Skip to content

Add App Router error boundaries, Sentry monitoring, and PII scrubbing… - #118

Open
Victorjonah-prog wants to merge 8 commits into
Deen-Bridge:mainfrom
Victorjonah-prog:fix/issue-109-error-monitoring
Open

Add App Router error boundaries, Sentry monitoring, and PII scrubbing…#118
Victorjonah-prog wants to merge 8 commits into
Deen-Bridge:mainfrom
Victorjonah-prog:fix/issue-109-error-monitoring

Conversation

@Victorjonah-prog

@Victorjonah-prog Victorjonah-prog commented Jul 22, 2026

Copy link
Copy Markdown

… (closes #109)

Summary by CodeRabbit

  • New Features
    • Added Sentry-backed error recovery screens (retry/reload/home) with visible report IDs.
    • Added PWA support: manifest/icons, quick “Install” prompt, offline page, and Serwist-powered service worker caching.
  • Monitoring & Privacy
    • Enabled Sentry across browser, server, and edge, including privacy-safe event scrubbing and improved CI behavior for reporting.
  • Bug Fixes
    • Reduced noisy auth/token console logging and improved logout cache cleanup.
  • Chores / Docs
    • Updated environment/CI Sentry configuration, added README screenshots, removed the debug-only auth logs component, and added required SDK dependencies.

@vercel

vercel Bot commented Jul 22, 2026

Copy link
Copy Markdown

@Victorjonah-prog is attempting to deploy a commit to the Deen Bridge Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ffe7f3bf-25a1-4e80-b16e-517ea1f0d1fc

📥 Commits

Reviewing files that changed from the base of the PR and between ec2af96 and fb23912.

📒 Files selected for processing (2)
  • hooks/useStellarDonation.js
  • sentry.shared.config.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • hooks/useStellarDonation.js
  • sentry.shared.config.js

Walkthrough

Sentry is integrated across browser, server, edge, CI, and Next.js builds. Error boundaries expose recovery actions and report IDs, sensitive event data is scrubbed, Stellar failures are captured, and PWA installation and offline caching support are added.

Changes

Application observability and recovery

Layer / File(s) Summary
Shared event privacy processing
sentry.shared.config.js
Adds event and transaction hooks that redact credentials, cookies, user details, and email addresses while filtering configured noisy errors.
Runtime and build integration
package.json, .env.example, .github/workflows/ci.yml, instrumentation*.js, sentry.*.config.js, next.config.mjs
Adds Sentry dependencies, runtime initialization, request-error handling, environment configuration, CI variables, and conditional source-map settings.
Error boundaries and terminal failure capture
app/.../error.jsx, app/global-error.jsx, hooks/useStellar*.js
Adds contextual and global recovery UIs with report IDs, retry or reload actions, and capture for Stellar payment and donation failures.
Sensitive logging cleanup
hooks/useAuth.js, lib/config/*.js
Removes authentication debug output and limits API startup logging to development.

Progressive web app support

Layer / File(s) Summary
Manifest metadata and install prompt
app/layout.js, app/manifest.js, app/account/settings/page.jsx
Adds PWA metadata and icons, and provides an install prompt with Install and Dismiss actions.
Offline route and service-worker behavior
app/offline/page.jsx, app/sw.js, public/sw.js, public/swe-worker-*.js
Adds offline navigation UI and Serwist precaching, runtime caching, cache expiration, lifecycle handling, and offline fallback behavior.

Estimated code review effort: 4 (Complex) | ~55 minutes

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR adds unrelated PWA/service-worker/offline/install-prompt changes that are not part of issue #109. Split the PWA/service-worker/manifest/offline UI changes into a separate PR so this one stays focused on Sentry and error-boundary work.
Docstring Coverage ⚠️ Warning Docstring coverage is 6.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: App Router error boundaries, Sentry monitoring, and PII scrubbing.
Linked Issues check ✅ Passed The PR appears to satisfy the issue's main requirements: App Router boundaries, Sentry setup, scrubbing, capture coverage, and CI source-map handling are all present.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@sentry.shared.config.js`:
- Around line 63-96: Replace the shallow value handling in scrubBreadcrumbs and
scrubExtra with the shared recursive redactor, preserving cookie-key removal and
string scrubbing at every nested level. Apply these same scrubbers to
breadcrumbs and extra data in sentryBeforeSendTransaction, matching the existing
sentryBeforeSend behavior for error events.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6fbe95d1-aaa6-4f6d-8062-97d07c080543

📥 Commits

Reviewing files that changed from the base of the PR and between c76e032 and 81386ae.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (20)
  • .env.example
  • .github/workflows/ci.yml
  • app/dashboard/courses/error.jsx
  • app/dashboard/error.jsx
  • app/dashboard/library/error.jsx
  • app/error.jsx
  • app/global-error.jsx
  • components/DebugAuthLogs.jsx
  • hooks/useAuth.js
  • hooks/useStellarDonation.js
  • hooks/useStellarPayment.js
  • instrumentation-client.js
  • instrumentation.js
  • lib/config/axios.config.js
  • lib/config/req.header.config.js
  • next.config.mjs
  • package.json
  • sentry.edge.config.js
  • sentry.server.config.js
  • sentry.shared.config.js
💤 Files with no reviewable changes (3)
  • components/DebugAuthLogs.jsx
  • lib/config/req.header.config.js
  • hooks/useAuth.js

Comment thread sentry.shared.config.js
Comment on lines +63 to +96
function scrubBreadcrumbs(breadcrumbs) {
if (!Array.isArray(breadcrumbs)) return breadcrumbs;
return breadcrumbs.map((crumb) => {
const cleaned = { ...crumb };
if (cleaned.data) {
const data = { ...cleaned.data };
delete data.cookies;
delete data.Cookie;
delete data.cookie;
if (data.headers) data.headers = scrubHeaders(data.headers);
if (data.url) data.url = scrubUrl(data.url);
if (typeof data.message === "string") data.message = scrubString(data.message);
cleaned.data = data;
}
if (typeof cleaned.message === "string") {
cleaned.message = scrubString(cleaned.message);
}
return cleaned;
});
}

function scrubExtra(extra) {
if (!extra || typeof extra !== "object") return extra;
const cleaned = { ...extra };
for (const key of SENSITIVE_COOKIE_KEYS) {
delete cleaned[key];
}
delete cleaned.cookies;
delete cleaned.Cookie;
delete cleaned.cookie;
for (const [key, value] of Object.entries(cleaned)) {
if (typeof value === "string") cleaned[key] = scrubString(value);
}
return cleaned;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the file and inspect the relevant region.
wc -l sentry.shared.config.js
cat -n sentry.shared.config.js | sed -n '1,220p'

Repository: Deen-Bridge/dnb-frontend

Length of output: 5758


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Focus on the relevant symbols and call sites.
rg -n "scrubBreadcrumbs|scrubExtra|sentryBeforeSendTransaction|scrubHeaders|scrubUrl|scrubString|sendDefaultPii|breadcrumbs|extra|contexts" sentry.shared.config.js

Repository: Deen-Bridge/dnb-frontend

Length of output: 1405


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the file around the reported lines, plus surrounding hook definitions.
sed -n '1,220p' sentry.shared.config.js

Repository: Deen-Bridge/dnb-frontend

Length of output: 4694


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the file outline first to locate the scrubber and hook definitions.
ast-grep outline sentry.shared.config.js --view expanded

Repository: Deen-Bridge/dnb-frontend

Length of output: 744


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find where these hooks are wired up and whether transaction events are routed through them.
rg -n "sentryBeforeSend(Transaction)?|beforeSendTransaction|beforeSend:|sendDefaultPii|Sentry\.init|integrations" .

Repository: Deen-Bridge/dnb-frontend

Length of output: 1469


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect any Sentry config files that import this module.
fd -a "sentry.*config.js|sentry.*config.ts|sentry.*config.mjs|sentry.*config.cjs" .

Repository: Deen-Bridge/dnb-frontend

Length of output: 289


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find where these hooks are wired up and whether transaction events are routed through them.
rg -n "sentryBeforeSend(Transaction)?|beforeSendTransaction|beforeSend:|sendDefaultPii|Sentry\\.init|integrations" .

Repository: Deen-Bridge/dnb-frontend

Length of output: 1469


🌐 Web query:

Sentry JavaScript beforeSendTransaction breadcrumbs extra transaction event payload documentation

💡 Result:

In the Sentry JavaScript SDK, the beforeSendTransaction hook is a user-facing callback that allows you to modify or discard a transaction event before it is sent to Sentry [1]. Regarding the structure of transaction events and breadcrumbs: Transaction Event Payload Transactions are events enriched with span data [2]. When modifying a transaction within beforeSendTransaction, the event object typically includes properties such as transaction, contexts.trace, and spans. Because transactions represent a span tree (where the root node is the transaction itself), they must contain specific tracing information, such as the contexts.trace object [2]. Breadcrumbs within Transactions Transaction events can contain a breadcrumbs property [3]. This property is an array of breadcrumb objects or an object containing a values array [3]. Each breadcrumb object supports the following keys: type, category, message, level, timestamp, and data [4][3][5]. The data key is specifically intended for any additional, structured information you wish to include with the breadcrumb [4][3]. Modification in beforeSendTransaction You can access and modify the breadcrumbs array directly within the beforeSendTransaction hook to scrub sensitive data or add extra information [6]. Example Usage Sentry.init({ beforeSendTransaction(event) { // Example: Accessing and modifying breadcrumbs if (event.breadcrumbs) { event.breadcrumbs.forEach(breadcrumb => { // Modify or scrub data in the breadcrumb if (breadcrumb.data && breadcrumb.data.sensitiveInfo) { delete breadcrumb.data.sensitiveInfo; } }); } return event; // Return the modified event }, }); Important Notes 1. Guaranteed Last Execution: beforeSendTransaction is guaranteed to run last, after all other event processors have completed, ensuring you have the final version of the event [7]. 2. Dedicated Hook: You should not use beforeSend for transaction events; beforeSend is exclusively for error events [1]. 3. Breadcrumb Customization: If you need to filter or modify individual breadcrumbs as they are created (rather than when the transaction event is sent), consider using the beforeBreadcrumb hook instead [4][5].

Citations:


🌐 Web query:

Sentry transaction event payload extra property javascript beforeSendTransaction extra

💡 Result:

In Sentry's JavaScript SDK, you can interact with the extra property of a transaction event payload within the beforeSendTransaction hook by directly mutating the event object passed to it [1][2][3]. The beforeSendTransaction hook is a configuration option available in transaction mode that is guaranteed to run last, after all other event processors [4][5][1]. It receives the transaction event object as its first argument, which includes an extra property (if present) that holds an arbitrary mapping of additional metadata [6][7][1]. Example usage: Sentry.init({ dsn: "https://@o.ingest.sentry.io/", beforeSendTransaction(event) { // Access and mutate the extra property event.extra = {...event.extra, customKey: "customValue" }; // You can also delete or modify existing entries delete event.extra.sensitiveData; return event; }, }); Key points to consider: 1. Data Availability: The extra field is a standard part of the Sentry event payload schema [6][8]. If you intend to add data, ensure the object structure aligns with the expected format [6]. 2. Alternative Approaches: While beforeSendTransaction is useful for final modifications or scrubbing [9][3], you can also use addEventProcessor or scope.setExtra to enrich events with additional data throughout the transaction's lifecycle [4][5]. 3. UI Considerations: Note that depending on the Sentry version and configuration, how extra data is rendered in the Sentry UI can vary, and in some contexts, attaching data to individual spans may be preferred over attaching it to the top-level transaction [10]. 4. Stream Mode: If your SDK is configured in "stream mode" rather than "transaction mode," beforeSendTransaction will not be invoked [9][1]. In that case, you should use beforeSendSpan to manage data on spans instead [9].

Citations:


🌐 Web query:

Sentry transaction event payload extra breadcrumbs fields documentation

💡 Result:

In Sentry event payloads, breadcrumbs are structured as part of the Breadcrumbs Interface [1][2]. While the overall event payload may contain an extra field for arbitrary metadata [1], the breadcrumb objects themselves utilize a specific data field to store arbitrary associated information [3][4]. Breadcrumb Object Structure Each breadcrumb object within the breadcrumbs array typically contains the following fields [3][5]: - type: An optional string defining the breadcrumb type (e.g., default, navigation, http, info, ui) [3][6][7]. - category: An optional string describing the category of the event (e.g., sentry.transaction, console, ui.click) [3][6][7]. - message: An optional string message describing the event [3][5]. - level: An optional string indicating the severity level (e.g., info, error, debug) [3][7]. - timestamp: An optional timestamp indicating when the breadcrumb occurred (RFC 3339 or Unix timestamp) [3][7]. - data: An optional dictionary/object for arbitrary metadata [3][4][5]. The contents of this field depend on the breadcrumb type [3][7]. Important Considerations - Additional Fields: While you can include other keys in a breadcrumb object, Sentry will drop any fields that are not recognized or supported by the breadcrumbs interface during processing [4]. - Data Field Usage: The data field is the designated location for adding custom, structured information to a breadcrumb [4]. For certain types, such as http or navigation, specific keys within data (e.g., url, method, from, to) are expected [6][7]. - Transaction Events: Transactions can also contain breadcrumbs. Internally, breadcrumbs of type default with categories like sentry.transaction or sentry.event are displayed as transaction type breadcrumbs [3][6]. For developers needing to manipulate these fields, SDKs generally provide a before_breadcrumb hook, which allows you to inspect and modify breadcrumbs—including the data dictionary—before they are sent to Sentry [4].

Citations:


Scrub nested breadcrumb/extra values in both hooks
breadcrumbs.data and extra are only redacted one level deep here, so nested objects can still leak tokens or email addresses. sentryBeforeSendTransaction also skips breadcrumb/extra scrubbing entirely, so transaction events can bypass the same redaction path. Reuse a recursive redactor in both hooks to keep error and transaction payloads consistent.

🤖 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 `@sentry.shared.config.js` around lines 63 - 96, Replace the shallow value
handling in scrubBreadcrumbs and scrubExtra with the shared recursive redactor,
preserving cookie-key removal and string scrubbing at every nested level. Apply
these same scrubbers to breadcrumbs and extra data in
sentryBeforeSendTransaction, matching the existing sentryBeforeSend behavior for
error events.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
.npmrc (1)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid globally enabling legacy-peer-deps.

This makes npm ignore peer-dependency conflicts, potentially allowing an incompatible dependency tree and masking the real package-version issue. Prefer fixing dependency ranges or using this only in a narrowly documented, verified CI workaround.

🤖 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 @.npmrc at line 1, Remove the global legacy-peer-deps setting from .npmrc.
Resolve any resulting peer-dependency conflicts by correcting the affected
package version ranges; only retain a narrowly scoped, documented CI workaround
if dependency alignment cannot address the verified conflict.
🤖 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 `@app/account/settings/page.jsx`:
- Around line 62-70: Update handleInstall so installable is reset when the
native prompt is dismissed as well as when it is accepted. Preserve clearing
deferredPrompt after userChoice, ensuring the banner cannot remain visible while
the prompt reference is unavailable.

In `@app/layout.js`:
- Around line 21-22: Update the manifest value in the layout metadata to
reference the actual `/manifest.webmanifest` endpoint instead of `/manifest`,
while leaving the surrounding icons configuration unchanged.

In `@app/sw.js`:
- Around line 15-148: Prefix every explicit runtime cacheName in the
runtimeCaching configuration with “serwist-”, including google-fonts,
static-font-assets, next-static-assets, next-static-images,
next-optimized-images, book-previews, cloudinary-images, pages, and
same-origin-others. Keep the existing cache strategies and expiration settings
unchanged so logout cleanup can remove all runtime caches through its serwist-
prefix filter.
- Around line 116-130: Update the HTML navigation matcher in the service worker
to inspect the response Content-Type rather than the incoming request header,
while retaining the sameOrigin restriction. Ensure same-origin HTML responses
are routed to the existing NetworkFirst “pages” cache and non-HTML resources
continue to use the fallback rule.

---

Nitpick comments:
In @.npmrc:
- Line 1: Remove the global legacy-peer-deps setting from .npmrc. Resolve any
resulting peer-dependency conflicts by correcting the affected package version
ranges; only retain a narrowly scoped, documented CI workaround if dependency
alignment cannot address the verified conflict.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8282331d-b58e-4beb-9eb3-8fb4b2d97ca3

📥 Commits

Reviewing files that changed from the base of the PR and between 81386ae and ec2af96.

⛔ Files ignored due to path filters (11)
  • docs/screenshots/courses.png is excluded by !**/*.png
  • docs/screenshots/dashboard.png is excluded by !**/*.png
  • docs/screenshots/landing.png is excluded by !**/*.png
  • docs/screenshots/library.png is excluded by !**/*.png
  • docs/screenshots/login.png is excluded by !**/*.png
  • docs/screenshots/wallet.png is excluded by !**/*.png
  • package-lock.json is excluded by !**/package-lock.json
  • public/icons/icon-192x192-maskable.png is excluded by !**/*.png
  • public/icons/icon-192x192.png is excluded by !**/*.png
  • public/icons/icon-512x512-maskable.png is excluded by !**/*.png
  • public/icons/icon-512x512.png is excluded by !**/*.png
📒 Files selected for processing (12)
  • .npmrc
  • README.md
  • app/account/settings/page.jsx
  • app/layout.js
  • app/manifest.js
  • app/offline/page.jsx
  • app/sw.js
  • hooks/useAuth.js
  • next.config.mjs
  • package.json
  • public/sw.js
  • public/swe-worker-f61931bc2770d10b.js
🚧 Files skipped from review as they are similar to previous changes (3)
  • package.json
  • hooks/useAuth.js
  • next.config.mjs

Comment on lines +62 to +70
const handleInstall = async () => {
if (!deferredPrompt) return;
deferredPrompt.prompt();
const result = await deferredPrompt.userChoice;
if (result.outcome === "accepted") {
setInstallable(false);
}
setDeferredPrompt(null);
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Install banner keeps showing but silently stops working after a dismissed prompt.

installable is only reset when outcome === "accepted". If the user dismisses the native prompt, deferredPrompt is nulled but installable stays true, so a subsequent click on "Install" silently no-ops (the !deferredPrompt guard returns early). The banner should also hide (or re-arm) after a dismissal.

♻️ Proposed fix
   const handleInstall = async () => {
     if (!deferredPrompt) return;
     deferredPrompt.prompt();
     const result = await deferredPrompt.userChoice;
-    if (result.outcome === "accepted") {
-      setInstallable(false);
-    }
+    setInstallable(false);
     setDeferredPrompt(null);
   };
📝 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.

Suggested change
const handleInstall = async () => {
if (!deferredPrompt) return;
deferredPrompt.prompt();
const result = await deferredPrompt.userChoice;
if (result.outcome === "accepted") {
setInstallable(false);
}
setDeferredPrompt(null);
};
const handleInstall = async () => {
if (!deferredPrompt) return;
deferredPrompt.prompt();
const result = await deferredPrompt.userChoice;
setInstallable(false);
setDeferredPrompt(null);
};
🤖 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 `@app/account/settings/page.jsx` around lines 62 - 70, Update handleInstall so
installable is reset when the native prompt is dismissed as well as when it is
accepted. Preserve clearing deferredPrompt after userChoice, ensuring the banner
cannot remain visible while the prompt reference is unavailable.

Comment thread app/layout.js
Comment on lines +21 to +22
manifest: "/manifest",
icons: {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== files ==\n'
git ls-files 'app/layout.js' 'app/**/manifest.*' 'public/sw.js'

printf '\n== outline: app/layout.js ==\n'
ast-grep outline app/layout.js --view expanded || true

printf '\n== relevant layout lines ==\n'
sed -n '1,120p' app/layout.js

printf '\n== manifest files ==\n'
for f in $(git ls-files 'app/**/manifest.*'); do
  echo "--- $f ---"
  wc -l "$f"
  sed -n '1,220p' "$f"
done

printf '\n== sw.js manifest references ==\n'
rg -n 'manifest|webmanifest' public/sw.js app -g '!**/node_modules/**' || true

Repository: Deen-Bridge/dnb-frontend

Length of output: 33106


Fix the manifest URL
app/manifest.js is served as /manifest.webmanifest, so manifest: "/manifest" points at the wrong path and breaks the manifest link for installability.

🐛 Proposed fix
-  manifest: "/manifest",
+  manifest: "/manifest.webmanifest",
📝 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.

Suggested change
manifest: "/manifest",
icons: {
manifest: "/manifest.webmanifest",
icons: {
🤖 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 `@app/layout.js` around lines 21 - 22, Update the manifest value in the layout
metadata to reference the actual `/manifest.webmanifest` endpoint instead of
`/manifest`, while leaving the surrounding icons configuration unchanged.

Comment thread app/sw.js
Comment on lines +15 to +148
runtimeCaching: [
{
matcher: /^https:\/\/fonts\.(?:gstatic|googleapis)\.com\/.*/i,
handler: new CacheFirst({
cacheName: "google-fonts",
plugins: [
new ExpirationPlugin({
maxEntries: 8,
maxAgeSeconds: 365 * 24 * 60 * 60,
maxAgeFrom: "last-used",
}),
],
}),
},
{
matcher: /\.(?:eot|otf|ttc|ttf|woff|woff2|font\.css)$/i,
handler: new CacheFirst({
cacheName: "static-font-assets",
plugins: [
new ExpirationPlugin({
maxEntries: 8,
maxAgeSeconds: 30 * 24 * 60 * 60,
maxAgeFrom: "last-used",
}),
],
}),
},
{
matcher: /\/_next\/static\/.+\.(?:js|css|json)$/i,
handler: new CacheFirst({
cacheName: "next-static-assets",
plugins: [
new ExpirationPlugin({
maxEntries: 64,
maxAgeSeconds: 30 * 24 * 60 * 60,
maxAgeFrom: "last-used",
}),
],
}),
},
{
matcher: /\/_next\/static\/media\/.+\.(?:png|jpg|jpeg|gif|svg|ico|webp|avif)$/i,
handler: new CacheFirst({
cacheName: "next-static-images",
plugins: [
new ExpirationPlugin({
maxEntries: 64,
maxAgeSeconds: 30 * 24 * 60 * 60,
maxAgeFrom: "last-used",
}),
],
}),
},
{
matcher: /\/_next\/image\?url=.+$/i,
handler: new StaleWhileRevalidate({
cacheName: "next-optimized-images",
plugins: [
new ExpirationPlugin({
maxEntries: 64,
maxAgeSeconds: 30 * 24 * 60 * 60,
maxAgeFrom: "last-used",
}),
],
}),
},
{
matcher: /\/api\/books\/[^/]+\/preview/i,
handler: new StaleWhileRevalidate({
cacheName: "book-previews",
plugins: [
new ExpirationPlugin({
maxEntries: 10,
maxAgeSeconds: 7 * 24 * 60 * 60,
maxAgeFrom: "last-used",
}),
],
}),
},
{
matcher: /^https:\/\/res\.cloudinary\.com\/.*/i,
handler: new StaleWhileRevalidate({
cacheName: "cloudinary-images",
plugins: [
new ExpirationPlugin({
maxEntries: 48,
maxAgeSeconds: 7 * 24 * 60 * 60,
maxAgeFrom: "last-used",
}),
],
}),
},
{
matcher: ({ sameOrigin, url }) =>
sameOrigin && url.pathname.startsWith("/api/"),
handler: new NetworkOnly(),
},
{
matcher: ({ sameOrigin }) => !sameOrigin,
handler: new NetworkOnly(),
},
{
matcher: ({ request, url, sameOrigin }) =>
request.headers.get("Content-Type")?.includes("text/html") &&
sameOrigin,
handler: new NetworkFirst({
cacheName: "pages",
plugins: [
new ExpirationPlugin({
maxEntries: 32,
maxAgeSeconds: 24 * 60 * 60,
maxAgeFrom: "last-used",
}),
],
}),
},
{
matcher: ({ sameOrigin, url }) => sameOrigin,
handler: new NetworkFirst({
cacheName: "same-origin-others",
plugins: [
new ExpirationPlugin({
maxEntries: 32,
maxAgeSeconds: 24 * 60 * 60,
maxAgeFrom: "last-used",
}),
],
}),
},
{
matcher: /.*/i,
handler: new NetworkOnly(),
},
],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Runtime cache names aren't prefixed with serwist-, breaking the logout cleanup in hooks/useAuth.js.

Serwist's getRuntimeName returns the supplied cacheName verbatim whenever one is provided (confirmed in the compiled public/sw.js), so none of these caches ("google-fonts", "static-font-assets", "next-static-assets", "next-static-images", "next-optimized-images", "cloudinary-images", "pages", "same-origin-others") get a serwist- prefix — only the internal precache cache does.

Per the provided snippet, hooks/useAuth.js's logout handler only deletes caches matching name.startsWith("serwist-") || name === "book-previews". That means every runtime cache defined here except book-previews survives logout, including pages and same-origin-others, which can hold previously-authenticated HTML responses — a real risk on shared/public devices.

Fix at the root: either prefix these cache names consistently (e.g. serwist-pages, serwist-same-origin-others, ...) or update the logout filter in hooks/useAuth.js to enumerate/match all cache names actually used here.

🤖 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 `@app/sw.js` around lines 15 - 148, Prefix every explicit runtime cacheName in
the runtimeCaching configuration with “serwist-”, including google-fonts,
static-font-assets, next-static-assets, next-static-images,
next-optimized-images, book-previews, cloudinary-images, pages, and
same-origin-others. Keep the existing cache strategies and expiration settings
unchanged so logout cleanup can remove all runtime caches through its serwist-
prefix filter.

Comment thread app/sw.js
Comment on lines +116 to +130
{
matcher: ({ request, url, sameOrigin }) =>
request.headers.get("Content-Type")?.includes("text/html") &&
sameOrigin,
handler: new NetworkFirst({
cacheName: "pages",
plugins: [
new ExpirationPlugin({
maxEntries: 32,
maxAgeSeconds: 24 * 60 * 60,
maxAgeFrom: "last-used",
}),
],
}),
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

HTML-page matcher checks the wrong header — navigations never carry Content-Type.

request.headers.get("Content-Type") is checked on the incoming request, but GET/navigation requests don't send a Content-Type request header (that describes a request body, which GETs don't have). This condition is effectively always falsy, so the "pages" cache bucket is dead code and all same-origin HTML falls through to the "same-origin-others" rule below, diluting its 32-entry limit with mixed resource types.

♻️ Proposed fix
     {
-      matcher: ({ request, url, sameOrigin }) =>
-        request.headers.get("Content-Type")?.includes("text/html") &&
-        sameOrigin,
+      matcher: ({ request, sameOrigin }) =>
+        sameOrigin && request.destination === "document",
       handler: new NetworkFirst({
         cacheName: "pages",
📝 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.

Suggested change
{
matcher: ({ request, url, sameOrigin }) =>
request.headers.get("Content-Type")?.includes("text/html") &&
sameOrigin,
handler: new NetworkFirst({
cacheName: "pages",
plugins: [
new ExpirationPlugin({
maxEntries: 32,
maxAgeSeconds: 24 * 60 * 60,
maxAgeFrom: "last-used",
}),
],
}),
},
{
matcher: ({ request, sameOrigin }) =>
sameOrigin && request.destination === "document",
handler: new NetworkFirst({
cacheName: "pages",
plugins: [
new ExpirationPlugin({
maxEntries: 32,
maxAgeSeconds: 24 * 60 * 60,
maxAgeFrom: "last-used",
}),
],
}),
},
🤖 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 `@app/sw.js` around lines 116 - 130, Update the HTML navigation matcher in the
service worker to inspect the response Content-Type rather than the incoming
request header, while retaining the sameOrigin restriction. Ensure same-origin
HTML responses are routed to the existing NetworkFirst “pages” cache and
non-HTML resources continue to use the fallback rule.

@zeemscript

Copy link
Copy Markdown
Collaborator

Strict review blocker: this branch conflicts with the base branch, Vercel is failing, and changes have been requested. Please resolve these before requesting merge.

@zeemscript

Copy link
Copy Markdown
Collaborator

Strict review blocker: this branch has merge conflicts with the base branch and/or failing deployment checks. Please rebase, resolve conflicts, and restore checks before requesting merge.

@zeemscript

Copy link
Copy Markdown
Collaborator

Strict review blocker: this branch conflicts with the base branch, is failing, and changes have been requested. Please resolve these before requesting merge.

@zeemscript

Copy link
Copy Markdown
Collaborator

@Victorjonah-prog this PR has merge conflicts with the main branch. Please resolve the conflicts (merge main in or rebase) and push the fix so it can be merged. Thanks!

@zeemscript

Copy link
Copy Markdown
Collaborator

@Taiye21 you are assigned to the issue that PR #118 addresses, which currently has merge conflicts with the main branch. Please resolve the conflicts (merge main in or rebase) and push the fix so it can be merged. Thanks!

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.

[Enhancement] Production error monitoring: App Router error boundaries and Sentry with source maps and PII scrubbing

3 participants