Skip to content

Server action error fix#2054

Merged
simo6529 merged 7 commits intomainfrom
server-action-error-fix
Mar 4, 2026
Merged

Server action error fix#2054
simo6529 merged 7 commits intomainfrom
server-action-error-fix

Conversation

@simo6529
Copy link
Copy Markdown
Collaborator

@simo6529 simo6529 commented Mar 4, 2026

Summary by CodeRabbit

  • New Features

    • Enhanced push notification registration with retry, in‑flight deduplication, and improved error handling.
    • API POST can return structured error metadata (new error mode).
    • Expanded probe-aware filters to reduce probe-related noise in error reporting.
  • Bug Fixes

    • Improved component stability across re-renders.
    • Better handling and deduplication of concurrent registration attempts.
  • Tests

    • New tests covering push registration retries and structured API error behavior.
  • Chores

    • Formatting and minor refactoring.

simo6529 added 5 commits March 4, 2026 12:57
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 4, 2026

📝 Walkthrough

Walkthrough

Implements retriable, deduplicated push-registration with fingerprinting and Sentry breadcrumbs; adds probe-aware Sentry filters for server-action, malformed next-action, and web-streams probes and wires them into beforeSend; expands API error handling to support structured errors and retry options; updates related tests and a wave container ref stability change.

Changes

Cohort / File(s) Summary
Push Registration Tests
__tests__/components/notifications/NotificationsContext.test.tsx
Adds tests for push registration retry flows (rate-limit handling and Retry-After), in-flight deduplication via fingerprints, and Sentry breadcrumb/exception assertions; resets Sentry mocks between tests.
Push Registration Logic
components/notifications/NotificationsContext.tsx
Introduces retry/backoff/jitter constants and utilities, Retry-After parsing, rate-limit/transient error detection, computePushRegistrationRetryDelayMs, PushRegistrationFingerprint type and helpers, in-flight deduplication/last-success caching, registerPushNotificationWithRetry, and wiring of handlePushRegistration into init flow with Sentry breadcrumbs.
Sentry Probe Utilities
config/sentryProbes.ts
Adds probe-detection constants and helpers for server-action, malformed next-action, and web-streams probe requests; exports three filters: filterServerActionProbeErrors, filterMalformedNextActionProbeErrors, and filterWebStreamsProbeErrors.
Sentry Edge Config
sentry.edge.config.ts
Refactors beforeSend to sequentially apply probe filters (server-action → malformed next-action → web-streams) with early null-returns; sanitization now runs after all filters.
Sentry Server Config
sentry.server.config.ts
Restructures beforeSend pipeline to tag security probes then run the three probe filters in sequence with early-drops and final sanitization.
API error handling & tests
services/api/common-api.ts, __tests__/services/common-api.test.ts
Adds ApiErrorMode and StructuredApiError, createStructuredApiError, normalizeHeaders; handleApiError/executeApiRequest accept errorMode; commonApiFetchWithRetry accepts retryOptions; commonApiPost supports errorMode; tests updated to validate structured error payloads and Retry-After behavior.
WaveDropsReverseContainer Tests
__tests__/components/waves/drops/WaveDropsReverseContainer.test.tsx
Formatting/quote-style changes and adds test ensuring an imperative callback ref remains stable across re-renders and detaches only on unmount.
WaveDropsReverseContainer Implementation
components/waves/drops/WaveDropsReverseContainer.tsx
Stabilizes useImperativeHandle by adding an empty dependency array.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Capacitor as Capacitor PushNotifications
    participant Backend as Backend Registration
    participant Sentry as Sentry

    App->>Capacitor: requestRegistration(fingerprint)
    activate Capacitor
    Capacitor->>Backend: POST /register (fingerprint)
    activate Backend

    alt 429 (Rate Limited)
        Backend-->>Capacitor: 429 + Retry-After
        Capacitor-->>App: error with retry metadata
        App->>Sentry: addBreadcrumb("rate-limit")
        App->>App: schedule retry (computePushRegistrationRetryDelayMs)
    else Transient Error
        Backend-->>Capacitor: 5xx / network error
        Capacitor-->>App: error
        App->>Sentry: captureException(tag="transient")
        App->>App: retry according to transient rules
    else Success
        Backend-->>Capacitor: 200 + token
        Capacitor-->>App: success
        App->>App: cache lastSuccessfulRegistrationRef(fingerprint)
        App->>Sentry: addBreadcrumb("registration-success")
    end
    deactivate Backend
    deactivate Capacitor
