Backend to frontend connection#9
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
More reviews will be available in 39 minutes and 43 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThis PR integrates authentication state management and replaces client dummy data with real API calls across the full stack. It adds an AuthContext that persists user/token to localStorage and synchronizes Axios headers, wires authentication guards into the Layout component, and rewrites five pages (Login, Accounts, Dashboard, Scheduler, AIComposer) to fetch and mutate backend data with toast-based error handling. Server-side changes add DNS configuration, correct the POST route registration, and fix the Zernio platform field mapping. ChangesBackend Authentication & API Client Setup + Frontend Auth Context
Page-Level API Integration
Server-Side Configuration and Fixes
Sequence DiagramsequenceDiagram
participant User
participant App
participant AuthContext
participant localStorage
participant APIServer
User->>App: Visit /login
App->>AuthContext: useAuth() returns { user: null, isAuthenticated: false }
AuthContext->>localStorage: Read persisted credentials (none)
User->>App: Enter credentials, submit form
App->>APIServer: POST /api/auth/login { email, password, name }
APIServer-->>App: { user, token }
App->>AuthContext: login(user, token)
AuthContext->>localStorage: Save user and token
AuthContext->>APIServer: Set Authorization: Bearer {token}
App->>App: Navigate to /dashboard
App->>APIServer: GET /api/posts, /api/accounts, /api/activity (Promise.all)
APIServer-->>App: Returns posts, accounts, activity
App->>App: Render dashboard with data
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
server/services/schedulerService.ts (2)
54-68:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDon’t overwrite a successful publish with a logging failure.
Once
createPost()andpost.save()succeed, any laterActivityLog.create()exception falls into the same catch and flips the post to"failed". That leaves your database inconsistent with the already-published external post.Suggested fix
post.status = "published"; await post.save(); - await ActivityLog.create({ - user: post.user, - actionType: "POST_PUBLISHED", - description: `Published post to ${accounts.map((a) => a.platform). - join(", ")}`, - relatedPost: post._id, - }) + try { + await ActivityLog.create({ + user: post.user, + actionType: "POST_PUBLISHED", + description: `Published post to ${accounts.map((a) => a.platform).join(", ")}`, + relatedPost: post._id, + }) + } catch (logError) { + console.error(`Failed to write activity log for post ${post._id}:`, logError); + } } catch (err: any) { console.error(`Failed to publish post ${post._id} :`, err?.response?.data || err?.message); post.status = "failed";🤖 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 `@server/services/schedulerService.ts` around lines 54 - 68, The current catch block flips post.status to "failed" for any error including ActivityLog.create failures after a successful publish; modify the flow so publishing errors still set post.status = "failed" but logging errors do not overwrite a successful publish. Specifically, keep the publish logic (createPost / post.save / post.status = "published") together, and move ActivityLog.create into its own try/catch (or check post.status === "published" before setting to "failed") so that exceptions from ActivityLog.create are caught and logged without changing post.status; reference functions/fields: createPost (or the publish call), post.save, post.status, ActivityLog.create.
11-18:⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy liftClaim each due post before calling Zernio.
These rows stay in
status: "scheduled"until after the external publish returns. A second cron tick—or another server instance running the same scheduler—can read the same post and publish it again before this save happens. This needs an atomic claim/lease step (scheduled -> publishing) beforecreatePost().Also applies to: 42-55
🤖 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 `@server/services/schedulerService.ts` around lines 11 - 18, Before calling createPost(), atomically claim each scheduled post by changing its status to "publishing" so concurrent scheduler ticks can't process the same post, e.g. replace the unconditional use of Post.find(...) + iterating with a conditional atomic update: use Post.findOneAndUpdate({_id: post._id, status: "scheduled", scheduledFor: {$lte: now}}, {$set: {status: "publishing", publishingAt: new Date()}}, {returnDocument: "after"}) and only call createPost() if the update returned a document; reference Post.find, the per-post loop, and createPost() when applying this change. Ensure the same pattern is applied to the other block mentioned (lines 42-55).Client/src/pages/Scheduler.tsx (1)
602-615:⚠️ Potential issue | 🟡 MinorDon’t create blob URLs during render.
Client/src/pages/Scheduler.tsxcallsURL.createObjectURL(mediaFile)directly in JSX for both the<img>and<video>previews, creating a new object URL on every rerender; there’s noURL.revokeObjectURL/cleanup anywhere in the file. Cache the preview URL and revoke it whenmediaFilechanges (and on unmount/removal).🤖 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 `@Client/src/pages/Scheduler.tsx` around lines 602 - 615, The preview currently calls URL.createObjectURL(mediaFile) inline in the JSX (mediaFile used inside the Scheduler component), which creates a new blob URL on every render and never revokes it; fix by adding a previewUrl state (e.g., const [previewUrl, setPreviewUrl] = useState<string | null>(null)) and a useEffect that watches mediaFile: when mediaFile is set, create a single blob URL with URL.createObjectURL(mediaFile), setPreviewUrl to it, and revoke any previous URL with URL.revokeObjectURL(prev) before replacing; also revoke the current previewUrl in the effect cleanup (and on component unmount) and update the <img> and <video> srcs to use previewUrl (or null) instead of calling URL.createObjectURL in the JSX.
🤖 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 `@Client/src/api/axios.ts`:
- Around line 3-5: The shared Axios instance "api" created via axios.create
currently only sets baseURL (import.meta.env.VITE_API_BASE_URL fallback) and
lacks a timeout; update the axios.create call that defines the api constant to
include a sensible timeout value (e.g., 5000 ms or project-configured env var)
so stalled requests are aborted and UI loading states don't hang; ensure the
timeout is documented/commented if using an env var and keep the identifier
"api" and the axios.create call unchanged otherwise.
In `@Client/src/context/AuthContext.tsx`:
- Around line 30-33: Guard the localStorage hydration in AuthContext by wrapping
JSON.parse(storedUser) in a try/catch: if parsing fails (malformed storedUser)
fall back to not setting user/token, clear the bad storedUser from localStorage
(or remove token) and avoid setting
api.defaults.headers.common["Authorization"]; update the code paths around
setUser and setToken to only run when parsing succeeds so the auth bootstrap
won't crash.
In `@Client/src/pages/Accounts.tsx`:
- Around line 16-27: When an error occurs during the sync call (the block using
isSync, platform, toast.loading and api.get("/api/oauth/sync")), the loading
toast with id "sync" isn't cleared; update the catch block to dismiss the "sync"
toast before showing the error (e.g., call toast.dismiss("sync") or equivalent)
so the persistent loading spinner is removed, then show the error toast
(toast.error(...)).
- Around line 44-45: The toast call re-decodes errorMsg (which was obtained from
new URLSearchParams(...).get("error") and is already decoded), causing failures
for strings with raw '%' sequences; update the error handling branch in the
component to pass errorMsg directly to toast.error (i.e., remove
decodeURIComponent(errorMsg)) and keep the existing fetchAccounts() call so the
rest of the flow (fetchAccounts) still runs; locate the branch using errorMsg
and toast.error in Accounts.tsx to make this change.
In `@Client/src/pages/AIComposer.tsx`:
- Around line 66-85: The scheduling handler can run twice because the button
remains clickable; add a fast guard at the top of handleSchedule that returns
early if scheduling is true (use the existing scheduling state managed by
setScheduling) and move setScheduling(true) to the very start of the function
before any awaits; also disable the modal schedule button while scheduling is
true (e.g., set the button's disabled prop using scheduling) so the UI prevents
double-clicks; apply the same guard/disable change to the other handler
referenced around the 314-324 block that uses setScheduling and posts to
/api/posts.
- Around line 55-75: The AIComposer schedule flow allows scheduling Instagram
posts without media (using activeScheduler, selectedPlatforms, scheduledDate,
scheduledTime and calling api.post) which differs from Scheduler.tsx validation;
update the validation in AIComposer.tsx to mirror Scheduler.tsx by checking if
selectedPlatforms includes "instagram" and ensuring activeScheduler.mediaUrl (or
appropriate media field) is present before proceeding, show a toast.error like
"Instagram posts require media" and return if missing, so the api.post payload
cannot create scheduled Instagram posts without media.
- Around line 43-45: The current prepend uses a render-time snapshot which can
lose entries; change setGenerations([data, ...generations]) in the generate
handler (e.g., where you call api.post and setActiveScheduler) to use a
functional updater: setGenerations(prev => [data, ...prev]). Also update
fetchGenerations (the function that currently does setGenerations(data)) to
merge results safely into state (e.g., setGenerations(prev => { combine fetched
items with prev, de-duplicate by id/timestamp, and return the merged array }) so
a late fetch won’t overwrite a just-generated entry.
In `@Client/src/pages/Dashboard.tsx`:
- Around line 17-21: The current Promise.all call fetching
api.get("/api/posts"), api.get("/api/accounts"), and api.get("/api/activity")
causes all results to be discarded if any promise (e.g., /api/activity) rejects;
change the implementation so posts/accounts still update even when activity
fails — either replace Promise.all with Promise.allSettled and handle each
result (fulfillment -> call setStats for posts/accounts and setActivities for
activity, rejection -> log and leave activities default), or split into two
awaits/try-catch blocks (one try/catch for api.get("/api/posts") and
api.get("/api/accounts") that calls setStats, and a separate try/catch for
api.get("/api/activity") that calls setActivities); ensure you reference and
update setStats and setActivities accordingly and keep existing error logging
behavior for failed activity calls.
In `@Client/src/pages/Scheduler.tsx`:
- Around line 478-484: fetchPosts currently always calls toast.error on any
failure causing the background polling loop to flood toasts; change fetchPosts
to accept an optional notify boolean (e.g., async function fetchPosts(notify =
false)) and only call toast.error when notify is true (or when it's the first
failure if you prefer). Update callers: the polling loop (where fetchPosts is
invoked every 10s) should call fetchPosts(false) to silently retry, and any
user-initiated refresh handler should call fetchPosts(true) so the user sees
errors. Keep the api.get("/api/posts") and setPosts logic unchanged and ensure
the catch block only shows toast when notify is true (or when using a
throttled/first-error-only policy).
- Around line 511-526: The scheduled datetime can be in the past and still be
sent as "scheduled", so compute the Date object from scheduledDate and
scheduledTime (same way you build scheduledFor), then validate that
scheduledDateTime is strictly in the future before building formData; if
scheduledDateTime <= new Date() show a toast.error like "Select a future date
and time" and return. Add this check after the existing presence checks for
scheduledDate/scheduledTime and before creating scheduledFor/formData (use the
same identifiers: scheduledDate, scheduledTime, scheduledFor).
In `@server/server.ts`:
- Line 2: The code currently forces global DNS servers (via dns.setServers)
which breaks many deployment environments; change it to read an environment
variable (e.g. process.env.CUSTOM_DNS_SERVERS) and only call dns.setServers when
that variable is set and non-empty, parsing a comma-separated list into the
array; leave the default behavior (do not call dns.setServers) when the env var
is absent so system DNS is used. Locate usages of dns.setServers in server.ts
(lines around import dns) and update them to use process.env.CUSTOM_DNS_SERVERS
with sensible validation (non-empty, split by comma, trim entries) before
invoking dns.setServers.
- Around line 13-14: Update the comment and guard around dns.setServers to
describe the specific Node 24 + Windows c-ares regression (where
dns.getServers() can return 127.0.0.1 causing dns.resolve*() to fail with
ECONNREFUSED) and only apply the override in that situation; check
process.platform === 'win32' and dns.getServers() for loopback entries (or check
process.version startsWith('v24')) before calling
dns.setServers(['8.8.8.8','8.8.4.4']), and change the comment to explicitly
mention the Windows c-ares bug, the observed failure mode (ECONNREFUSED), and
that this is a targeted workaround rather than a general DNS config change.
---
Outside diff comments:
In `@Client/src/pages/Scheduler.tsx`:
- Around line 602-615: The preview currently calls
URL.createObjectURL(mediaFile) inline in the JSX (mediaFile used inside the
Scheduler component), which creates a new blob URL on every render and never
revokes it; fix by adding a previewUrl state (e.g., const [previewUrl,
setPreviewUrl] = useState<string | null>(null)) and a useEffect that watches
mediaFile: when mediaFile is set, create a single blob URL with
URL.createObjectURL(mediaFile), setPreviewUrl to it, and revoke any previous URL
with URL.revokeObjectURL(prev) before replacing; also revoke the current
previewUrl in the effect cleanup (and on component unmount) and update the <img>
and <video> srcs to use previewUrl (or null) instead of calling
URL.createObjectURL in the JSX.
In `@server/services/schedulerService.ts`:
- Around line 54-68: The current catch block flips post.status to "failed" for
any error including ActivityLog.create failures after a successful publish;
modify the flow so publishing errors still set post.status = "failed" but
logging errors do not overwrite a successful publish. Specifically, keep the
publish logic (createPost / post.save / post.status = "published") together, and
move ActivityLog.create into its own try/catch (or check post.status ===
"published" before setting to "failed") so that exceptions from
ActivityLog.create are caught and logged without changing post.status; reference
functions/fields: createPost (or the publish call), post.save, post.status,
ActivityLog.create.
- Around line 11-18: Before calling createPost(), atomically claim each
scheduled post by changing its status to "publishing" so concurrent scheduler
ticks can't process the same post, e.g. replace the unconditional use of
Post.find(...) + iterating with a conditional atomic update: use
Post.findOneAndUpdate({_id: post._id, status: "scheduled", scheduledFor: {$lte:
now}}, {$set: {status: "publishing", publishingAt: new Date()}},
{returnDocument: "after"}) and only call createPost() if the update returned a
document; reference Post.find, the per-post loop, and createPost() when applying
this change. Ensure the same pattern is applied to the other block mentioned
(lines 42-55).
🪄 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
Run ID: 2ec07b4c-face-48e0-9b6e-7bc3fd03b586
⛔ Files ignored due to path filters (1)
Client/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (16)
Client/package.jsonClient/src/App.tsxClient/src/api/axios.tsClient/src/components/Home/Navbar.tsxClient/src/components/Layout.tsxClient/src/components/Sidebar.tsxClient/src/context/AuthContext.tsxClient/src/main.tsxClient/src/pages/AIComposer.tsxClient/src/pages/Accounts.tsxClient/src/pages/Dashboard.tsxClient/src/pages/Login.tsxClient/src/pages/Scheduler.tsxserver/routes/postRoutes.tsserver/server.tsserver/services/schedulerService.ts
| if(isSync){ | ||
| const label = platform ? platform.charAt(0).toUpperCase() + platform.slice(1) : | ||
| "Social Media"; | ||
| toast.loading(`Syncing ${label} account...`, {id: "sync"}); | ||
| await api.get("/api/oauth/sync"); | ||
| toast.success(successMsg || "Accounts synced!", {id: "sync"}) | ||
| } | ||
|
|
||
| const {data} = await api.get("/api/accounts") | ||
| setAccounts(data) | ||
| } catch (error: any) { | ||
| toast.error(error?.response?.data?.message || error?.message || "Failed to load accounts"); |
There was a problem hiding this comment.
Clear the sync loading toast on failures.
If /api/oauth/sync throws, the "sync" loading toast never gets replaced or dismissed, so users end up with a permanent spinner plus an error toast.
Suggested fix
if(isSync){
const label = platform ? platform.charAt(0).toUpperCase() + platform.slice(1) :
"Social Media";
toast.loading(`Syncing ${label} account...`, {id: "sync"});
await api.get("/api/oauth/sync");
toast.success(successMsg || "Accounts synced!", {id: "sync"})
}
@@
} catch (error: any) {
- toast.error(error?.response?.data?.message || error?.message || "Failed to load accounts");
+ toast.error(
+ error?.response?.data?.message || error?.message || "Failed to load accounts",
+ isSync ? { id: "sync" } : undefined,
+ );
}📝 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.
| if(isSync){ | |
| const label = platform ? platform.charAt(0).toUpperCase() + platform.slice(1) : | |
| "Social Media"; | |
| toast.loading(`Syncing ${label} account...`, {id: "sync"}); | |
| await api.get("/api/oauth/sync"); | |
| toast.success(successMsg || "Accounts synced!", {id: "sync"}) | |
| } | |
| const {data} = await api.get("/api/accounts") | |
| setAccounts(data) | |
| } catch (error: any) { | |
| toast.error(error?.response?.data?.message || error?.message || "Failed to load accounts"); | |
| if(isSync){ | |
| const label = platform ? platform.charAt(0).toUpperCase() + platform.slice(1) : | |
| "Social Media"; | |
| toast.loading(`Syncing ${label} account...`, {id: "sync"}); | |
| await api.get("/api/oauth/sync"); | |
| toast.success(successMsg || "Accounts synced!", {id: "sync"}) | |
| } | |
| const {data} = await api.get("/api/accounts") | |
| setAccounts(data) | |
| } catch (error: any) { | |
| toast.error( | |
| error?.response?.data?.message || error?.message || "Failed to load accounts", | |
| isSync ? { id: "sync" } : undefined, | |
| ); | |
| } |
🤖 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 `@Client/src/pages/Accounts.tsx` around lines 16 - 27, When an error occurs
during the sync call (the block using isSync, platform, toast.loading and
api.get("/api/oauth/sync")), the loading toast with id "sync" isn't cleared;
update the catch block to dismiss the "sync" toast before showing the error
(e.g., call toast.dismiss("sync") or equivalent) so the persistent loading
spinner is removed, then show the error toast (toast.error(...)).
| } else if(errorMsg){ | ||
| toast.error(`Connection failed: ${decodeURIComponent(errorMsg)}`) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show the relevant region of the file
sed -n '1,120p' Client/src/pages/Accounts.tsx | nl -ba | sed -n '1,120p'
# Extract any lines mentioning "errorMsg" to see where it's derived
rg -n "errorMsg" Client/src/pages/Accounts.tsx
# Show a bit more context around the usage near the indicated lines
# (Assuming file isn't huge; otherwise just show around the match lines.)
line_numbers=$(rg -n "errorMsg" Client/src/pages/Accounts.tsx | cut -d: -f1 | head -n 20)
for ln in $line_numbers; do
start=$((ln-20))
end=$((ln+20))
echo "---- context around line $ln ----"
sed -n "${start},${end}p" Client/src/pages/Accounts.tsx | nl -ba | sed -n "${start},${end}p"
done
# Search for URLSearchParams.get() usage and how query params are read (decode/encode)
rg -n "URLSearchParams|get\(" Client/src/pages/Accounts.tsxRepository: krishnag1606/SocialMediaAutomation
Length of output: 121
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="Client/src/pages/Accounts.tsx"
echo "== File exists =="
ls -la "$file" | head -n 20
echo "== Lines 35-70 (with line numbers via awk) =="
awk 'NR>=35 && NR<=70 {printf "%5d %s\n", NR, $0}' "$file"
echo "== errorMsg assignments/usages =="
rg -n "errorMsg" "$file" || true
echo "== URLSearchParams usage =="
rg -n "URLSearchParams|get\(|decodeURIComponent|encodeURIComponent" "$file" || trueRepository: krishnag1606/SocialMediaAutomation
Length of output: 2480
Remove redundant decodeURIComponent for the error query param
errorMsg is already read via new URLSearchParams(...).get("error"), which returns a decoded string—re-decoding can throw for valid messages containing raw % (e.g., "50% complete"), breaking the failed-connect path.
} else if(errorMsg){
toast.error(`Connection failed: ${decodeURIComponent(errorMsg)}`)
fetchAccounts();
}🤖 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 `@Client/src/pages/Accounts.tsx` around lines 44 - 45, The toast call
re-decodes errorMsg (which was obtained from new
URLSearchParams(...).get("error") and is already decoded), causing failures for
strings with raw '%' sequences; update the error handling branch in the
component to pass errorMsg directly to toast.error (i.e., remove
decodeURIComponent(errorMsg)) and keep the existing fetchAccounts() call so the
rest of the flow (fetchAccounts) still runs; locate the branch using errorMsg
and toast.error in Accounts.tsx to make this change.
| const { data } = await api.post("/api/posts/generate", {prompt, tone, generateImage}); | ||
| setGenerations([data, ...generations]); | ||
| setActiveScheduler(data) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate and print the relevant portions of AIComposer.tsx and Scheduler.tsx
repo_root="$(pwd)"
echo "== AIComposer.tsx (relevant section) =="
# Show around lines 1-120 to include definitions around the mentioned snippet
nl -ba Client/src/pages/AIComposer.tsx | sed -n '1,160p'
echo
echo "== Scheduler.tsx (relevant section) =="
nl -ba Client/src/pages/Scheduler.tsx | sed -n '1,220p'
echo
echo "== Search for generations updates and scheduling submission guards =="
rg -n "fetchGenerations|handleGenerate|handleSchedule|setGenerations\\(|/api/posts/generate|Instagram|media guard|disabled=\\{scheduling\\}|onClick=\\{.*Schedule|setActiveScheduler\\(" Client/src/pages/AIComposer.tsx Client/src/pages/Scheduler.tsx
echo
echo "== Search for any other setGenerations usages =="
rg -n "setGenerations\\(" Client/src/pages | head -n 50Repository: krishnag1606/SocialMediaAutomation
Length of output: 179
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== AIComposer.tsx (first ~180 lines) =="
awk '{printf "%4d\t%s\n", NR, $0}' Client/src/pages/AIComposer.tsx | sed -n '1,180p'
echo
echo "== AIComposer.tsx (lines 30-120) =="
awk '{printf "%4d\t%s\n", NR, $0}' Client/src/pages/AIComposer.tsx | sed -n '30,120p'
echo
echo "== Scheduler.tsx (first ~260 lines) =="
awk '{printf "%4d\t%s\n", NR, $0}' Client/src/pages/Scheduler.tsx | sed -n '1,260p'
echo
echo "== Search in AIComposer.tsx for generations / schedule submission =="
rg -n "fetchGenerations|handleGenerate|handleSchedule|setGenerations\\(|/api/posts/generate|Instagram|media|disabled=\\{scheduling\\}|onClick=\\{.*Schedule|setActiveScheduler\\(" Client/src/pages/AIComposer.tsx
echo
echo "== Search in Scheduler.tsx for Instagram/media guard and submission guard =="
rg -n "Instagram|media|guard|disabled=|setDisabled|onClick=\\{|handleSchedule|/api/posts" Client/src/pages/Scheduler.tsx
echo
echo "== Search whole Client/src/pages for setGenerations usages =="
rg -n "setGenerations\\(" Client/src/pages | head -n 80Repository: krishnag1606/SocialMediaAutomation
Length of output: 28647
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== AIComposer.tsx (lines 180-380) =="
awk '{printf "%4d\t%s\n", NR, $0}' Client/src/pages/AIComposer.tsx | sed -n '180,380p'
echo
echo "== AIComposer.tsx (lines 380-end) =="
awk '{printf "%4d\t%s\n", NR, $0}' Client/src/pages/AIComposer.tsx | tail -n 200
echo
echo "== Scheduler.tsx (Instagram media guard area) =="
awk '{printf "%4d\t%s\n", NR, $0}' Client/src/pages/Scheduler.tsx | sed -n '480,560p'
echo
echo "== Scheduler.tsx (schedule button disabled/loading area) =="
awk '{printf "%4d\t%s\n", NR, $0}' Client/src/pages/Scheduler.tsx | sed -n '650,710p'Repository: krishnag1606/SocialMediaAutomation
Length of output: 23904
Use a functional updater when prepending generations.
setGenerations([data, ...generations]) prepends using a render-time snapshot, so overlapping/rapid handleGenerate completions can lose previously-added items. Also, the initial fetchGenerations() currently overwrites the whole list (setGenerations(data)), which can drop a just-generated entry if it returns afterward.
Suggested fix
- setGenerations([data, ...generations]);
+ setGenerations((prev) => [data, ...prev]);📝 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 { data } = await api.post("/api/posts/generate", {prompt, tone, generateImage}); | |
| setGenerations([data, ...generations]); | |
| setActiveScheduler(data) | |
| const { data } = await api.post("/api/posts/generate", {prompt, tone, generateImage}); | |
| setGenerations((prev) => [data, ...prev]); | |
| setActiveScheduler(data) |
🤖 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 `@Client/src/pages/AIComposer.tsx` around lines 43 - 45, The current prepend
uses a render-time snapshot which can lose entries; change setGenerations([data,
...generations]) in the generate handler (e.g., where you call api.post and
setActiveScheduler) to use a functional updater: setGenerations(prev => [data,
...prev]). Also update fetchGenerations (the function that currently does
setGenerations(data)) to merge results safely into state (e.g.,
setGenerations(prev => { combine fetched items with prev, de-duplicate by
id/timestamp, and return the merged array }) so a late fetch won’t overwrite a
just-generated entry.
| const [postsRes, accountsRes, activityRes] = await Promise.all([ | ||
| api.get("/api/posts"), | ||
| api.get("/api/accounts"), | ||
| api.get("/api/activity") | ||
| ]) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate and inspect the referenced file/lines
FILE="Client/src/pages/Dashboard.tsx"
if [ ! -f "$FILE" ]; then
echo "Missing: $FILE"
exit 1
fi
echo "=== File: $FILE (lines 1-120) ==="
nl -ba "$FILE" | sed -n '1,140p'
echo "=== Extract: lines 10-60 (fetch logic + surrounding) ==="
nl -ba "$FILE" | sed -n '10,70p'
echo "=== Search for Promise.all / allSettled usage ==="
rg -n "Promise\.all|allSettled\(" "$FILE" || true
echo "=== Search for console.error handling in Dashboard.tsx ==="
rg -n "console\.error" "$FILE" || true
echo "=== Search for posts/accounts/activity response handling ==="
rg -n "postsRes|accountsRes|activityRes|posts|accounts|activity" "$FILE" | head -n 80Repository: krishnag1606/SocialMediaAutomation
Length of output: 199
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="Client/src/pages/Dashboard.tsx"
test -f "$FILE" || { echo "Missing: $FILE"; exit 1; }
echo "=== File: $FILE (lines 1-140) ==="
cat -n "$FILE" | sed -n '1,140p'
echo "=== Extract: lines 10-70 ==="
cat -n "$FILE" | sed -n '10,70p'
echo "=== Search for Promise.all / allSettled usage ==="
rg -n "Promise\.all|allSettled\(" "$FILE" || true
echo "=== Search for console.error handling in Dashboard.tsx ==="
rg -n "console\.error" "$FILE" || true
echo "=== Search for response handling variables ==="
rg -n "postsRes|accountsRes|activityRes" "$FILE" || true
echo "=== Show fetch section for context (API calls) ==="
rg -n "api\.get\(\"/api/(posts|accounts|activity)\"\)" "$FILE" -n || trueRepository: krishnag1606/SocialMediaAutomation
Length of output: 8987
Don’t gate dashboard stats on /api/activity failure.
Client/src/pages/Dashboard.tsx fetches /api/posts, /api/accounts, and /api/activity in one Promise.all; if /api/activity rejects, neither setStats(...) nor setActivities(...) runs (the single catch only logs with console.error), so the dashboard stays at default values. Use Promise.allSettled() or split into separate try/catch blocks so posts/accounts render even when activity fails.
🤖 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 `@Client/src/pages/Dashboard.tsx` around lines 17 - 21, The current Promise.all
call fetching api.get("/api/posts"), api.get("/api/accounts"), and
api.get("/api/activity") causes all results to be discarded if any promise
(e.g., /api/activity) rejects; change the implementation so posts/accounts still
update even when activity fails — either replace Promise.all with
Promise.allSettled and handle each result (fulfillment -> call setStats for
posts/accounts and setActivities for activity, rejection -> log and leave
activities default), or split into two awaits/try-catch blocks (one try/catch
for api.get("/api/posts") and api.get("/api/accounts") that calls setStats, and
a separate try/catch for api.get("/api/activity") that calls setActivities);
ensure you reference and update setStats and setActivities accordingly and keep
existing error logging behavior for failed activity calls.
| const fetchPosts = async () => { | ||
| setPosts(dummyPostsData) | ||
| try { | ||
| const { data } = await api.get("/api/posts") | ||
| setPosts(data) | ||
| } catch (error: any) { | ||
| toast.error(error?.response?.data?.message || error.message); | ||
| } |
There was a problem hiding this comment.
Background refresh failures will spam the user every 10 seconds.
fetchPosts() is used by the polling loop and always calls toast.error() on failure. If the API is down, this page becomes a toast flood instead of passively retrying in the background.
Also applies to: 491-492
🤖 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 `@Client/src/pages/Scheduler.tsx` around lines 478 - 484, fetchPosts currently
always calls toast.error on any failure causing the background polling loop to
flood toasts; change fetchPosts to accept an optional notify boolean (e.g.,
async function fetchPosts(notify = false)) and only call toast.error when notify
is true (or when it's the first failure if you prefer). Update callers: the
polling loop (where fetchPosts is invoked every 10s) should call
fetchPosts(false) to silently retry, and any user-initiated refresh handler
should call fetchPosts(true) so the user sees errors. Keep the
api.get("/api/posts") and setPosts logic unchanged and ensure the catch block
only shows toast when notify is true (or when using a throttled/first-error-only
policy).
| @@ -1,4 +1,5 @@ | |||
| import "dotenv/config"; | |||
| import dns from "dns"; | |||
There was a problem hiding this comment.
Hardcoded DNS servers will break in many deployment environments.
Setting DNS servers to hardcoded public Google DNS (8.8.8.8, 8.8.4.4) at the process level can cause failures in:
- Container orchestrators (Kubernetes, ECS) that use internal DNS for service discovery
- Corporate networks requiring internal DNS servers
- Regions where Google DNS is blocked or slow
- Any environment with custom DNS configuration (service mesh, split-horizon DNS)
Make DNS servers configurable via environment variables with sensible defaults (system DNS):
🔧 Proposed fix to make DNS configuration optional and environment-driven
-// 2. Set custom DNS servers to fix Node 24 DNS resolution issues
-dns.setServers(['8.8.8.8', '8.8.4.4']); // Google's DNS servers
+// Set custom DNS servers if specified (workaround for Node 24 DNS resolution issues)
+const customDnsServers = process.env.CUSTOM_DNS_SERVERS;
+if (customDnsServers) {
+ const servers = customDnsServers.split(',').map(s => s.trim());
+ dns.setServers(servers);
+ console.log(`Using custom DNS servers: ${servers.join(', ')}`);
+}Then set CUSTOM_DNS_SERVERS="8.8.8.8,8.8.4.4" only in environments where the workaround is needed.
Also applies to: 13-14
🤖 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 `@server/server.ts` at line 2, The code currently forces global DNS servers
(via dns.setServers) which breaks many deployment environments; change it to
read an environment variable (e.g. process.env.CUSTOM_DNS_SERVERS) and only call
dns.setServers when that variable is set and non-empty, parsing a
comma-separated list into the array; leave the default behavior (do not call
dns.setServers) when the env var is absent so system DNS is used. Locate usages
of dns.setServers in server.ts (lines around import dns) and update them to use
process.env.CUSTOM_DNS_SERVERS with sensible validation (non-empty, split by
comma, trim entries) before invoking dns.setServers.
| // 2. Set custom DNS servers to fix Node 24 DNS resolution issues | ||
| dns.setServers(['8.8.8.8', '8.8.4.4']); // Google's DNS servers |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Node.js 24 DNS resolution issues bugs problems
💡 Result:
As of June 8, 2026, several DNS-related issues have been documented in Node.js 24 (as well as other versions) primarily tied to regressions in the bundled c-ares library and libuv thread pool handling. DNS Regression on Windows A significant regression has been observed on Windows where Node.js incorrectly identifies DNS servers, often returning 127.0.0.1 instead of the actual system-configured DNS server [1][2]. This issue is linked to c-ares version 1.34.6 [1]. - Symptoms: dns.getServers() returns ['127.0.0.1'] [1][2]. Subsequent calls to dns.resolve*() methods (which rely on c-ares) fail with ECONNREFUSED because there is no listener on that loopback address [1][3]. - Workaround: The dns.lookup() function, which bypasses c-ares and uses the OS-level getaddrinfo, continues to function correctly [1]. Alternatively, manually setting the DNS servers using dns.setServers() can restore functionality [1]. SRV Record Failures Users have reported ECONNREFUSED errors specifically when using dns.resolveSrv() (and related methods like resolveMx) on Windows, often impacting applications like MongoDB drivers [3][4]. This was identified as a c-ares fallback detection issue, where the library failed to properly identify the loopback resolver, resulting in attempted queries to port 53 on 127.0.0.1 [3]. While specific fixes have been committed to the Node.js repository [3][4], users encountering these persistent issues are advised to verify their specific minor version and consider if they are affected by the c-ares 1.34.6 regression [1]. Unbounded Promise Queuing A separate performance issue involves dns.promises.lookup() [5]. Under high load, when hostnames trigger EAI_AGAIN (e.g., invalid TLDs), the associated getaddrinfo calls can block libuv threads for extended periods (approximately 10 seconds) [5]. Because the thread pool is fixed in size (default of 4), sustained load leads to an unbounded growth of pending promises as new requests queue behind the blocked threads [5]. Users experiencing these DNS failures are encouraged to: 1. Check the official Node.js issue tracker for the most recent updates on c-ares patches [1][3]. 2. Use dns.lookup() as a temporary alternative if dns.resolve* methods are failing due to c-ares regressions [1]. 3. Ensure their environment is not suffering from libuv thread pool saturation if experiencing latency or promise-related issues [5].
Citations:
- 1: dns.getServers() returns 127.0.0.1 instead of actual DNS server on Windows (c-ares 1.34.6 regression) nodejs/node#62748
- 2: dns.getServers() incorrectly returns 127.0.0.1 when OS DNS is configured to 8.8.8.8 nodejs/node#62347
- 3: dns: fix Windows SRV ECONNREFUSED regression by correcting c-ares fallback detection nodejs/node#61453
- 4: dns: error ECONNREFUSED when using resolveSrv nodejs/node#61435
- 5: dns.lookup: pending promises grow unboundedly under sustained EAI_AGAIN load nodejs/node#62503
Clarify the exact Node 24 DNS workaround and its scope (server/server.ts:13-14)
The phrase “Node 24 DNS resolution issues” should be tied to a specific known failure mode: on Windows, a c-ares regression can mis-detect the DNS server (e.g., dns.getServers() returning 127.0.0.1), causing dns.resolve*() to fail (commonly ECONNREFUSED); in that scenario, overriding via dns.setServers() is a documented workaround. Update the comment to mention this (and ideally gate it to the affected platform/condition) so it doesn’t broadly mask unrelated DNS/network configuration problems.
🤖 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 `@server/server.ts` around lines 13 - 14, Update the comment and guard around
dns.setServers to describe the specific Node 24 + Windows c-ares regression
(where dns.getServers() can return 127.0.0.1 causing dns.resolve*() to fail with
ECONNREFUSED) and only apply the override in that situation; check
process.platform === 'win32' and dns.getServers() for loopback entries (or check
process.version startsWith('v24')) before calling
dns.setServers(['8.8.8.8','8.8.4.4']), and change the comment to explicitly
mention the Windows c-ares bug, the observed failure mode (ECONNREFUSED), and
that this is a targeted workaround rather than a general DNS config change.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Summary by CodeRabbit
New Features
Bug Fixes