{"_id":"@dsr-kit/connector-resend","name":"@dsr-kit/connector-resend","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@dsr-kit/connector-resend","version":"0.1.0","description":"Resend processor connector for dsr-kit — contact suppression for GDPR erasure workflows.","keywords":["gdpr","resend","suppression","processor","data-subject-rights","dsr-kit","privacy"],"license":"Apache-2.0","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js","default":"./dist/index.js"}},"scripts":{"build":"tsc -p tsconfig.json","test":"vitest run","lint":"tsc -p tsconfig.json --noEmit"},"dependencies":{"@dsr-kit/core":"^0.1.0"},"devDependencies":{"typescript":"^5.9.3","vitest":"3.2.4"},"_id":"@dsr-kit/connector-resend@0.1.0","gitHead":"c9f9b9156f70e9ae96cbbbef1632977bc9bad57f","_nodeVersion":"22.14.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-Xlf8x7uwYw4UKqNi2Zg0HCSsBvbHDHeSDoiR4WjzcG6XKRkcE/SG+vSmQRcB9JP8NnsX42qKOBqPe4+Stt2uHg==","shasum":"fb25c5b5857fe53f188ceecc979cbdd9ae017eb0","tarball":"https://registry.npmjs.org/@dsr-kit/connector-resend/-/connector-resend-0.1.0.tgz","fileCount":6,"unpackedSize":16619,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDRnD09UWc2zcKgYqfedRtSALf1tdkLNJxyO8ib60gvwAiAPsh99I/VZPNuD0/kRnEwEuSoKqpL28Q47dYUqCY7HZA=="}]},"_npmUser":{"name":"murdad","email":"max_shakh@yahoo.com"},"directories":{},"maintainers":[{"name":"murdad","email":"max_shakh@yahoo.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/connector-resend_0.1.0_1781985848563_0.2650566227263529"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-20T20:04:08.422Z","0.1.0":"2026-06-20T20:04:08.742Z","modified":"2026-06-20T20:04:08.938Z"},"maintainers":[{"name":"murdad","email":"max_shakh@yahoo.com"}],"description":"Resend processor connector for dsr-kit — contact suppression for GDPR erasure workflows.","keywords":["gdpr","resend","suppression","processor","data-subject-rights","dsr-kit","privacy"],"license":"Apache-2.0","readme":"# dsr-kit\n\n**GDPR Data Subject Rights Kit** — auditable erasure, access/export, and proof-of-compliance for Next.js + Prisma apps.\n\n[![CI](https://github.com/BrixPilot/dsr-kit/actions/workflows/ci.yml/badge.svg)](https://github.com/BrixPilot/dsr-kit/actions/workflows/ci.yml)\n\n> **This is not legal advice.** dsr-kit provides engineering tooling to help implement GDPR data subject rights workflows. Consult qualified counsel for compliance obligations specific to your organization.\n>\n> **Read first:** [Guarantees and limits](docs/GUARANTEES-AND-LIMITS.md) · [Threat model](docs/threat-model.md)\n\n## What it guarantees\n\n- **Declarative data map** — every personal-data location is explicit, reviewable TypeScript config\n- **Dry-run by default** — first erasure reports what would happen; no silent mutations\n- **Correct cascades** — relation-aware deletion order; delete vs redact vs retain\n- **Legal-hold / retention** — RETAIN items are never deleted; reason recorded in proof\n- **Processor propagation** — pluggable connectors; erasure never deletes data you are legally required to keep\n- **Tamper-evident proof** — per-subject hash chains with serialized append; no raw PII\n- **Post-erasure verification** — re-scan fails loudly if personal data residue remains on mapped primary-store fields\n- **Identity gate** — erasure/export blocked until integrator confirms requester identity\n- **Coverage check** — build/test warns on undeclared personal-data columns (structural, not semantic)\n\n`REDACT` replaces field values with sentinels — **pseudonymization, not legal anonymization**. See [Guarantees and limits](docs/GUARANTEES-AND-LIMITS.md).\n\n## What it does NOT do\n\n- Provide legal advice or guarantee GDPR compliance\n- Replace a hosted DSR portal, audit PDF reports, or evidence platforms (Vanta/Drata)\n- Cover regulations beyond GDPR DSR in the OSS core (CCPA, SOC2, AI Act → commercial layer)\n- Phone home or require external SaaS accounts\n- Treat `REDACT` as legal anonymization — replacing email/name with a sentinel while a stable `userId` remains is still personal data under GDPR\n- Auto-erasure outside declared paths — coverage is **primary store + registered processors**; logs, caches, search, analytics/warehouse, and backups/replicas are declarable but not auto-erased\n- Semantic PII detection — the coverage check is **structural** (model/column names), not content-aware; it will not see PII inside JSON/text columns\n- Prove every copy is gone — verification covers the **mapped primary-store surface only**\n- **Resume across crashes** — v0.1 has no durable step ledger; a mid-run failure may leave partial deletion without proof (see [Guarantees §7](docs/GUARANTEES-AND-LIMITS.md#7-atomicity-crashes-and-resumability-v01-limit))\n\nFull limits: [docs/GUARANTEES-AND-LIMITS.md](docs/GUARANTEES-AND-LIMITS.md)\n\n## Tests and CI\n\nDestructive paths are covered by Vitest suites in `packages/*` (dry-run zero-mutation, per-subject proof-chain concurrency, RETAIN, idempotent re-run, processor dry-run). Run locally:\n\n```bash\nnpm run build && npm test\n```\n\nCI runs the same on push via [`.github/workflows/ci.yml`](.github/workflows/ci.yml) (Postgres service + full package test matrix).\n\n## GDPR article mapping\n\n| Feature | Articles |\n|---------|----------|\n| Right to erasure | Art. 17 |\n| Right of access | Art. 15 |\n| Data portability | Art. 20 |\n| Response deadline tracking | Art. 12(3) |\n\n## Try the demo app\n\nThe repo includes a runnable example at [`apps/example`](apps/example) — a Next.js + Prisma app with a small UI and API routes. Use this to explore dsr-kit before wiring it into your own app.\n\n```bash\n# 1. Clone and install\ngit clone git@github.com:BrixPilot/dsr-kit.git && cd dsr-kit\nnpm install\n\n# 2. Start Postgres\ndocker compose up -d\n\n# 3. Set up the demo database\ncp apps/example/.env.example apps/example/.env\nnpm run build\ncd apps/example && npx prisma db push && npm run db:seed\n\n# 4. Start the demo UI\ncd .. && npm run dev:example\n# open http://localhost:3000 — paste the User id printed by db:seed\n\n# 5. Or call the API directly (dry-run first — no mutations)\ncurl -X POST \"http://localhost:3000/api/dsr/erasure?subjectValue=USER_ID_FROM_SEED\"\n\n# Execute only after identity verification\ncurl -X POST \"http://localhost:3000/api/dsr/erasure?subjectValue=USER_ID&execute=true\" \\\n  -H \"x-dsr-verified: true\"\n```\n\nThe demo uses `x-dsr-verified: true` as a stand-in identity check. **Do not use that in production** — implement real verification (see below).\n\nRun the demo coverage check (validates the example data map against its schema):\n\n```bash\nnpm run coverage\n```\n\n---\n\n## Use in your project\n\ndsr-kit ships as npm workspace packages. In a **Next.js App Router + Prisma + Postgres** app:\n\n### 1. Install packages\n\n```bash\nnpm install @dsr-kit/core @dsr-kit/adapter-prisma @dsr-kit/next\n# optional processor connectors\nnpm install @dsr-kit/connector-stripe @dsr-kit/connector-resend\n```\n\n### 2. Declare your data map\n\nCreate a TypeScript config listing every model/column that holds personal data, and what happens on erasure. This is the auditable source of truth — review it like any other security-sensitive config.\n\n**Action precedence:** declared field actions win; undeclared columns inherit the model `action`; if every field is `RETAIN`, the model is `RETAIN`. Details in [Guarantees and limits](docs/GUARANTEES-AND-LIMITS.md#data-map-action-precedence).\n\n```typescript\n// lib/dsr/data-map.ts\nimport { defineDataMap } from \"@dsr-kit/core\";\n\nexport const dataMap = defineDataMap({\n  subjectKey: \"userId\",       // FK column on child tables\n  subjectModel: \"User\",       // root entity — matched by `id`\n  models: {\n    User: {\n      fields: { email: \"REDACT\", name: \"REDACT\" },\n      action: \"REDACT\",        // pseudonymization — NOT legal anonymization\n    },\n    Session: { parent: \"User\", cascade: \"DELETE\", subjectLink: \"userId\" },\n    Invoice: {\n      fields: { amount: \"RETAIN\", taxId: \"RETAIN\" },\n      legalBasis: \"tax_retention_7y\",\n      subjectLink: \"userId\",\n    },\n  },\n  processors: [\"stripe\", \"resend\"],\n});\n```\n\nSee [`apps/example/lib/data-map.ts`](apps/example/lib/data-map.ts) for a full example.\n\n### 3. Wire the Prisma adapter\n\n```typescript\n// lib/dsr/adapter.ts\nimport { PrismaClient } from \"@prisma/client\";\nimport { createPrismaAdapter } from \"@dsr-kit/adapter-prisma\";\nimport { dataMap } from \"./data-map\";\n\nconst prisma = new PrismaClient();\n\nexport const adapter = createPrismaAdapter({ prisma, dataMap });\n```\n\n### 4. Add proof + request storage\n\nProof records must be persisted (hash-chained, no raw PII). The demo stores them in Postgres — copy the `DsrProof` and `DsrRequest` models from [`apps/example/prisma/schema.prisma`](apps/example/prisma/schema.prisma) and implement `ProofStore` / `RequestStore`, or see [`apps/example/lib/dsr.ts`](apps/example/lib/dsr.ts) for a working implementation.\n\nFor local prototyping only, `@dsr-kit/core` exports `InMemoryProofStore` and `InMemoryRequestStore`.\n\n### 5. Register processor connectors (optional)\n\n**Stripe** — reference connector with meaningful erasure (customer identity deleted; billing artifacts retained where legally required).\n\n**Resend** — reference connector demonstrating **limits**: send logs are immutable; only future suppression is possible. Not parity with Stripe — included to show honest processor boundaries.\n\nErasure never means deleting data you are legally required to keep — connectors mark RETAIN items in the proof, same as the primary store.\n\n```typescript\nimport { createStripeConnector } from \"@dsr-kit/connector-stripe\";\nimport { createResendConnector } from \"@dsr-kit/connector-resend\";\n\nconst processors = [\n  createStripeConnector({ secretKey: process.env.STRIPE_SECRET_KEY }),\n  createResendConnector({ apiKey: process.env.RESEND_API_KEY }), // suppression-only demo\n];\n```\n\nConnectors are no-ops in dry-run mode — outbound API calls only happen on execute.\n\n### 6. Create route handlers\n\n```typescript\n// lib/dsr/handlers.ts\nimport { createDsrHandler } from \"@dsr-kit/next\";\nimport { createStripeConnector } from \"@dsr-kit/connector-stripe\";\nimport { createResendConnector } from \"@dsr-kit/connector-resend\";\nimport { adapter } from \"./adapter\";\nimport { dataMap } from \"./data-map\";\nimport { proofStore, requestStore } from \"./stores\";\n\nexport const dsrHandlers = createDsrHandler({\n  dataMap,\n  adapter,\n  proofStore,\n  requestStore,\n  processors: [\n    createStripeConnector({ secretKey: process.env.STRIPE_SECRET_KEY }),\n    createResendConnector({ apiKey: process.env.RESEND_API_KEY }),\n  ],\n  identityVerify: async (req, subject) => {\n    // REQUIRED: verify the requester before execute/export.\n    // Return { verified: false } until your auth flow confirms identity.\n    const session = await getSession(req);\n    return {\n      verified: session?.userId === subject.value,\n      verifiedAt: new Date().toISOString(),\n      method: \"session\",\n    };\n  },\n});\n```\n\nWire into App Router routes:\n\n```typescript\n// app/api/dsr/erasure/route.ts\nimport { dsrHandlers } from \"@/lib/dsr/handlers\";\n\nexport async function POST(req: Request) {\n  return dsrHandlers.handleErasure(req);\n}\n```\n\nAdd matching routes for export, proof, and status — see [`apps/example/app/api/dsr/`](apps/example/app/api/dsr/).\n\n### 7. Dry-run first, then execute\n\n| Action | Request |\n|--------|---------|\n| Dry-run erasure (default, safe) | `POST /api/dsr/erasure?subjectValue=<user-id>` |\n| Execute erasure | `POST /api/dsr/erasure?subjectValue=<user-id>&execute=true` + verified identity |\n| Export personal data | `POST /api/dsr/export?subjectValue=<user-id>` + verified identity |\n| Export proof record | `GET /api/dsr/proof/<proof-id>` |\n| Request deadline status | `GET /api/dsr/status/<request-id>` |\n\n**Always dry-run first.** Execution requires your `identityVerify` hook to return `{ verified: true }`. Export always requires verification.\n\n### 8. Run the coverage check in CI\n\nCompare your data map against your Prisma schema so undeclared personal-data columns fail at build/test time. Adapt [`apps/example/scripts/coverage-check.ts`](apps/example/scripts/coverage-check.ts) for your schema and add it to CI. Remember: structural check only — see [limits](docs/GUARANTEES-AND-LIMITS.md#coverage-check-structural-not-semantic).\n\n---\n\n## Packages\n\n| Package | Purpose |\n|---------|---------|\n| `@dsr-kit/core` | Engine, data map, erasure, export, proof |\n| `@dsr-kit/adapter-prisma` | Prisma + Postgres adapter |\n| `@dsr-kit/connector-stripe` | Stripe customer erasure (billing RETAIN where required) |\n| `@dsr-kit/connector-resend` | Resend suppression-only limits demo (not full erasure) |\n| `@dsr-kit/next` | Next.js App Router handlers |\n\n## Reference implementation\n\n[`apps/example`](apps/example) is the canonical integration: data map, Prisma adapter, proof/request stores, API routes, and coverage script. Start there when wiring dsr-kit into your app.\n\n## License\n\nApache-2.0 — see [LICENSE](LICENSE).\n","readmeFilename":"README.md","_rev":"1-60274455ade90fdb97528f7b45f9e348"}