Loading
sequenceDiagram
    participant Event as Sentry Event
    participant Tagger as tagSecurityProbes
    participant Filter1 as filterServerActionProbeErrors
    participant Filter2 as filterMalformedNextActionProbeErrors
    participant Filter3 as filterWebStreamsProbeErrors
    participant Sanitizer as sanitizeSentryEvent
    participant Sentry as Sentry Backend

    Event->>Tagger: beforeSend(event)
    activate Tagger
    Tagger-->>Filter1: taggedEvent
    deactivate Tagger

    Filter1->>Filter1: is probe-like?
    alt probe-like
        Filter1-->>Sentry: null (suppress)
    else not probe-like
        Filter1-->>Filter2: continue
        Filter2->>Filter2: malformed next-action?
        alt malformed
            Filter2-->>Sentry: null (suppress)
        else
            Filter2-->>Filter3: continue
            Filter3->>Filter3: web-streams probe?
            alt probe-like
                Filter3-->>Sentry: null (suppress)
            else
                Filter3-->>Sanitizer: continue
                Sanitizer-->>Sentry: send sanitized event
            end
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • #1623 — modifies push registration and NotificationsContext.tsx; overlaps on registration/listener flow.
  • #1667 — modifies push-registration flow and tests in NotificationsContext; overlaps on callback/listener handling and retry behavior.
  • #1614 — updates services/api/common-api.ts error handling and tests; relates to structured API error changes and retry behavior.

Suggested reviewers

  • prxt6529
  • ragnep

Poem

🐰
A hop, a retry, a fingerprint fine,
No duplicate dances this registration time.
Breadcrumbs to Sentry, probes gently spared,
We hop on—resilient, debounced, and prepared.

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Server action error fix' is too vague and generic. While the PR does include server action error handling in config/sentryProbes.ts, it encompasses much broader changes including push notification retry mechanisms, API error handling, Sentry filtering logic, and test updates across multiple files. The title only hints at one aspect and fails to convey the primary scope of changes. Consider a more descriptive title that captures the main objective, such as 'Add push notification retry logic with Sentry probe filtering' or 'Implement retry mechanism and probe-aware error handling' to better reflect the comprehensive nature of changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch server-action-error-fix

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e770a83af9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread components/notifications/NotificationsContext.tsx Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
config/sentryProbes.ts (1)

170-206: Split getHeaderValue into shape-specific helpers to reduce complexity.

This block already tripped the cognitive-complexity threshold; extracting array/object parsing keeps behavior intact and lowers maintenance cost.

