Repository navigation
chore: automated code quality fixes () - #2
saurabhhhcodes wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthroughThe pull request combines an email-verification render-safety fix with broad JavaScript, CSS, workflow, template, and documentation formatting updates. It also adds user-model proxy methods, URL response handling, Redis queue wiring, and a new performance-documentation item. ChangesCreatorOS updates
Estimated code review effort: 4 (Complex) | ~45 minutes 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 19
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
controller/collaborationController.js (1)
206-221: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winNon-atomic read-modify-write on
inviter.collaboratorsraces under concurrent invite acceptance.
User.findById→ array membership check →push→saveis a classic TOCTOU pattern. Two concurrent acceptances touching the same inviter document can both read the same snapshot and save, causing a lost update tocollaborators.🔒 Proposed atomic fix
- const inviter = await User.findById(invite.inviter); - if (inviter) { - if (!inviter.collaborators) inviter.collaborators = []; - - const isAlreadyCollaborator = inviter.collaborators.some( - (id) => id.toString() === req.user.id.toString(), - ); - if (!isAlreadyCollaborator) { - inviter.collaborators.push(req.user.id); - await inviter.save(); - } - } + await User.updateOne( + { _id: invite.inviter }, + { $addToSet: { collaborators: req.user.id } }, + );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@controller/collaborationController.js` around lines 206 - 221, Replace the read-modify-write collaborator handling after the invite is saved with an atomic User update that adds req.user.id to inviter.collaborators only when absent, using the database’s set-style array update (such as $addToSet). Preserve the existing inviter lookup guard and avoid loading, checking, pushing, and saving the array through a stale document.utils/email.js (1)
63-103: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winUnescaped user-supplied
personalMessageinterpolated into email HTML.
personalMessage(ultimately the user-supplied invitemessage) is inserted raw into the HTML template. Since it isn't HTML-escaped, an inviter can inject arbitrary markup/links into a transactional email delivered to a third party.🛡️ Proposed fix
+function escapeHtml(value) { + return String(value) + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/"/g, """) + .replace(/'/g, "&`#39`;"); +} + const html = ` <div style="font-family: Arial, sans-serif; color: `#111`; line-height: 1.5;"> <h2 style="color: `#0f172a`;">You've been invited to collaborate</h2> <p><strong>${inviterName}</strong> has invited you to collaborate on <strong>${projectName}</strong>.</p> - ${personalMessage ? `<p><em>Message:</em> ${personalMessage}</p>` : ""} + ${personalMessage ? `<p><em>Message:</em> ${escapeHtml(personalMessage)}</p>` : ""}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@utils/email.js` around lines 63 - 103, Escape personalMessage before interpolating it into the HTML template in sendInvitationEmail, while preserving the existing plain-text message behavior. Reuse an existing HTML-escaping utility if available; otherwise add the smallest local escaping mechanism needed so user-supplied content cannot inject markup or links.
🧹 Nitpick comments (6)
public/css/style.css (1)
200-202: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winStylelint errors here originate from Tailwind's generated Preflight, not authored CSS.
Lines 200-202 (triple
-webkit-text-decoration), 380/383 (appearance: button), and 321 (currentColorcasing) are all Lightning CSS / Preflight output. Reformatting a build artifact with Prettier means the nexttailwindcssbuild will revert it, and these lint errors will keep reappearing. Consider excluding compiled CSS from Prettier/Stylelint instead.🧹 Suggested ignore entries
# .prettierignore +public/css/style.css# .stylelintignore +public/css/style.css🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@public/css/style.css` around lines 200 - 202, Exclude Tailwind/Lightning CSS compiled output from Prettier and Stylelint rather than modifying generated declarations in public/css/style.css. Update the relevant formatter and linter ignore configuration to cover the generated CSS artifact, preserving authored CSS checks while preventing future builds from reintroducing these reported errors.Source: Linters/SAST tools
public/css/settings.css (1)
36-50: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winHardcoded colors bypass the theme tokens and break under
appearance-dark. Both sites write literal hex values where a--settings-*token exists, so they don't follow the dark-mode overrides defined at Lines 72-84.
public/css/settings.css#L36-L50: replacebackground-color:#2d2d2d/ `color: `#f5f5f5withvar(--settings-card)/var(--settings-text), and drop the duplicatebody.settings-page.appearance-darkblock in favor of the token block at Lines 72-84.public/css/settings.css#L143-L146: replacebackground:#fff`` withvar(--settings-surface)so hovered nav links stay readable when text is `#f5f1ea`.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@public/css/settings.css` around lines 36 - 50, Replace the hardcoded dark-mode colors in the body.settings-page.appearance-dark card selectors with var(--settings-card) and var(--settings-text), then remove that duplicate dark-mode block so the existing token override block is authoritative. Also update the hover styles at public/css/settings.css lines 143-146 to use var(--settings-surface) instead of `#fff`.model/seedSuggestions.js (1)
2-23: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winHardcoded local Mongo URI instead of
MONGODB_URI.Every other script/module (
connect.js,scripts/seedTestUser.js) connects viaprocess.env.MONGODB_URI. This script hardcodesmongodb://localhost:27017/yourdb, which is easy to leave stale and diverges from the rest of the codebase's connection pattern.♻️ Suggested fix
-async function seed() { - await mongoose.connect("mongodb://localhost:27017/yourdb"); +async function seed() { + await mongoose.connect(process.env.MONGODB_URI || "mongodb://localhost:27017/yourdb");🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@model/seedSuggestions.js` around lines 2 - 23, Update the mongoose connection in seed to use process.env.MONGODB_URI instead of the hardcoded local MongoDB URI, matching the connection pattern used by the rest of the codebase.public/js/pages/settings.js (1)
408-419: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winConsider avoiding raw
innerHTMLinterpolation for invoice rows.Row markup is built via a template literal directly interpolating API-supplied fields (
inv.date,inv.invoiceId,inv.amount,inv.status) intoinnerHTML, flagged by static analysis for the untrusted-HTML-sink pattern. Even though this data currently comes from the trusted billing endpoint, building rows viatextContent/createElementavoids relying on that assumption holding forever.🛡️ Example hardening
- tbody.innerHTML = billing.invoices - .map( - (inv) => `<tr data-invoice-id="${inv.invoiceId}"> - <td>${inv.date}</td> - <td>${inv.invoiceId}</td> - <td>${inv.amount}</td> - <td><span class="badge-paid">${inv.status}</span></td> - </tr>`, - ) - .join(""); + tbody.textContent = ""; + billing.invoices.forEach((inv) => { + const tr = document.createElement("tr"); + tr.dataset.invoiceId = inv.invoiceId; + tr.innerHTML = "<td></td><td></td><td></td><td><span class='badge-paid'></span></td>"; + const [dateCell, idCell, amountCell, statusCell] = tr.children; + dateCell.textContent = inv.date; + idCell.textContent = inv.invoiceId; + amountCell.textContent = inv.amount; + statusCell.firstElementChild.textContent = inv.status; + tbody.appendChild(tr); + });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@public/js/pages/settings.js` around lines 408 - 419, Replace the raw innerHTML template construction in the invoice rendering block with DOM element creation and textContent assignments for inv.date, inv.invoiceId, inv.amount, and inv.status. Preserve the existing row structure, data-invoice-id attribute, and bindInvoiceRows() call while ensuring API-provided values are never interpreted as HTML.Source: Linters/SAST tools
controller/instagramController.js (1)
34-55: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winUnbounded
lookupTrackermap growth.Every unique
lookupKey(user id / IP / "anonymous") adds a permanent entry that is never cleaned up, so this grows indefinitely for the life of the process — a slow memory leak on a public endpoint. It's also purely in-process, so the cooldown isn't honored across multiple app instances.♻️ Suggested cleanup approach
+function pruneLookupTracker(now) { + for (const [key, expiry] of lookupTracker) { + if (expiry <= now) lookupTracker.delete(key); + } +} + function assertLookupAllowed(req) { const cooldownSeconds = getCooldownSeconds(); if (cooldownSeconds === 0) { return; } const lookupKey = getLookupKey(req); const now = Date.now(); + pruneLookupTracker(now); const nextAllowedAt = lookupTracker.get(lookupKey) || 0;For multi-instance deployments, consider a shared store (e.g., Redis) instead of in-process memory.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@controller/instagramController.js` around lines 34 - 55, Update the cooldown tracking around lookupTracker so entries are removed after their cooldown expires, preventing permanent growth for unique lookup keys. Preserve the existing rate-limit response and retryAfter calculation, and use a shared store such as Redis for lookupTracker when cooldown enforcement must work across multiple application instances.services/dmQueueService.js (1)
87-100: 🎯 Functional Correctness | 🔵 Trivial
sendInstagramDMis a stub — no real Instagram API call is made.This function only logs the outgoing message and randomly (20%) throws a synthetic rate-limit error "for testing," per the inline comments. Since the BullMQ worker (Line 45) calls this directly for every real
process-dmjob, the DM Automation feature currently never delivers an actual DM in production — it only simulates success/failure.Is the real Graph API integration tracked elsewhere, or is this stub still pending? I can help wire up the actual
POST https://graph.facebook.com/v19.0/me/messagescall if useful — happy to open a tracking issue.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@services/dmQueueService.js` around lines 87 - 100, Replace the stub implementation in sendInstagramDM with a real POST request to the Instagram Graph API endpoint, passing the recipientId, text, and required authentication/configured access token. Remove the console-only success simulation and random synthetic rate-limit failure, while preserving propagation of API errors so the BullMQ worker can handle failed process-dm jobs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CONTRIBUTING.md`:
- Around line 333-337: Correct the Automation Guide link in the documentation
list by removing the embedded space and pointing it to the actual
.github/AUTOMATION.md location. Leave the surrounding documentation links
unchanged.
In `@controller/auth.js`:
- Around line 219-255: Update login to require a valid email and password,
locate only the matching user through User.findOne, and verify the supplied
password against user.password with bcrypt.compare before issuing tokens. Remove
the fallback to User.findOne({}) and automatic User.create path, return the
existing authentication failure response for missing, unknown, or invalid
credentials, and stop forcing user.isVerified = true so email verification
remains enforced.
In `@controller/url.js`:
- Line 76: Update handleGenerateShortUrl to replace both shortid() calls with
the imported nanoid generator, preserving the existing custom-slug and
auto-generated paths so the endpoint no longer references an undefined symbol.
- Around line 77-91: Replace the check-then-create uniqueness flow around
customSlug and shortId with atomic database uniqueness enforcement and
duplicate-key retry handling. Ensure concurrent custom-slug requests return the
intended conflict response, while auto-generated IDs are regenerated and retried
after duplicate-key failures; update the surrounding create path rather than
relying on the existing findOne checks.
- Around line 46-47: Update the linkedAt assignment in serializeLink to read the
Date-valued entry.createdAt directly, then fall back to entry.linkedAt and
finally new Date(). Remove the array/timestamp access so generated links
preserve the model’s actual creation date.
In `@docs/EMAIL_VERIFICATION.md`:
- Around line 452-459: Update the Protected Routes middleware example to reflect
Express redirect behavior by using res.redirect(302, "/resend-verification") for
the documented 302 flow, or remove the ineffective status(403) call and any
accompanying 403 description.
In `@index.js`:
- Around line 51-52: Update the middleware ordering around generateCsrf and
verifyCsrf so signature-verified webhook routes, including /api/instagram, are
mounted before CSRF enforcement, or explicitly exempt only those webhook paths.
Preserve CSRF protection for cookie-authenticated unsafe requests.
- Around line 720-722: Scope dashboard URLs to authenticated accounts: in
index.js lines 720-722, update the URL creation flow to persist the
authenticated account identifier alongside shortId and redirectUrl; in
utils/dashboardHelper.js lines 18-19, filter aggregation queries by that same
identifier and migrate existing URL records to populate ownership before
enabling the filter.
In `@middleware/auth.js`:
- Around line 53-59: Update the unverified-user branch in the authentication
middleware to use wantsHtml(req) before responding: retain the redirect to
/resend-verification for HTML requests, and return the established JSON 403
response for non-HTML requests instead of redirecting.
In `@model/url.js`:
- Around line 8-54: Extend the shared URL model contract with a listForUser
method: implement it in both MongooseUrlModel and MockUrlModel to persist and
filter records by userId, then proxy it through UrlModel alongside the existing
model methods. Ensure handleListUserLinks can call Url.listForUser(userId, 100)
and receive only that user’s links.
In `@public/css/my-links.css`:
- Around line 629-642: Rename the keyframe identifier from ctaPulse to cta-pulse
in both the animation declaration and the `@keyframes` block, preserving the
existing animation behavior.
In `@public/css/settings.css`:
- Around line 477-482: Update the .form-input:focus and .form-textarea:focus
focus styling to avoid removing the native outline, and add a visible outline
for keyboard-focused controls via :focus-visible. Preserve the existing
background and box-shadow styles while ensuring the focus ring remains clearly
visible.
- Around line 143-146: Update the `.settings-nav a:hover` rule to replace the
hardcoded `#fff` background with the appropriate surface color token, preserving
the existing border styling and ensuring hover text remains readable in dark
mode.
- Around line 26-34: Wire the density variables into the existing consumers:
update `.section-card` to use `--section-pad` for padding and
`.settings-sections` to use `--card-gap` for its gap. Preserve the default
spacing for the base settings page by defining appropriate fallback or base
variable values, and verify compact and tactile classes produce the intended
spacing.
In `@public/css/workspace-shell.css`:
- Around line 185-195: Update the SVG stroke declarations in the selectors
around .menu-btn svg and the corresponding block around lines 424-434, replacing
both currentColor values with lowercase currentcolor to satisfy the configured
value-keyword-case rule.
In `@public/js/pages/file-upload.js`:
- Around line 124-128: Update the success rendering around statusEl.innerHTML so
data.filename is inserted as text rather than interpreted as HTML, preventing
markup or script execution from a crafted filename; preserve the existing
success message and formatted size output.
In `@public/js/pages/login.js`:
- Around line 11-19: Remove the pasted Markdown fence tokens surrounding the
handler bodies in all Google, email, and contributor login flows, including the
sections anchored by the loading-state logic and contributorLoading guard. Leave
the JavaScript statements and handler structure intact so each callback executes
normally.
In `@scripts/seedTestUser.js`:
- Around line 1-7: Correct the database connection import in the seed script by
changing the module reference used by connectDB from the misspelled “conect”
path to the existing “connect” module, leaving the User and bcrypt imports
unchanged.
In `@workers/analyticsRefreshWorker.js`:
- Around line 14-23: Gate mock analytics generation in the scheduled worker
around the mock data block so it runs only when an explicit non-production/demo
feature flag is enabled; otherwise, skip all analytics persistence unless a real
provider is configured. Update docs/analytics.md at line 122 to document this
production guard and clarify that mock data is not persisted in production.
---
Outside diff comments:
In `@controller/collaborationController.js`:
- Around line 206-221: Replace the read-modify-write collaborator handling after
the invite is saved with an atomic User update that adds req.user.id to
inviter.collaborators only when absent, using the database’s set-style array
update (such as $addToSet). Preserve the existing inviter lookup guard and avoid
loading, checking, pushing, and saving the array through a stale document.
In `@utils/email.js`:
- Around line 63-103: Escape personalMessage before interpolating it into the
HTML template in sendInvitationEmail, while preserving the existing plain-text
message behavior. Reuse an existing HTML-escaping utility if available;
otherwise add the smallest local escaping mechanism needed so user-supplied
content cannot inject markup or links.
---
Nitpick comments:
In `@controller/instagramController.js`:
- Around line 34-55: Update the cooldown tracking around lookupTracker so
entries are removed after their cooldown expires, preventing permanent growth
for unique lookup keys. Preserve the existing rate-limit response and retryAfter
calculation, and use a shared store such as Redis for lookupTracker when
cooldown enforcement must work across multiple application instances.
In `@model/seedSuggestions.js`:
- Around line 2-23: Update the mongoose connection in seed to use
process.env.MONGODB_URI instead of the hardcoded local MongoDB URI, matching the
connection pattern used by the rest of the codebase.
In `@public/css/settings.css`:
- Around line 36-50: Replace the hardcoded dark-mode colors in the
body.settings-page.appearance-dark card selectors with var(--settings-card) and
var(--settings-text), then remove that duplicate dark-mode block so the existing
token override block is authoritative. Also update the hover styles at
public/css/settings.css lines 143-146 to use var(--settings-surface) instead of
`#fff`.
In `@public/css/style.css`:
- Around line 200-202: Exclude Tailwind/Lightning CSS compiled output from
Prettier and Stylelint rather than modifying generated declarations in
public/css/style.css. Update the relevant formatter and linter ignore
configuration to cover the generated CSS artifact, preserving authored CSS
checks while preventing future builds from reintroducing these reported errors.
In `@public/js/pages/settings.js`:
- Around line 408-419: Replace the raw innerHTML template construction in the
invoice rendering block with DOM element creation and textContent assignments
for inv.date, inv.invoiceId, inv.amount, and inv.status. Preserve the existing
row structure, data-invoice-id attribute, and bindInvoiceRows() call while
ensuring API-provided values are never interpreted as HTML.
In `@services/dmQueueService.js`:
- Around line 87-100: Replace the stub implementation in sendInstagramDM with a
real POST request to the Instagram Graph API endpoint, passing the recipientId,
text, and required authentication/configured access token. Remove the
console-only success simulation and random synthetic rate-limit failure, while
preserving propagation of API errors so the BullMQ worker can handle failed
process-dm jobs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 79525724-dd30-454f-956f-985503694c08
📒 Files selected for processing (83)
.github/AUTOMATION.md.github/pull_request_template.md.github/scripts/auto-label.js.github/scripts/remind-issues.mjs.github/workflows/auto-label.yml.github/workflows/contributor-welcome.yml.github/workflows/issue-reminder.ymlBUG_FIX_PATCH.mdCONTRIBUTING.mdDESIGN.mdEMAIL_VERIFICATION_BUG_FIX.mdIMPLEMENTATION_SUMMARY.mdPULL_REQUEST_TEMPLATE.mdQUICK_DEPLOYMENT_GUIDE.mdQUICK_REFERENCE.mdREADME.mdconnect.jscontroller/analytics.jscontroller/auth.jscontroller/collaborationController.jscontroller/instagramController.jscontroller/instagramWebhookController.jscontroller/suggestionController.jscontroller/url.jsdocs/EMAIL_VERIFICATION.mddocs/analytics.mdindex.jsmiddleware/auth.jsmiddleware/csrf.jsmiddleware/errorHandler.jsmiddleware/rateLimiters.jsmiddleware/validators.jsmodel/analyticsSnapshot.jsmodel/contributorSession.jsmodel/creator.jsmodel/engagementHistory.jsmodel/invite.jsmodel/post.jsmodel/seedSuggestions.jsmodel/suggestion.jsmodel/suggestionData.jsmodel/url.jsmodel/user.jsperformance.mdpublic/css/dashboard.csspublic/css/my-links.csspublic/css/settings.csspublic/css/style.csspublic/css/workspace-shell.csspublic/js/pages/dashboard.jspublic/js/pages/file-upload.jspublic/js/pages/home.jspublic/js/pages/login.jspublic/js/pages/services-hub.jspublic/js/pages/settings.jspublic/js/pages/suggestions.jspublic/js/site-3d.jspublic/site.webmanifestroutes/analytics.jsroutes/auth.jsroutes/collaboration.jsroutes/instagram.jsroutes/settings.jsroutes/suggestionRoutes.jsroutes/url.jsscratch.jsscripts/addDocs.jsscripts/replace-layout.jsscripts/seedTestUser.jsservices.config.jsservices/dmQueueService.jstests/email-verification.test.jsutils/asyncHandler.jsutils/dashboardHelper.jsutils/email.jsutils/instagramProfileService.jsutils/requestType.jsutils/swaggerOptions.jsutils/validators.jsutils/viewModels.jsvercel.jsonview/index.htmlworkers/analyticsRefreshWorker.js
💤 Files with no reviewable changes (1)
- .github/workflows/contributor-welcome.yml
|
|
||
| - [Project Architecture](./ARCHITECTURE.md) | ||
| - [API Documentation](./API.md) | ||
| - [Automation Guide](./ AUTOMATION.md) | ||
| - [Deployment Guide](./DEPLOYMENT.md) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Broken "Automation Guide" link.
./ AUTOMATION.md has an embedded space breaking the link, and the target actually lives at .github/AUTOMATION.md, not at the repo root.
🔗 Proposed fix
-- [Automation Guide](./ AUTOMATION.md)
+- [Automation Guide](.github/AUTOMATION.md)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - [Project Architecture](./ARCHITECTURE.md) | |
| - [API Documentation](./API.md) | |
| - [Automation Guide](./ AUTOMATION.md) | |
| - [Deployment Guide](./DEPLOYMENT.md) | |
| - [Project Architecture](./ARCHITECTURE.md) | |
| - [API Documentation](./API.md) | |
| - [Automation Guide](.github/AUTOMATION.md) | |
| - [Deployment Guide](./DEPLOYMENT.md) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CONTRIBUTING.md` around lines 333 - 337, Correct the Automation Guide link in
the documentation list by removing the embedded space and pointing it to the
actual .github/AUTOMATION.md location. Leave the surrounding documentation links
unchanged.
| const login = asyncHandler(async (req, res, next) => { | ||
| const User = await getUserModel(); | ||
|
|
||
| const { email, password } = req.body || {}; | ||
| const normalizedEmail = (email && typeof email === 'string') ? email.toLowerCase().trim() : ""; | ||
|
|
||
| // Allow login with any credentials: find user by email, or get the first user, or create a mock user | ||
| let user = null; | ||
| if (normalizedEmail) { | ||
| user = await User.findOne({ email: normalizedEmail }); | ||
| } | ||
| if (!user) { | ||
| user = await User.findOne({}); | ||
| } | ||
| if (!user) { | ||
| user = await User.create({ | ||
| name: "Test User", | ||
| email: normalizedEmail || "test@local.com", | ||
| password: await bcrypt.hash("Password123!", 10), | ||
| role: "creator", | ||
| isVerified: true | ||
| }); | ||
| } | ||
| const User = await getUserModel(); | ||
|
|
||
| const { email, password } = req.body || {}; | ||
| const normalizedEmail = | ||
| email && typeof email === "string" ? email.toLowerCase().trim() : ""; | ||
|
|
||
| // Allow login with any credentials: find user by email, or get the first user, or create a mock user | ||
| let user = null; | ||
| if (normalizedEmail) { | ||
| user = await User.findOne({ email: normalizedEmail }); | ||
| } | ||
| if (!user) { | ||
| user = await User.findOne({}); | ||
| } | ||
| if (!user) { | ||
| user = await User.create({ | ||
| name: "Test User", | ||
| email: normalizedEmail || "test@local.com", | ||
| password: await bcrypt.hash("Password123!", 10), | ||
| role: "creator", | ||
| isVerified: true, | ||
| }); | ||
| } | ||
|
|
||
| user.isVerified = true; | ||
| user.lastLoginAt = new Date(); | ||
| await user.save(); | ||
| user.isVerified = true; | ||
| user.lastLoginAt = new Date(); | ||
| await user.save(); | ||
|
|
||
| const token = createToken(user); | ||
| setAuthCookie(res, token); | ||
| const token = createToken(user); | ||
| setAuthCookie(res, token); | ||
|
|
||
| if (wantsHtml(req)) return res.redirect("/dashboard"); | ||
| return res.status(200).json({ success: true, token, user: serializeUser(user) }); | ||
| if (wantsHtml(req)) return res.redirect("/dashboard"); | ||
| return res | ||
| .status(200) | ||
| .json({ success: true, token, user: serializeUser(user) }); | ||
| }); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift
Critical authentication bypass: login never verifies the password.
password is destructured from req.body but never checked against user.password (no bcrypt.compare). Consequences:
- Any password value succeeds as long as the email matches an existing user.
- If no user matches (or
emailis omitted), the code silently falls back toUser.findOne({})— logging the caller in as an arbitrary existing account — and if the DB is empty, it auto-creates a new account and logs the caller in. user.isVerified = trueis force-set on every login, completely defeating the email-verification feature this PR's docs describe.
This allows unauthenticated takeover of any account.
🔒 Proposed fix: restore password verification
const login = asyncHandler(async (req, res, next) => {
const User = await getUserModel();
const { email, password } = req.body || {};
const normalizedEmail =
email && typeof email === "string" ? email.toLowerCase().trim() : "";
- // Allow login with any credentials: find user by email, or get the first user, or create a mock user
- let user = null;
- if (normalizedEmail) {
- user = await User.findOne({ email: normalizedEmail });
- }
- if (!user) {
- user = await User.findOne({});
- }
- if (!user) {
- user = await User.create({
- name: "Test User",
- email: normalizedEmail || "test@local.com",
- password: await bcrypt.hash("Password123!", 10),
- role: "creator",
- isVerified: true,
- });
- }
-
- user.isVerified = true;
+ if (!normalizedEmail || !password) {
+ return renderLoginError(req, res);
+ }
+
+ const user = await User.findOne({ email: normalizedEmail });
+ if (!user || !(await bcrypt.compare(password, user.password))) {
+ return renderLoginError(req, res);
+ }
+
+ if (!user.isVerified) {
+ if (wantsHtml(req)) return res.status(403).redirect("/resend-verification");
+ return res.status(403).json({ success: false, message: "Please verify your email address before logging in." });
+ }
+
user.lastLoginAt = new Date();
await user.save();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const login = asyncHandler(async (req, res, next) => { | |
| const User = await getUserModel(); | |
| const { email, password } = req.body || {}; | |
| const normalizedEmail = (email && typeof email === 'string') ? email.toLowerCase().trim() : ""; | |
| // Allow login with any credentials: find user by email, or get the first user, or create a mock user | |
| let user = null; | |
| if (normalizedEmail) { | |
| user = await User.findOne({ email: normalizedEmail }); | |
| } | |
| if (!user) { | |
| user = await User.findOne({}); | |
| } | |
| if (!user) { | |
| user = await User.create({ | |
| name: "Test User", | |
| email: normalizedEmail || "test@local.com", | |
| password: await bcrypt.hash("Password123!", 10), | |
| role: "creator", | |
| isVerified: true | |
| }); | |
| } | |
| const User = await getUserModel(); | |
| const { email, password } = req.body || {}; | |
| const normalizedEmail = | |
| email && typeof email === "string" ? email.toLowerCase().trim() : ""; | |
| // Allow login with any credentials: find user by email, or get the first user, or create a mock user | |
| let user = null; | |
| if (normalizedEmail) { | |
| user = await User.findOne({ email: normalizedEmail }); | |
| } | |
| if (!user) { | |
| user = await User.findOne({}); | |
| } | |
| if (!user) { | |
| user = await User.create({ | |
| name: "Test User", | |
| email: normalizedEmail || "test@local.com", | |
| password: await bcrypt.hash("Password123!", 10), | |
| role: "creator", | |
| isVerified: true, | |
| }); | |
| } | |
| user.isVerified = true; | |
| user.lastLoginAt = new Date(); | |
| await user.save(); | |
| user.isVerified = true; | |
| user.lastLoginAt = new Date(); | |
| await user.save(); | |
| const token = createToken(user); | |
| setAuthCookie(res, token); | |
| const token = createToken(user); | |
| setAuthCookie(res, token); | |
| if (wantsHtml(req)) return res.redirect("/dashboard"); | |
| return res.status(200).json({ success: true, token, user: serializeUser(user) }); | |
| if (wantsHtml(req)) return res.redirect("/dashboard"); | |
| return res | |
| .status(200) | |
| .json({ success: true, token, user: serializeUser(user) }); | |
| }); | |
| const login = asyncHandler(async (req, res, next) => { | |
| const User = await getUserModel(); | |
| const { email, password } = req.body || {}; | |
| const normalizedEmail = | |
| email && typeof email === "string" ? email.toLowerCase().trim() : ""; | |
| if (!normalizedEmail || !password) { | |
| return renderLoginError(req, res); | |
| } | |
| const user = await User.findOne({ email: normalizedEmail }); | |
| if (!user || !(await bcrypt.compare(password, user.password))) { | |
| return renderLoginError(req, res); | |
| } | |
| if (!user.isVerified) { | |
| if (wantsHtml(req)) return res.status(403).redirect("/resend-verification"); | |
| return res | |
| .status(403) | |
| .json({ success: false, message: "Please verify your email address before logging in." }); | |
| } | |
| user.lastLoginAt = new Date(); | |
| await user.save(); | |
| const token = createToken(user); | |
| setAuthCookie(res, token); | |
| if (wantsHtml(req)) return res.redirect("/dashboard"); | |
| return res | |
| .status(200) | |
| .json({ success: true, token, user: serializeUser(user) }); | |
| }); |
🧰 Tools
🪛 ast-grep (0.44.1)
[warning] 248-248: Avoid using the initial state variable in setState
Context: setAuthCookie(res, token)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.
(setstate-same-var)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@controller/auth.js` around lines 219 - 255, Update login to require a valid
email and password, locate only the matching user through User.findOne, and
verify the supplied password against user.password with bcrypt.compare before
issuing tokens. Remove the fallback to User.findOne({}) and automatic
User.create path, return the existing authentication failure response for
missing, unknown, or invalid credentials, and stop forcing user.isVerified =
true so email verification remains enforced.
| const linkedAt = | ||
| entry.linkedAt || entry.createdAt?.[0]?.timeStamp || new Date(); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect the Url schema to confirm createdAt's actual shape
fd -e js url.js -p model | xargs cat -nRepository: saurabhhhcodes/CreatorOs
Length of output: 5007
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the Url controller around linkedAt usage and confirm UrlModel shape/import.
sed -n '1,140p' controller/url.js | cat -n
# Behavioral probe for the expression under the schema/implementation shape: createdAt is Date.
node - <<'JS'
function expr(entry) {
return entry.linkedAt || entry.createdAt?.[0]?.timeStamp || new Date();
}
for (const entry of [
{ createdAt: new Date("2025-07-01T12:34:56Z") },
{ createdAt: [ { timeStamp: new Date("2025-01-01T00:00:00Z") } ] },
{ createdAt: undefined },
{ linkedAt: new Date("2020-01-01T00:00:00Z"), createdAt: new Date("2025-07-01T12:34:56Z") },
]) {
const linkedAt = expr(entry);
console.log(String(entry.createdAt), "=>", linkedAt.toISOString());
}
JSRepository: saurabhhhcodes/CreatorOs
Length of output: 5532
Read createdAt directly for linkedAt.
UrlModel.createdAt is a Date, but serializeLink falls through to new Date() via entry.createdAt?.[0]?.timeStamp, so generated response links report the serialization time instead of the actual linked date. Use entry.createdAt || entry.linkedAt || new Date() instead.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@controller/url.js` around lines 46 - 47, Update the linkedAt assignment in
serializeLink to read the Date-valued entry.createdAt directly, then fall back
to entry.linkedAt and finally new Date(). Remove the array/timestamp access so
generated links preserve the model’s actual creation date.
| } | ||
| const { redirectUrl, title, customSlug, tag } = req.body; | ||
|
|
||
| let shortId = shortid(); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
shortid() is undefined — handleGenerateShortUrl will throw a ReferenceError.
Only nanoid is imported (Line 1), but shortid() is invoked here and at Line 90. This breaks the short-URL creation API endpoint (handleGenerateShortUrl, referenced from routes/url.js) for both the custom-slug and auto-generated paths.
🐛 Proposed fix
- let shortId = shortid();
+ let shortId = nanoid(8);
if (customSlug) {
const slug = String(customSlug).trim().toLowerCase();
const existing = await Url.findOne({ shortId: slug });
if (existing) {
return res
.status(409)
.json({ error: "That slug is already taken. Try another." });
}
shortId = slug;
} else {
const existing = await Url.findOne({ shortId });
if (existing) {
- shortId = shortid();
+ shortId = nanoid(8);
}
}Also applies to: 90-90
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@controller/url.js` at line 76, Update handleGenerateShortUrl to replace both
shortid() calls with the imported nanoid generator, preserving the existing
custom-slug and auto-generated paths so the endpoint no longer references an
undefined symbol.
| if (customSlug) { | ||
| const slug = String(customSlug).trim().toLowerCase(); | ||
| const existing = await Url.findOne({ shortId: slug }); | ||
| if (existing) { | ||
| return res | ||
| .status(409) | ||
| .json({ error: "That slug is already taken. Try another." }); | ||
| } | ||
|
|
||
| const allowedTags = ['active', 'social', 'campaign', 'general']; | ||
| const linkTag = allowedTags.includes(tag) ? tag : 'active'; | ||
|
|
||
| const entry = await Url.create({ | ||
| shortId, | ||
| redirectUrl, | ||
| userId: req.user?.id || null, | ||
| title: deriveTitle(redirectUrl, title?.trim()), | ||
| tag: linkTag, | ||
| linkedAt: new Date(), | ||
| }); | ||
|
|
||
| const hostBase = `${req.protocol}://${req.get('host')}`; | ||
|
|
||
| return res.status(201).json({ | ||
| message: 'Link created successfully', | ||
| link: serializeLink(entry, hostBase), | ||
| }); | ||
| shortId = slug; | ||
| } else { | ||
| const existing = await Url.findOne({ shortId }); | ||
| if (existing) { | ||
| shortId = shortid(); | ||
| } | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
TOCTOU race on shortId uniqueness checks.
Both branches perform a findOne check followed by a separate create with no atomicity or loop-based retry: two concurrent requests with the same custom slug (or the same regenerated auto id) can both pass the existence check before either write completes, producing duplicate slugs or an unhandled duplicate-key error.
Consider relying on a unique index at the DB layer plus a retry loop on the duplicate-key error (or a findOneAndUpdate upsert-style pattern) instead of check-then-create.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@controller/url.js` around lines 77 - 91, Replace the check-then-create
uniqueness flow around customSlug and shortId with atomic database uniqueness
enforcement and duplicate-key retry handling. Ensure concurrent custom-slug
requests return the intended conflict response, while auto-generated IDs are
regenerated and retried after duplicate-key failures; update the surrounding
create path rather than relying on the existing findOne checks.
| .menu-btn svg, | ||
| .icon-btn svg, | ||
| .action-icon-btn svg { | ||
| width: 1.25rem; | ||
| height: 1.25rem; | ||
| fill: none; | ||
| stroke: currentColor; | ||
| stroke-width: 2; | ||
| stroke-linecap: round; | ||
| stroke-linejoin: round; | ||
| width: 1.25rem; | ||
| height: 1.25rem; | ||
| fill: none; | ||
| stroke: currentColor; | ||
| stroke-width: 2; | ||
| stroke-linecap: round; | ||
| stroke-linejoin: round; | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Match the configured currentcolor keyword casing.
Lines 191 and 430 violate the configured Stylelint value-keyword-case rule. Replace both currentColor values with currentcolor.
Also applies to: 424-434
🧰 Tools
🪛 Stylelint (17.14.0)
[error] 191-191: Expected "currentColor" to be "currentcolor" (value-keyword-case)
(value-keyword-case)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@public/css/workspace-shell.css` around lines 185 - 195, Update the SVG stroke
declarations in the selectors around .menu-btn svg and the corresponding block
around lines 424-434, replacing both currentColor values with lowercase
currentcolor to satisfy the configured value-keyword-case rule.
Source: Linters/SAST tools
| statusEl.innerHTML = | ||
| "<strong>Upload successful!</strong><br>File: " + | ||
| data.filename + | ||
| "<br>Size: " + | ||
| formatSize(data.size); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Render the returned filename as text, not HTML.
data.filename crosses a network boundary and is interpolated into innerHTML, allowing a crafted filename to execute script in the authenticated application origin.
Proposed fix
- statusEl.innerHTML =
- "<strong>Upload successful!</strong><br>File: " +
- data.filename +
- "<br>Size: " +
- formatSize(data.size);
+ const title = document.createElement("strong");
+ title.textContent = "Upload successful!";
+ statusEl.replaceChildren(
+ title,
+ document.createElement("br"),
+ document.createTextNode(`File: ${data.filename}`),
+ document.createElement("br"),
+ document.createTextNode(`Size: ${formatSize(data.size)}`),
+ );📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| statusEl.innerHTML = | |
| "<strong>Upload successful!</strong><br>File: " + | |
| data.filename + | |
| "<br>Size: " + | |
| formatSize(data.size); | |
| const title = document.createElement("strong"); | |
| title.textContent = "Upload successful!"; | |
| statusEl.replaceChildren( | |
| title, | |
| document.createElement("br"), | |
| document.createTextNode(`File: ${data.filename}`), | |
| document.createElement("br"), | |
| document.createTextNode(`Size: ${formatSize(data.size)}`), | |
| ); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@public/js/pages/file-upload.js` around lines 124 - 128, Update the success
rendering around statusEl.innerHTML so data.filename is inserted as text rather
than interpreted as HTML, preventing markup or script execution from a crafted
filename; preserve the existing success message and formatted size output.
Source: Linters/SAST tools
| ``` | ||
| const span = this.querySelector('span'); | ||
|
|
||
| if (span) { | ||
| span.textContent = this.dataset.loadingText || 'Signing in...'; | ||
| } | ||
|
|
||
| this.disabled = true; | ||
| ``` | ||
|
|
||
| ```; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Remove the pasted Markdown fence tokens.
The ``` lines turn each handler body into tagged-template expressions rather than executable statements. The Google, email, and contributor login flows will throw instead of applying their loading or authentication logic.
Proposed fix
- ```
const span = this.querySelector('span');
...
this.disabled = true;
-```;
});
- ```
emailLoading = true;
...
-```;
});
- ```
if (contributorLoading) return;
...
-```;
});Also applies to: 25-39, 45-92
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@public/js/pages/login.js` around lines 11 - 19, Remove the pasted Markdown
fence tokens surrounding the handler bodies in all Google, email, and
contributor login flows, including the sections anchored by the loading-state
logic and contributorLoading guard. Leave the JavaScript statements and handler
structure intact so each callback executes normally.
| const dotenv = require("dotenv"); | ||
| dotenv.config(); | ||
|
|
||
| const connectDB = require('../conect'); | ||
| const User = require('../model/user'); | ||
| const bcrypt = require('bcryptjs'); | ||
| const connectDB = require("../conect"); | ||
| const User = require("../model/user"); | ||
| const bcrypt = require("bcryptjs"); | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Broken import: ../conect should be ../connect.
This resolves to a nonexistent module (the actual file is connect.js, as used by routes/auth.js/controller/auth.js/middleware/auth.js). Running this script will throw Cannot find module '../conect' immediately.
-const connectDB = require("../conect");
+const connectDB = require("../connect");📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const dotenv = require("dotenv"); | |
| dotenv.config(); | |
| const connectDB = require('../conect'); | |
| const User = require('../model/user'); | |
| const bcrypt = require('bcryptjs'); | |
| const connectDB = require("../conect"); | |
| const User = require("../model/user"); | |
| const bcrypt = require("bcryptjs"); | |
| const dotenv = require("dotenv"); | |
| dotenv.config(); | |
| const connectDB = require("../connect"); | |
| const User = require("../model/user"); | |
| const bcrypt = require("bcryptjs"); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/seedTestUser.js` around lines 1 - 7, Correct the database connection
import in the seed script by changing the module reference used by connectDB
from the misspelled “conect” path to the existing “connect” module, leaving the
User and bcrypt imports unchanged.
| // TODO: Replace with real platform API call (e.g. Instagram Graph API) | ||
| const mockFetchedData = { | ||
| followers: Math.floor(Math.random() * 10000), | ||
| following: Math.floor(Math.random() * 1000), | ||
| totalPosts: Math.floor(Math.random() * 500), | ||
| totalLikes: Math.floor(Math.random() * 50000), | ||
| totalComments: Math.floor(Math.random() * 5000), | ||
| totalViews: Math.floor(Math.random() * 100000), | ||
| engagementRate: parseFloat((Math.random() * 10).toFixed(2)), | ||
| }; |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Do not persist random analytics in production. The scheduled worker writes randomly generated snapshots and derived growth deltas every six hours, which permanently corrupts creator analytics rather than representing an unavailable integration.
workers/analyticsRefreshWorker.js#L14-L23: gate mock generation behind a non-production/demo-only feature flag and skip all analytics writes unless a real provider is configured.docs/analytics.md#L122-L122: document the production guard instead of presenting persisted mock data as a temporary replacement.
📍 Affects 2 files
workers/analyticsRefreshWorker.js#L14-L23(this comment)docs/analytics.md#L122-L122
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@workers/analyticsRefreshWorker.js` around lines 14 - 23, Gate mock analytics
generation in the scheduled worker around the mock data block so it runs only
when an explicit non-production/demo feature flag is enabled; otherwise, skip
all analytics persistence unless a real provider is configured. Update
docs/analytics.md at line 122 to document this production guard and clarify that
mock data is not persisted in production.
Automated code quality improvements using official language tools.
Tools applied:
Diff stats:
.github/AUTOMATION.md | 9 +-
.github/pull_request_template.md | 10 +
.github/scripts/auto-label.js | 18 +-
.github/scripts/remind-issues.mjs | 2 +-
.github/workflows/auto-label.yml | 2 +-
.github/workflows/contributor-welcome.yml | 1 -
.github/workflows/issue-reminder.yml | 2 +-
BUG_FIX_PATCH.md | 61 +-
CONTRIBUTING.md | 56 +-
DESIGN.md | 208 ++--
EMAIL_VERIFICATION_BUG_FIX.md | 92 +-
IMPLEMENTATION_SUMMARY.md | 107 +-
PULL_REQUEST_TEMPLATE.md | 28 +-
QUICK_DEPLOYMENT_GUIDE.md | 69 +-
QUICK_REFERENCE.md | 95 +-
README.md | 58 +-
connect.js | 146 ++-
controller/analytics.js | 93 +-
controller/auth.js | 664 ++++++-----
controller/collaborationController.js | 127 +-
controller/instagramController.js | 105 +-
controller/instagramWebhookController.js | 202 ++--
controller/suggestionController.js | 103 +-
controller/url.js | 542 +++++----
docs/EMAIL_VERIFICATION.md | 107 +-
docs/analytics.md | 96 +-
index.js | 988 ++++++++++------
middleware/auth.js | 131 +-
middleware/csrf.js | 78 +-
middleware/errorHandler.js | 14 +-
middleware/rateLimiters.js | 113 +-
middleware/validators.js | 145 ++-
model/analyticsSnapshot.js | 52 +-
model/contributorSession.js | 88 +-
model/creator.js | 108 +-
model/engagementHistory.js | 40 +-
model/invite.js | 20 +-
model/post.js | 38 +-
model/seedSuggestions.js | 22 +-
model/suggestion.js | 148 ++-
model/suggestionData.js | 11 +-
model/url.js | 223 ++--
model/user.js | 439 +++----
performance.md | 3 +-
public/css/dashboard.css | 10 +-
public/css/my-links.css | 813 ++++++-------
public/css/settings.css | 1029 ++++++++--------
public/css/style.css | 1842 ++++++++++++++++++++++++++++-
public/css/workspace-shell.css | 808 ++++++-------
public/js/pages/dashboard.js | 58 +-
public/js/pages/file-upload.js | 313 ++---
public/js/pages/home.js | 130 +-
public/js/pages/login.js | 61 +-
public/js/pages/services-hub.js | 287 +++--
public/js/pages/settings.js | 851 +++++++------
public/js/pages/suggestions.js | 76 +-
public/js/site-3d.js | 158 ++-
public/site.webmanifest | 20 +-
routes/analytics.js | 24 +-
routes/auth.js | 218 ++--
routes/collaboration.js | 21 +-
routes/instagram.js | 17 +-
routes/settings.js | 226 ++--
routes/suggestionRoutes.js | 16 +-
routes/url.js | 66 +-
scratch.js | 12 +-
scripts/addDocs.js | 130 +-
scripts/replace-layout.js | 139 ++-
scripts/seedTestUser.js | 32 +-
services.config.js | 158 +--
services/dmQueueService.js | 160 +--
tests/email-verification.test.js | 205 ++--
utils/asyncHandler.js | 4 +-
utils/dashboardHelper.js | 216 ++--
utils/email.js | 34 +-
utils/instagramProfileService.js | 621 +++++-----
utils/requestType.js | 4 +-
utils/swaggerOptions.js | 77 +-
utils/validators.js | 16 +-
utils/viewModels.js | 20 +-
vercel.json | 2 +-
view/index.html | 273 ++---
workers/analyticsRefreshWorker.js | 100 +-
83 files changed, 9017 insertions(+), 5894 deletions(-)
This PR contains only automated fixes from linters/formatters (eslint, prettier, black, rustfmt, etc.).
No manual changes or AI-generated code.
Summary by CodeRabbit
Bug Fixes
Style
Documentation