feat(examples): add Next.js deletion webhook quickstart #21 - #51
feat(examples): add Next.js deletion webhook quickstart #21#51Adityakk9031 wants to merge 1 commit into
Conversation
|
This run croaked 😵 The workflow encountered an error before any progress could be reported. Please check the link below for details. |
|
Warning Review limit reached
Next review available in: 46 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (8)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe SDK adds configurable webhook receiver creation and middleware aliases for Express, Hono, and Next.js. A Next.js example adds signed DSAR event handling, demo-user deletion, project setup, documentation, and a smoke test. ChangesWebhook receiver and Next.js example
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant SmokeTest
participant NextDSARRoute
participant WebhookReceiver
participant DemoDatabase
SmokeTest->>NextDSARRoute: POST signed DSAR payload
NextDSARRoute->>WebhookReceiver: verify and dispatch event
WebhookReceiver->>NextDSARRoute: return event data
NextDSARRoute->>DemoDatabase: delete user by email
NextDSARRoute-->>SmokeTest: return acknowledgement
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ 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: 10
🤖 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 `@examples/nextjs-deletion-webhook/app/api/webhooks/dsar/route.ts`:
- Around line 5-6: Remove the shared fallback signing secret: in route.ts, make
DSAR_WEBHOOK_SECRET required and fail configuration when absent; in
.env.example, replace the known value with an empty generated-secret
placeholder; in scripts/smoke.ts, require the test environment secret without a
fallback.
- Around line 21-24: Update both event-handler logs in
examples/nextjs-deletion-webhook/app/api/webhooks/dsar/route.ts at lines 21-24
and 33-36 to remove the subject email, while retaining the event identifier and
deletion outcome in each message.
In `@examples/nextjs-deletion-webhook/lib/db.ts`:
- Around line 74-81: Update deleteByEmail in
examples/nextjs-deletion-webhook/lib/db.ts:74-81 to accept eventId, requestId,
and required lifecycle metadata, persist an audit record containing the event
identity, deletion outcome, and legal timestamp before acknowledging the
deletion, while preserving the boolean result. Update the DSAR webhook handler
in examples/nextjs-deletion-webhook/app/api/webhooks/dsar/route.ts:15-36 to pass
those values into deleteByEmail.
- Around line 26-48: Update the storage methods load() and save() to propagate
typed storage failures instead of silently resetting users or ignoring write
errors. Ensure the deletion webhook’s lifecycle mutation only acknowledges
success after save() completes durably, and returns the typed failure when load
or save fails while preserving existing legal clock behavior.
- Around line 26-45: Align the persistence implementation and environment
documentation: either replace the JSON logic in the database class methods load
and save with SQLite persistence, or explicitly retain JSON storage. If
retaining JSON, update examples/nextjs-deletion-webhook/.env.example lines 4-5
to use a JSON filename and describe it as a JSON database file; if implementing
SQLite, update the persistence methods and keep the existing SQLite
configuration documentation.
In `@examples/nextjs-deletion-webhook/README.md`:
- Around line 5-8: Update the README quickstart formatting around each step
heading and fenced code block: add the required blank lines before and after
every heading and fence, including the additional locations referenced in the
review, while preserving the existing commands and content.
- Around line 21-33: The request_captured handler in the documented
nextWebhookMiddleware example must validate event.payload.email before deletion
instead of casting it to string. Add a focused guard or Effect Schema decode for
the adapter payload, reject invalid or missing email values, and call
deleteDemoUserByEmail only with the validated string.
In `@examples/nextjs-deletion-webhook/scripts/smoke.ts`:
- Around line 71-74: Update the acknowledgement handling around response.json()
to treat the decoded payload as unknown and validate it with a focused guard
that accepts only an object whose ok property is exactly true. Remove the { ok:
boolean } cast, and retain the existing error behavior for all invalid response
shapes.
In `@packages/node-sdk/test/client.test.ts`:
- Around line 319-328: Expand the test for sdk.webhooks.receiver() to exercise
its public behavior: configure a verifier and request_captured handler, invoke
receiver.handle() with a signed payload, and assert the handler’s observable
effect plus the resulting { ok: true } acknowledgment. Replace the current
method-presence-only assertions while keeping the setup through the public SDK
API.
In `@packages/node-sdk/test/webhooks/next.test.ts`:
- Around line 75-89: Update the middleware response assertions in the test
around middleware so both res1 and res2 validate their parsed JSON bodies equal
{ ok: true }, in addition to the existing 200 status checks and handler
assertions.
🪄 Autofix
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: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b24c361d-154e-4242-adea-d8c3e320207f
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (18)
examples/nextjs-deletion-webhook/.env.exampleexamples/nextjs-deletion-webhook/.gitignoreexamples/nextjs-deletion-webhook/README.mdexamples/nextjs-deletion-webhook/app/api/webhooks/dsar/route.tsexamples/nextjs-deletion-webhook/lib/db.tsexamples/nextjs-deletion-webhook/package.jsonexamples/nextjs-deletion-webhook/scripts/smoke.tsexamples/nextjs-deletion-webhook/tsconfig.jsonpackage.jsonpackages/node-sdk/src/endpoints/webhooks.tspackages/node-sdk/src/webhooks/express.tspackages/node-sdk/src/webhooks/hono.tspackages/node-sdk/src/webhooks/next.tspackages/node-sdk/src/webhooks/receiver.tspackages/node-sdk/test/client.test.tspackages/node-sdk/test/webhooks/express.test.tspackages/node-sdk/test/webhooks/hono.test.tspackages/node-sdk/test/webhooks/next.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: pullfrog
🧰 Additional context used
📓 Path-based instructions (5)
**/package.json
📄 CodeRabbit inference engine (AGENTS.md)
**/package.json: Use Bun only, keepbun.lockcanonical, and do not create npm, pnpm, or Yarn lock files.
Prefer root catalogs for versions shared across workspaces and keep peer ranges compatible with the exact development dependency used by an adapter.
Add a Changeset for user-visible package behavior, public API, runtime requirement, or dependency compatibility changes; keep unrelated package changes out of the same Changeset.
Files:
package.jsonexamples/nextjs-deletion-webhook/package.json
**/*
📄 CodeRabbit inference engine (AGENTS.md)
**/*: Preserve unrelated worktree changes; do not reset, rewrite, or delete work not created for the task.
Do not amend, force-push, publish, or open a pull request unless explicitly asked by the user.
Before committing, inspectgit diff --check, the staged file list, and generated or lockfile changes.
Files:
package.jsonpackages/node-sdk/test/client.test.tsexamples/nextjs-deletion-webhook/tsconfig.jsonexamples/nextjs-deletion-webhook/package.jsonexamples/nextjs-deletion-webhook/README.mdpackages/node-sdk/src/webhooks/hono.tsexamples/nextjs-deletion-webhook/app/api/webhooks/dsar/route.tspackages/node-sdk/test/webhooks/hono.test.tspackages/node-sdk/src/webhooks/express.tsexamples/nextjs-deletion-webhook/scripts/smoke.tspackages/node-sdk/test/webhooks/express.test.tspackages/node-sdk/src/endpoints/webhooks.tspackages/node-sdk/src/webhooks/receiver.tsexamples/nextjs-deletion-webhook/lib/db.tspackages/node-sdk/test/webhooks/next.test.tspackages/node-sdk/src/webhooks/next.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use Bun-managed, ESM-only TypeScript; compile product code with TypeScript 7, not the@typescript/typescript6alias.
Use Effect 4 and keepeffect,@effect/platform-*,@effect/sql-*, and@effect/viteston one matching release line.
Decodeunknownat system boundaries with Effect Schema or a focused guard; do not cast request bodies, persisted JSON, or adapter payloads into domain types.
Every persistence operation that reads or writes tenant data must requireTenantContextand run throughwithTenant.
Tenant identifiers must come from verified runtime context, not request payloads or untrusted adapter metadata.
Keep policy evaluation deterministic; represent new inputs in the explainability trace and cover them with golden or matrix tests.
Lifecycle mutations must preserve auditability, typed failures, and legal clock behavior.
Adapter failures must not silently corrupt request state or bypass lifecycle rules.
Public exports must use explicit package entrypoints; avoid new convenience barrel files while preserving intentional entrypoints anddsarumbrella exports.
Public failures must use established typed error classes, catalog codes, and response envelopes.
Keep runtime behavior, schemas, SDK types, CLI commands, OpenAPI, and documentation synchronized.
Import focused Effect modules such aseffect/Effectandeffect/Schema; rooteffectimports are lint-restricted except for type-only imports.
Define services withContext.Serviceand provide implementations through Layers; keep requirements visible in the Effect environment.
PreferEffect.gen,Effect.fn, and typed combinators over nested promises; useEffect.runPromiseonly at runtime, adapter, or test boundaries.
Model expected failures in the error channel with descriptive tagged error types; do not use defects for routine validation or integration failures.
Files:
packages/node-sdk/test/client.test.tspackages/node-sdk/src/webhooks/hono.tsexamples/nextjs-deletion-webhook/app/api/webhooks/dsar/route.tspackages/node-sdk/test/webhooks/hono.test.tspackages/node-sdk/src/webhooks/express.tsexamples/nextjs-deletion-webhook/scripts/smoke.tspackages/node-sdk/test/webhooks/express.test.tspackages/node-sdk/src/endpoints/webhooks.tspackages/node-sdk/src/webhooks/receiver.tsexamples/nextjs-deletion-webhook/lib/db.tspackages/node-sdk/test/webhooks/next.test.tspackages/node-sdk/src/webhooks/next.ts
**/*.{test.ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use
@effect/vitestfor Effectful tests and provide Layers explicitly; preferit.effect, sharedlayer(...)setup, andTestClockover manual runtimes or real-time sleeps.
Files:
packages/node-sdk/test/client.test.tspackages/node-sdk/test/webhooks/hono.test.tspackages/node-sdk/test/webhooks/express.test.tspackages/node-sdk/test/webhooks/next.test.ts
**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{test,spec}.{ts,tsx}: For defects, add a regression test at the highest stable boundary that could reasonably have caught the defect before implementing the fix.
For user-visible behavior, prefer acceptance paths through a public API, CLI, SDK, or adapter contract; assert responses and durable side effects rather than internal calls.
Prefer real repository-owned implementations; replace external providers or deliberately controlled effects such as time and randomness, but do not mock internal layers merely to simplify tests.
Call a test E2E only when it crosses real process, transport, runtime, and storage boundaries; injected fetch, in-memory repositories, and direct calls are integration or component tests.
Never commit.only,.skip, debug logging, or unexplained snapshot rewrites.
Files:
packages/node-sdk/test/client.test.tspackages/node-sdk/test/webhooks/hono.test.tspackages/node-sdk/test/webhooks/express.test.tspackages/node-sdk/test/webhooks/next.test.ts
🪛 ast-grep (0.45.0)
examples/nextjs-deletion-webhook/app/api/webhooks/dsar/route.ts
[warning] 21-23: Avoid logging sensitive data
Context: console.log(
[DSAR Webhook] Processed request_captured for ${email} (deleted: ${deleted})
)
Note: [CWE-532] Insertion of Sensitive Information into Log File.
(log-sensitive-data-typescript)
[warning] 33-35: Avoid logging sensitive data
Context: console.log(
[DSAR Webhook] Processed request_fulfilled for ${email} (deleted: ${deleted})
)
Note: [CWE-532] Insertion of Sensitive Information into Log File.
(log-sensitive-data-typescript)
examples/nextjs-deletion-webhook/scripts/smoke.ts
[warning] 38-38: Avoid logging sensitive data
Context: console.log(--> Found active user ${initialUser.id} (${initialUser.email}))
Note: [CWE-532] Insertion of Sensitive Information into Log File.
(log-sensitive-data-typescript)
examples/nextjs-deletion-webhook/lib/db.ts
[warning] 28-28: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFileSync(this.filePath, "utf8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
(detect-non-literal-fs-filename-typescript)
[warning] 40-44: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.writeFileSync(
this.filePath,
JSON.stringify(list, null, 2),
"utf8"
)
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
(detect-non-literal-fs-filename-typescript)
🪛 dotenv-linter (4.0.0)
examples/nextjs-deletion-webhook/.env.example
[warning] 2-2: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
[warning] 5-5: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
🪛 markdownlint-cli2 (0.23.2)
examples/nextjs-deletion-webhook/README.md
[warning] 7-7: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 8-8: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 12-12: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 14-14: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 18-18: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 35-35: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 36-36: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 40-40: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 42-42: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
🔇 Additional comments (11)
packages/node-sdk/src/webhooks/receiver.ts (1)
14-17: LGTM!Also applies to: 279-305, 334-344
packages/node-sdk/src/endpoints/webhooks.ts (1)
5-6: LGTM!Also applies to: 154-159, 223-223
packages/node-sdk/src/webhooks/express.ts (1)
3-4: LGTM!Also applies to: 31-52
packages/node-sdk/src/webhooks/next.ts (1)
3-4: LGTM!Also applies to: 14-32
examples/nextjs-deletion-webhook/.gitignore (1)
1-6: LGTM!package.json (1)
85-86: LGTM!packages/node-sdk/test/webhooks/express.test.ts (1)
4-4: LGTM!Also applies to: 93-154
packages/node-sdk/src/webhooks/hono.ts (1)
3-27: LGTM!packages/node-sdk/test/webhooks/hono.test.ts (1)
4-16: LGTM!Also applies to: 43-81
examples/nextjs-deletion-webhook/package.json (1)
1-27: LGTM!examples/nextjs-deletion-webhook/tsconfig.json (1)
1-19: LGTM!
| const signingSecret = | ||
| process.env.DSAR_WEBHOOK_SECRET ?? "whsec_demo_secret_key_12345"; |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Remove the shared known signing secret.
The route, sample environment file, and smoke test use the same public value. A deployment without explicit configuration accepts forged deletion webhooks.
examples/nextjs-deletion-webhook/app/api/webhooks/dsar/route.ts#L5-L6: fail configuration whenDSAR_WEBHOOK_SECRETis absent.examples/nextjs-deletion-webhook/.env.example#L1-L2: use an empty generated-secret placeholder.examples/nextjs-deletion-webhook/scripts/smoke.ts#L4-L5: require the test environment secret instead of using a fallback.
📍 Affects 3 files
examples/nextjs-deletion-webhook/app/api/webhooks/dsar/route.ts#L5-L6(this comment)examples/nextjs-deletion-webhook/.env.example#L1-L2examples/nextjs-deletion-webhook/scripts/smoke.ts#L4-L5
🤖 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 `@examples/nextjs-deletion-webhook/app/api/webhooks/dsar/route.ts` around lines
5 - 6, Remove the shared fallback signing secret: in route.ts, make
DSAR_WEBHOOK_SECRET required and fail configuration when absent; in
.env.example, replace the known value with an empty generated-secret
placeholder; in scripts/smoke.ts, require the test environment secret without a
fallback.
| private load(): void { | ||
| if (fs.existsSync(this.filePath)) { | ||
| try { | ||
| const data = fs.readFileSync(this.filePath, "utf8"); | ||
| const list: readonly DemoUser[] = JSON.parse(data); | ||
| this.users = new Map(list.map((user) => [user.email, user])); | ||
| } catch { | ||
| this.users = new Map(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private save(): void { | ||
| try { | ||
| const list = Array.from(this.users.values()); | ||
| fs.writeFileSync( | ||
| this.filePath, | ||
| JSON.stringify(list, null, 2), | ||
| "utf8" | ||
| ); | ||
| } catch { | ||
| // Ignore filesystem write errors in read-only serverless environments | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Do not hide storage failures.
load() converts a read or parse failure into an empty store. save() ignores write failures. A webhook can then acknowledge a deletion that exists only in memory.
Return a typed storage failure. Do not acknowledge the deletion until durable persistence succeeds. As per coding guidelines, “Lifecycle mutations must preserve auditability, typed failures, and legal clock behavior.”
🧰 Tools
🪛 ast-grep (0.45.0)
[warning] 28-28: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFileSync(this.filePath, "utf8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
(detect-non-literal-fs-filename-typescript)
[warning] 40-44: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.writeFileSync(
this.filePath,
JSON.stringify(list, null, 2),
"utf8"
)
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
(detect-non-literal-fs-filename-typescript)
🤖 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 `@examples/nextjs-deletion-webhook/lib/db.ts` around lines 26 - 48, Update the
storage methods load() and save() to propagate typed storage failures instead of
silently resetting users or ignoring write errors. Ensure the deletion webhook’s
lifecycle mutation only acknowledges success after save() completes durably, and
returns the typed failure when load or save fails while preserving existing
legal clock behavior.
Source: Coding guidelines
| /** Deletes a demo user record by email. */ | ||
| deleteByEmail(email: string): boolean { | ||
| const existed = this.users.has(email); | ||
| if (existed) { | ||
| this.users.delete(email); | ||
| this.save(); | ||
| } | ||
| return existed; |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
Create a durable audit contract for deletion.
The route discards DSAR event identity, and the database deletes a record without an audit entry. The completed webhook cannot be traced to a deletion operation.
examples/nextjs-deletion-webhook/lib/db.ts#L74-L81: persist an audit record with event identity, outcome, and legal timestamp before acknowledging deletion.examples/nextjs-deletion-webhook/app/api/webhooks/dsar/route.ts#L15-L36: passeventId,requestId, and required lifecycle metadata to the deletion operation.
📍 Affects 2 files
examples/nextjs-deletion-webhook/lib/db.ts#L74-L81(this comment)examples/nextjs-deletion-webhook/app/api/webhooks/dsar/route.ts#L15-L36
🤖 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 `@examples/nextjs-deletion-webhook/lib/db.ts` around lines 74 - 81, Update
deleteByEmail in examples/nextjs-deletion-webhook/lib/db.ts:74-81 to accept
eventId, requestId, and required lifecycle metadata, persist an audit record
containing the event identity, deletion outcome, and legal timestamp before
acknowledging the deletion, while preserving the boolean result. Update the DSAR
webhook handler in
examples/nextjs-deletion-webhook/app/api/webhooks/dsar/route.ts:15-36 to pass
those values into deleteByEmail.
Source: Coding guidelines
| ```typescript | ||
| import { nextWebhookMiddleware } from "@dsar/node-sdk/webhooks/next"; | ||
| import { deleteDemoUserByEmail } from "../../../../lib/db"; | ||
|
|
||
| export const POST = nextWebhookMiddleware({ | ||
| signingSecret: process.env.DSAR_WEBHOOK_SECRET!, | ||
| handlers: { | ||
| request_captured: (event) => { | ||
| deleteDemoUserByEmail(event.payload.email as string); | ||
| }, | ||
| }, | ||
| }); | ||
| ``` |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Validate the email before deletion.
event.payload.email as string does not validate the adapter payload. A malformed but signed event can pass undefined or a non-string value into deleteDemoUserByEmail.
Decode event.payload with a focused guard or Effect Schema. Reject invalid payloads before calling the deletion function. Update the copied route example to show that validation.
As per coding guidelines, “Decode unknown at system boundaries with Effect Schema or a focused guard; do not cast request bodies, persisted JSON, or adapter payloads into domain types.”
🤖 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 `@examples/nextjs-deletion-webhook/README.md` around lines 21 - 33, The
request_captured handler in the documented nextWebhookMiddleware example must
validate event.payload.email before deletion instead of casting it to string.
Add a focused guard or Effect Schema decode for the adapter payload, reject
invalid or missing email values, and call deleteDemoUserByEmail only with the
validated string.
Source: Coding guidelines
| const responseBody = (await response.json()) as { ok: boolean }; | ||
| if (!responseBody.ok) { | ||
| throw new Error("Expected response body { ok: true }"); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Decode the acknowledgement response.
The cast allows invalid truthy values, such as { "ok": "yes" }, to pass. Treat response.json() as unknown and use a focused guard that requires exactly { ok: true }.
As per coding guidelines, “Decode unknown at system boundaries with Effect Schema or a focused guard; do not cast … adapter payloads into domain types.”
🤖 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 `@examples/nextjs-deletion-webhook/scripts/smoke.ts` around lines 71 - 74,
Update the acknowledgement handling around response.json() to treat the decoded
payload as unknown and validate it with a focused guard that accepts only an
object whose ok property is exactly true. Remove the { ok: boolean } cast, and
retain the existing error behavior for all invalid response shapes.
Source: Coding guidelines
| it("creates a webhook receiver from sdk.webhooks.receiver()", () => { | ||
| const sdk = createNodeSdk({ | ||
| baseUrl: "http://localhost:3000/api/v1", | ||
| token: TEST_API_TOKEN, | ||
| }); | ||
|
|
||
| const receiver = sdk.webhooks.receiver({ signingSecret: "test-secret" }); | ||
| expect(receiver).toBeDefined(); | ||
| expect(typeof receiver.handle).toBe("function"); | ||
| expect(typeof receiver.on).toBe("function"); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Exercise the receiver behavior through the public API.
This test only checks method presence. It does not verify that sdk.webhooks.receiver() transfers handlers, invokes verification, dispatches an event, or returns the acknowledgment result.
Create a receiver with a verifier and a request_captured handler. Call receiver.handle() with a signed payload. Assert the handler effect and { ok: true } response.
As per coding guidelines, “For user-visible behavior, prefer acceptance paths through a public API, CLI, SDK, or adapter contract; assert responses and durable side effects rather than internal calls.”
🤖 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 `@packages/node-sdk/test/client.test.ts` around lines 319 - 328, Expand the
test for sdk.webhooks.receiver() to exercise its public behavior: configure a
verifier and request_captured handler, invoke receiver.handle() with a signed
payload, and assert the handler’s observable effect plus the resulting { ok:
true } acknowledgment. Replace the current method-presence-only assertions while
keeping the setup through the public SDK API.
Source: Coding guidelines
| const res1 = await middleware(makeReq()); | ||
| expect(verify).toHaveBeenCalledTimes(1); | ||
| expect(res1.status).toBe(200); | ||
| expect(capturedHandler).toHaveBeenCalledTimes(1); | ||
| expect(capturedHandler).toHaveBeenCalledWith( | ||
| expect.objectContaining({ | ||
| eventId: "evt_1", | ||
| eventType: "request_captured", | ||
| requestId: "req_1", | ||
| }) | ||
| ); | ||
|
|
||
| const res2 = await middleware(makeReq()); | ||
| expect(res2.status).toBe(200); | ||
| expect(capturedHandler).toHaveBeenCalledTimes(2); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Assert the acknowledgment response body.
A 200 response can contain an incompatible payload. Assert await res1.json() and await res2.json() equal { ok: true }.
As per coding guidelines, “For user-visible behavior, prefer acceptance paths through a public API, CLI, SDK, or adapter contract; assert responses and durable side effects rather than internal calls.”
🤖 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 `@packages/node-sdk/test/webhooks/next.test.ts` around lines 75 - 89, Update
the middleware response assertions in the test around middleware so both res1
and res2 validate their parsed JSON bodies equal { ok: true }, in addition to
the existing 200 status checks and handler assertions.
Source: Coding guidelines
|
@KayleeWilliams have a look |

Summary
Adds a standalone, 5-minute quickstart example in \examples/nextjs-deletion-webhook\ demonstrating how to receive outbound DSAR deletion/erasure webhooks using @dsar/node-sdk/webhooks/next.
Features
extWebhookMiddleware.
Closes #21
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.