♻️ Refactor sketch
+function getHeaderValueFromTupleEntries(
+  headers: unknown[],
+  normalizedTarget: string
+): string | undefined {
+  for (const entry of headers) {
+    if (!Array.isArray(entry) || entry.length < 2) continue;
+    const key = entry[0];
+    const value = entry[1];
+    if (
+      typeof key === "string" &&
+      key.toLowerCase() === normalizedTarget &&
+      typeof value === "string"
+    ) {
+      return value;
+    }
+  }
+  return undefined;
+}
+
+function getHeaderValueFromRecord(
+  headers: Record<string, unknown>,
+  normalizedTarget: string
+): string | undefined {
+  for (const [key, value] of Object.entries(headers)) {
+    if (key.toLowerCase() !== normalizedTarget) continue;
+    return typeof value === "string" ? value : undefined;
+  }
+  return undefined;
+}
+
 function getHeaderValue(
   headers: unknown,
   headerName: string
 ): string | undefined {
   const normalizedTarget = headerName.toLowerCase();
 
   if (Array.isArray(headers)) {
-    for (const entry of headers) {
-      if (!Array.isArray(entry) || entry.length < 2) {
-        continue;
-      }
-      const key = entry[0];
-      const value = entry[1];
-      if (
-        typeof key === "string" &&
-        key.toLowerCase() === normalizedTarget &&
-        typeof value === "string"
-      ) {
-        return value;
-      }
-    }
-    return undefined;
+    return getHeaderValueFromTupleEntries(headers, normalizedTarget);
   }
 
-  if (!isRecord(headers)) {
-    return undefined;
+  if (isRecord(headers)) {
+    return getHeaderValueFromRecord(headers, normalizedTarget);
   }
 
-  for (const [key, value] of Object.entries(headers)) {
-    if (key.toLowerCase() !== normalizedTarget) {
-      continue;
-    }
-    return typeof value === "string" ? value : undefined;
-  }
-
   return undefined;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/sentryProbes.ts` around lines 170 - 206, getHeaderValue is doing two
shape-specific parsing flows (array and record) in one function which raised
cognitive complexity; extract the array-handling and record-handling logic into
two small helpers (e.g., getHeaderValueFromArray(headers: unknown[], headerName:
string): string | undefined and getHeaderValueFromRecord(headers: Record<string,
unknown>, headerName: string): string | undefined) and have getHeaderValue call
them: if Array.isArray(headers) -> getHeaderValueFromArray, else if
isRecord(headers) -> getHeaderValueFromRecord, otherwise return undefined;
preserve all current checks (entry length, string key/value checks,
case-insensitive compare using headerName.toLowerCase()) and return semantics
exactly as implemented.
sentry.edge.config.ts (1)

44-69: Consider extracting the shared beforeSend probe pipeline.

This sequence now duplicates sentry.server.config.ts almost line-for-line, which increases drift risk during future tuning.

♻️ Suggested extraction pattern
+// config/sentryEventFilters.ts
+import type { Event, EventHint } from "@sentry/nextjs";
+import {
+  filterMalformedNextActionProbeErrors,
+  filterServerActionProbeErrors,
+  filterTunnelRouteErrors,
+  filterWebStreamsProbeErrors,
+  tagSecurityProbes,
+} from "@/config/sentryProbes";
+
+export function applyProbeFilters<T extends Event>(event: T, hint?: EventHint): T | null {
+  const tunnelFiltered = filterTunnelRouteErrors(event, hint);
+  if (tunnelFiltered === null) return null;
+
+  const tagged = tagSecurityProbes(tunnelFiltered);
+  const actionFiltered = filterServerActionProbeErrors(tagged);
+  if (actionFiltered === null) return null;
+
+  const malformed = filterMalformedNextActionProbeErrors(actionFiltered);
+  if (malformed === null) return null;
+
+  return filterWebStreamsProbeErrors(malformed);
+}
-  beforeSend(event: Sentry.ErrorEvent, hint: Sentry.EventHint) {
-    const tunnelFiltered = filterTunnelRouteErrors(event, hint);
-    ...
-    return sanitizeSentryEvent(webStreamsFiltered);
-  },
+  beforeSend(event: Sentry.ErrorEvent, hint: Sentry.EventHint) {
+    const filtered = applyProbeFilters(event, hint);
+    if (filtered === null) return null;
+    return sanitizeSentryEvent(filtered);
+  },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sentry.edge.config.ts` around lines 44 - 69, The beforeSend pipeline in
sentry.edge.config.ts duplicates logic from sentry.server.config.ts; extract the
shared sequence into a single exported helper (e.g., buildProbeBeforeSend or
runProbePipeline) that composes filterTunnelRouteErrors, tagSecurityProbes,
filterServerActionProbeErrors, filterMalformedNextActionProbeErrors,
filterWebStreamsProbeErrors, and sanitizeSentryEvent so both
sentry.edge.config.ts and sentry.server.config.ts import and call that helper
from their beforeSend functions to avoid duplication and drift.
__tests__/components/notifications/NotificationsContext.test.tsx (2)

241-244: Mock the rate-limit failure as a string too (runtime-realistic path).

commonApiPost can reject HTTP failures as plain strings, so this test should also cover string-based rate-limit errors to validate real retry classification behavior.

Suggested diff
-    const rateLimitError = new Error("Rate limit exceeded. Try again in 1 sec");
+    const rateLimitError = "Too Many Requests. Try again in 1 sec";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__tests__/components/notifications/NotificationsContext.test.tsx` around
lines 241 - 244, The test currently mocks a rate-limit error as an Error object
(rateLimitError) but commonApiPost can also reject with plain strings at
runtime, so update the test around commonApiPost and setupRegistrationCallback
to also cover the string-rejection path: add an additional mock (or replace the
mock) so commonApiPost.mockRejectedValue / mockRejectedValueOnce returns the
string "Rate limit exceeded. Try again in 1 sec" (in addition to or instead of
the Error instance) and assert that the registrationCallback retry
classification behaves the same; reference commonApiPost and
setupRegistrationCallback when making this change.

246-253: Use globalThis for timer spies.

Switching from global to globalThis is more idiomatic and avoids environment-specific lint warnings.

Suggested diff
-    const setTimeoutSpy = jest.spyOn(global, "setTimeout").mockImplementation(((
+    const setTimeoutSpy = jest.spyOn(globalThis, "setTimeout").mockImplementation(((
       handler: TimerHandler
     ) => {
       if (typeof handler === "function") {
         handler();
       }
       return 0 as unknown as NodeJS.Timeout;
-    }) as typeof global.setTimeout);
+    }) as typeof globalThis.setTimeout);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__tests__/components/notifications/NotificationsContext.test.tsx` around
lines 246 - 253, Replace the environment-specific global reference when spying
timers: change the jest.spyOn call that creates setTimeoutSpy from using global
to globalThis so the spy is environment-agnostic (update the expression
jest.spyOn(global, "setTimeout") to jest.spyOn(globalThis, "setTimeout") and
keep the current mockImplementation/cast intact for setTimeoutSpy).
__tests__/components/waves/drops/WaveDropsReverseContainer.test.tsx (1)

46-51: Prefer globalThis over window in test mocks.

Using globalThis.requestAnimationFrame makes this setup more runtime-agnostic and aligns with the static-analysis warning.

Suggested diff
-    jest
-      .spyOn(window, "requestAnimationFrame")
+    jest
+      .spyOn(globalThis, "requestAnimationFrame")
       .mockImplementation((cb: any) => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__tests__/components/waves/drops/WaveDropsReverseContainer.test.tsx` around
lines 46 - 51, Update the test's spy to use globalThis instead of window: change
the jest.spyOn target from window to globalThis (i.e., jest.spyOn(globalThis,
"requestAnimationFrame")...) and keep the same mockImplementation callback and
return value so the test remains behaviorally identical; ensure the spy
references requestAnimationFrame so static analysis warnings are resolved.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/notifications/NotificationsContext.tsx`:
- Around line 127-144: The code assumes errors are object-shaped
(extractErrorStatusCode / extractRetryAfterMs) but commonApiPost in
services/api/common-api.ts rejects non-2xx responses as plain strings, so update
commonApiPost to reject with an Error-like object that preserves status and
headers (e.g., throw or reject { message, status: response.status, headers:
response.headers } or an Error instance augmented with status and headers) so
extractErrorStatusCode and extractRetryAfterMs can read status/response.status
and headers; alternatively, if you prefer changing the extractors, extend
extractErrorStatusCode and extractRetryAfterMs to detect string rejections from
commonApiPost and parse/unwrap an attached metadata object (status/headers) —
ensure the unique symbols mentioned (commonApiPost, extractErrorStatusCode,
extractRetryAfterMs) are updated accordingly so retry classification and
Retry-After backoff receive the status and header info.

---

Nitpick comments:
In `@__tests__/components/notifications/NotificationsContext.test.tsx`:
- Around line 241-244: The test currently mocks a rate-limit error as an Error
object (rateLimitError) but commonApiPost can also reject with plain strings at
runtime, so update the test around commonApiPost and setupRegistrationCallback
to also cover the string-rejection path: add an additional mock (or replace the
mock) so commonApiPost.mockRejectedValue / mockRejectedValueOnce returns the
string "Rate limit exceeded. Try again in 1 sec" (in addition to or instead of
the Error instance) and assert that the registrationCallback retry
classification behaves the same; reference commonApiPost and
setupRegistrationCallback when making this change.
- Around line 246-253: Replace the environment-specific global reference when
spying timers: change the jest.spyOn call that creates setTimeoutSpy from using
global to globalThis so the spy is environment-agnostic (update the expression
jest.spyOn(global, "setTimeout") to jest.spyOn(globalThis, "setTimeout") and
keep the current mockImplementation/cast intact for setTimeoutSpy).

In `@__tests__/components/waves/drops/WaveDropsReverseContainer.test.tsx`:
- Around line 46-51: Update the test's spy to use globalThis instead of window:
change the jest.spyOn target from window to globalThis (i.e.,
jest.spyOn(globalThis, "requestAnimationFrame")...) and keep the same
mockImplementation callback and return value so the test remains behaviorally
identical; ensure the spy references requestAnimationFrame so static analysis
warnings are resolved.

In `@config/sentryProbes.ts`:
- Around line 170-206: getHeaderValue is doing two shape-specific parsing flows
(array and record) in one function which raised cognitive complexity; extract
the array-handling and record-handling logic into two small helpers (e.g.,
getHeaderValueFromArray(headers: unknown[], headerName: string): string |
undefined and getHeaderValueFromRecord(headers: Record<string, unknown>,
headerName: string): string | undefined) and have getHeaderValue call them: if
Array.isArray(headers) -> getHeaderValueFromArray, else if isRecord(headers) ->
getHeaderValueFromRecord, otherwise return undefined; preserve all current
checks (entry length, string key/value checks, case-insensitive compare using
headerName.toLowerCase()) and return semantics exactly as implemented.

In `@sentry.edge.config.ts`:
- Around line 44-69: The beforeSend pipeline in sentry.edge.config.ts duplicates
logic from sentry.server.config.ts; extract the shared sequence into a single
exported helper (e.g., buildProbeBeforeSend or runProbePipeline) that composes
filterTunnelRouteErrors, tagSecurityProbes, filterServerActionProbeErrors,
filterMalformedNextActionProbeErrors, filterWebStreamsProbeErrors, and
sanitizeSentryEvent so both sentry.edge.config.ts and sentry.server.config.ts
import and call that helper from their beforeSend functions to avoid duplication
and drift.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 31ededf2-6316-4452-95d6-a41400888358

📥 Commits

Reviewing files that changed from the base of the PR and between 6954351 and e770a83.

📒 Files selected for processing (7)
  • __tests__/components/notifications/NotificationsContext.test.tsx
  • __tests__/components/waves/drops/WaveDropsReverseContainer.test.tsx
  • components/notifications/NotificationsContext.tsx
  • components/waves/drops/WaveDropsReverseContainer.tsx
  • config/sentryProbes.ts
  • sentry.edge.config.ts
  • sentry.server.config.ts

Comment thread components/notifications/NotificationsContext.tsx
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
__tests__/components/notifications/NotificationsContext.test.tsx (1)

246-253: Prefer globalThis over global for cross-environment compatibility.

Static analysis correctly flags the use of global. Using globalThis is the modern, standardized approach that works consistently across Node.js and browser environments.

Proposed fix
-    const setTimeoutSpy = jest.spyOn(global, "setTimeout").mockImplementation(((
+    const setTimeoutSpy = jest.spyOn(globalThis, "setTimeout").mockImplementation(((
       handler: TimerHandler
     ) => {
       if (typeof handler === "function") {
         handler();
       }
-      return 0 as unknown as NodeJS.Timeout;
-    }) as typeof global.setTimeout);
+      return 0 as unknown as ReturnType<typeof setTimeout>;
+    }) as typeof globalThis.setTimeout);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__tests__/components/notifications/NotificationsContext.test.tsx` around
lines 246 - 253, Replace usage of the Node-specific global with the standardized
globalThis when spying on setTimeout: update the jest.spyOn call that creates
setTimeoutSpy (the spy variable created with jest.spyOn(global, "setTimeout"))
to use globalThis instead (i.e., jest.spyOn(globalThis, "setTimeout")), ensuring
the mockImplementation and teardown logic remain unchanged and still target the
same setTimeout function.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@services/api/common-api.ts`:
- Around line 92-119: The code currently calls res.json() then res.text(), which
double-reads the response body; instead, read the response body once (call
res.text() a single time into a variable like rawContent), assign errorBody =
rawContent (if present), then attempt to JSON.parse(rawContent) to extract
bodyRecord/bodyError/bodyMessage and set errorMessage accordingly (falling back
to rawContent or res.statusText or "Something went wrong"); update the
error-parsing block around res, errorBody, errorMessage, bodyRecord, bodyError,
and bodyMessage to follow this single-read approach.

---

Nitpick comments:
In `@__tests__/components/notifications/NotificationsContext.test.tsx`:
- Around line 246-253: Replace usage of the Node-specific global with the
standardized globalThis when spying on setTimeout: update the jest.spyOn call
that creates setTimeoutSpy (the spy variable created with jest.spyOn(global,
"setTimeout")) to use globalThis instead (i.e., jest.spyOn(globalThis,
"setTimeout")), ensuring the mockImplementation and teardown logic remain
unchanged and still target the same setTimeout function.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1b64c7d2-87dd-4ade-a4dd-0d0323d4b8ae

📥 Commits

Reviewing files that changed from the base of the PR and between e770a83 and 8a44339.

📒 Files selected for processing (4)
  • __tests__/components/notifications/NotificationsContext.test.tsx
  • __tests__/services/common-api.test.ts
  • components/notifications/NotificationsContext.tsx
  • services/api/common-api.ts

Comment thread services/api/common-api.ts
Signed-off-by: Simo <simo@6529.io>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Mar 4, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
3.8% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
__tests__/services/common-api.test.ts (1)

119-169: Comprehensive test for structured error mode.

Good coverage of the structured error contract: verifies message, status, headers, response.status, response.headers, and response.body are all correctly populated. The retry-after header assertion validates the header preservation needed for retry logic.

Consider renaming the catch parameter per project conventions.

,

♻️ Optional: Rename catch parameter to follow naming convention
     } catch (caught) {
-      error = caught as {
+      error = caught as unknown as {

Or if the convention is error_:

-    } catch (caught) {
-      error = caught as {
+    } catch (error_) {
+      error = error_ as {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__tests__/services/common-api.test.ts` around lines 119 - 169, Rename the
catch parameter in the test from "caught" to the project's preferred convention
(e.g., "error_" or "err") to match naming standards; update the try/catch block
in the test case that calls commonApiPost (the variable currently declared as
let error = null and the catch parameter named caught) so the caught exception
is assigned using the new parameter name and all references to the caught
variable within the catch block are updated accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@__tests__/services/common-api.test.ts`:
- Around line 119-169: Rename the catch parameter in the test from "caught" to
the project's preferred convention (e.g., "error_" or "err") to match naming
standards; update the try/catch block in the test case that calls commonApiPost
(the variable currently declared as let error = null and the catch parameter
named caught) so the caught exception is assigned using the new parameter name
and all references to the caught variable within the catch block are updated
accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f4358307-aa16-41cc-b205-777c3b49e400

📥 Commits

Reviewing files that changed from the base of the PR and between 8a44339 and 5443dfb.

📒 Files selected for processing (3)
  • __tests__/services/common-api.test.ts
  • components/notifications/NotificationsContext.tsx
  • services/api/common-api.ts

@simo6529 simo6529 merged commit afdc4c0 into main Mar 4, 2026
6 of 7 checks passed
@simo6529 simo6529 deleted the server-action-error-fix branch March 4, 2026 20:22
@coderabbitai coderabbitai Bot mentioned this pull request Mar 5, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants