From e378c950a91cde9f1a1c42d10c46116877424937 Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Tue, 19 May 2026 19:32:03 +0000 Subject: [PATCH] feat(core-dsr): scaffold package + GDPR DSR interfaces and types - Add pnpm turbo gen core-package dsr generator template and register dsr in CORE_PACKAGE_GENERATORS / choices list - Run generator to produce packages/core-dsr/ shell - Define IDataExport (Art. 15/20), IDataDelete (Art. 17), IDataRectify (Art. 16), IProcessingRestriction (Art. 18) interfaces - Add UserDataBundle and DeletionCertificate types in dsr-types.ts - Ship core-dsr/contexts/user-data.jsonld schema.org JSON-LD @context - Wire @repo/core-dsr into transpilePackages (web-next) Co-Authored-By: Claude Sonnet 4.6 --- apps/web-next/next.config.mjs | 1 + coverage/summary.json | 30 ++++++-- packages/core-dsr/AGENTS.md | 33 ++++++++ packages/core-dsr/eslint.config.js | 3 + packages/core-dsr/package.json | 26 +++++++ .../core-dsr/src/contexts/user-data.jsonld | 39 ++++++++++ .../core-dsr/src/data-delete.interface.ts | 29 +++++++ .../core-dsr/src/data-export.interface.ts | 22 ++++++ .../core-dsr/src/data-rectify.interface.ts | 24 ++++++ packages/core-dsr/src/dsr-types.ts | 75 +++++++++++++++++++ packages/core-dsr/src/index.ts | 16 ++++ .../src/processing-restriction.interface.ts | 25 +++++++ packages/core-dsr/tsconfig.json | 12 +++ packages/core-dsr/turbo.json | 4 + packages/core-dsr/vitest.config.ts | 9 +++ pnpm-lock.yaml | 25 +++++++ turbo/generators/config.ts | 37 ++++++++- .../templates/core-package/dsr/AGENTS.md.hbs | 32 ++++++++ .../core-package/dsr/eslint.config.js.hbs | 3 + .../core-package/dsr/package.json.hbs | 27 +++++++ .../core-package/dsr/src/index.ts.hbs | 2 + .../core-package/dsr/tsconfig.json.hbs | 12 +++ .../templates/core-package/dsr/turbo.json.hbs | 4 + .../core-package/dsr/vitest.config.ts.hbs | 9 +++ 24 files changed, 490 insertions(+), 9 deletions(-) create mode 100644 packages/core-dsr/AGENTS.md create mode 100644 packages/core-dsr/eslint.config.js create mode 100644 packages/core-dsr/package.json create mode 100644 packages/core-dsr/src/contexts/user-data.jsonld create mode 100644 packages/core-dsr/src/data-delete.interface.ts create mode 100644 packages/core-dsr/src/data-export.interface.ts create mode 100644 packages/core-dsr/src/data-rectify.interface.ts create mode 100644 packages/core-dsr/src/dsr-types.ts create mode 100644 packages/core-dsr/src/index.ts create mode 100644 packages/core-dsr/src/processing-restriction.interface.ts create mode 100644 packages/core-dsr/tsconfig.json create mode 100644 packages/core-dsr/turbo.json create mode 100644 packages/core-dsr/vitest.config.ts create mode 100644 turbo/generators/templates/core-package/dsr/AGENTS.md.hbs create mode 100644 turbo/generators/templates/core-package/dsr/eslint.config.js.hbs create mode 100644 turbo/generators/templates/core-package/dsr/package.json.hbs create mode 100644 turbo/generators/templates/core-package/dsr/src/index.ts.hbs create mode 100644 turbo/generators/templates/core-package/dsr/tsconfig.json.hbs create mode 100644 turbo/generators/templates/core-package/dsr/turbo.json.hbs create mode 100644 turbo/generators/templates/core-package/dsr/vitest.config.ts.hbs diff --git a/apps/web-next/next.config.mjs b/apps/web-next/next.config.mjs index 645ecea..6eba1e2 100644 --- a/apps/web-next/next.config.mjs +++ b/apps/web-next/next.config.mjs @@ -10,6 +10,7 @@ const nextConfig = { "@repo/core-audit", "@repo/core-cms", "@repo/core-consent", + "@repo/core-dsr", "@repo/core-shared", "@repo/marketing-pages", "@repo/media", diff --git a/coverage/summary.json b/coverage/summary.json index 19f9e25..68e99e4 100644 --- a/coverage/summary.json +++ b/coverage/summary.json @@ -1,18 +1,18 @@ { - "generatedAt": "2026-05-19T19:19:27.597Z", - "commit": "33e3c09", + "generatedAt": "2026-05-19T19:30:03.273Z", + "commit": "86d9492", "repo": { "statements": 96.74, - "branches": 92.11, - "functions": 96.86, + "branches": 92.15, + "functions": 96.92, "lines": 96.74, "counts": { "lf": 4632, "lh": 4481, - "brf": 912, - "brh": 840, - "fnf": 287, - "fnh": 278 + "brf": 917, + "brh": 845, + "fnf": 292, + "fnh": 283 } }, "byPackage": { @@ -72,6 +72,20 @@ "fnh": 33 } }, + "@repo/core-dsr": { + "statements": 100, + "branches": 100, + "functions": 100, + "lines": 100, + "counts": { + "lf": 0, + "lh": 0, + "brf": 5, + "brh": 5, + "fnf": 5, + "fnh": 5 + } + }, "@repo/core-shared": { "statements": 98.03, "branches": 95.89, diff --git a/packages/core-dsr/AGENTS.md b/packages/core-dsr/AGENTS.md new file mode 100644 index 0000000..f76952e --- /dev/null +++ b/packages/core-dsr/AGENTS.md @@ -0,0 +1,33 @@ +# @repo/core-dsr + +Optional core package providing GDPR Data Subject Rights (DSR) interfaces and implementations. Scaffold via `pnpm turbo gen core-package dsr`. + +## Structure + +``` +src/ + data-export.interface.ts # IDataExport — exportSubjectData + data-delete.interface.ts # IDataDelete — deleteSubjectData + data-rectify.interface.ts # IDataRectify — updateSubjectField + processing-restriction.interface.ts # IProcessingRestriction — setRestriction, isRestricted + dsr-types.ts # UserDataBundle, DeletionCertificate, DSR value types + contexts/ + user-data.jsonld # schema.org JSON-LD @context + index.ts # Barrel export +``` + +## Design + +Four interfaces map directly to GDPR Articles 15–18 + 20: + +- `IDataExport` (Art. 15/20) — export a subject's data as `UserDataBundle` +- `IDataDelete` (Art. 17) — soft-delete or cascade-hard-delete subject data; returns `DeletionCertificate` +- `IDataRectify` (Art. 16) — update a specific field for a subject +- `IProcessingRestriction` (Art. 18) — toggle and read the processing restriction flag + +Implementations walk `custom.pii`-tagged fields and `custom.subject`-linked collections. Row semantics: + +- `kind: "self" | "owner"` → directly owned by the subject (export full; delete hard or soft) +- `kind: "reference"` → references the subject from another entity (export redacted; redact link on delete) + +See `docs/architecture/agent-first-workflow-and-conformance.md` for the DI conventions. diff --git a/packages/core-dsr/eslint.config.js b/packages/core-dsr/eslint.config.js new file mode 100644 index 0000000..7440d8f --- /dev/null +++ b/packages/core-dsr/eslint.config.js @@ -0,0 +1,3 @@ +import baseConfig from "@repo/core-eslint/base"; + +export default baseConfig; diff --git a/packages/core-dsr/package.json b/packages/core-dsr/package.json new file mode 100644 index 0000000..dd0b77d --- /dev/null +++ b/packages/core-dsr/package.json @@ -0,0 +1,26 @@ +{ + "name": "@repo/core-dsr", + "version": "0.0.1", + "private": true, + "type": "module", + "exports": { + ".": "./src/index.ts" + }, + "scripts": { + "build": "tsc --noEmit", + "lint": "eslint .", + "typecheck": "tsc --noEmit", + "test": "vitest run --passWithNoTests" + }, + "dependencies": { + "@repo/core-shared": "workspace:*" + }, + "devDependencies": { + "@repo/core-eslint": "workspace:*", + "@repo/core-testing": "workspace:*", + "@repo/core-typescript": "workspace:*", + "@vitest/coverage-v8": "^3.0.0", + "typescript": "^5.8.0", + "vitest": "^3.0.0" + } +} diff --git a/packages/core-dsr/src/contexts/user-data.jsonld b/packages/core-dsr/src/contexts/user-data.jsonld new file mode 100644 index 0000000..519cc95 --- /dev/null +++ b/packages/core-dsr/src/contexts/user-data.jsonld @@ -0,0 +1,39 @@ +{ + "@context": { + "@vocab": "https://schema.org/", + "dsr": "https://w3.org/ns/dpv#", + "prov": "https://www.w3.org/ns/prov#", + + "subjectId": "identifier", + "exportedAt": "dateCreated", + "format": "encodingFormat", + + "data": { + "@id": "prov:hadMember", + "@container": "@index" + }, + + "asSelf": { + "@id": "dsr:hasPersonalDataHandling", + "@type": "@id" + }, + "asReference": { + "@id": "dsr:hasDataSubjectRight", + "@type": "@id" + }, + "rowId": "identifier", + "linkedField": "name", + "linkedThrough": { + "@id": "isPartOf", + "@type": "@id" + }, + + "auditLog": { + "@id": "prov:wasGeneratedBy", + "@type": "@id" + }, + + "UserDataBundle": "dsr:RightOfAccess", + "SubjectReference": "dsr:DataSubjectRight" + } +} diff --git a/packages/core-dsr/src/data-delete.interface.ts b/packages/core-dsr/src/data-delete.interface.ts new file mode 100644 index 0000000..239b8ea --- /dev/null +++ b/packages/core-dsr/src/data-delete.interface.ts @@ -0,0 +1,29 @@ +import type { DeletionCertificate, DeletionMode } from "./dsr-types"; + +/** + * GDPR Art. 17 (right to erasure / "right to be forgotten"). + * + * Two modes: + * + * - `"soft"` — sets `processingRestrictedAt`, NULLs all `exportable: true` + * PII fields, and redacts `reference`-role linked fields to null. The row + * structure is preserved so other subjects' data in shared rows remains + * intact. Emits one RESTRICT audit entry per affected collection. + * + * - `"cascade-hard"` — hard-deletes `self` and `owner` rows immediately, then + * redacts `reference` fields. Auth-guarded at the procedure layer; must not + * be called from user-facing flows. Emits DELETE audit entries. + */ +export interface IDataDelete { + /** + * Delete or erase all personal data held for the given subject. + * + * @param subjectId - The subject's canonical ID. + * @param mode - Deletion strategy (soft redaction vs hard cascade). + * @returns A signed `DeletionCertificate` linking to the audit log entry. + */ + deleteSubjectData( + subjectId: string, + mode: DeletionMode, + ): Promise; +} diff --git a/packages/core-dsr/src/data-export.interface.ts b/packages/core-dsr/src/data-export.interface.ts new file mode 100644 index 0000000..4888f6d --- /dev/null +++ b/packages/core-dsr/src/data-export.interface.ts @@ -0,0 +1,22 @@ +import type { DsrFormat, UserDataBundle } from "./dsr-types"; + +/** + * GDPR Art. 15 (right of access) + Art. 20 (right to data portability). + * + * Implementations walk all Payload collections with `custom.subject` linkage, + * segment rows by role (self/owner vs reference), and filter to fields marked + * `exportable: true` in `custom.pii`. + */ +export interface IDataExport { + /** + * Export all personal data held for the given subject. + * + * @param subjectId - The subject's canonical ID (e.g. users.id). + * @param format - "json" for a plain JSON bundle; "json-ld" attaches the + * @context from `contexts/user-data.jsonld`. + */ + exportSubjectData( + subjectId: string, + format: DsrFormat, + ): Promise; +} diff --git a/packages/core-dsr/src/data-rectify.interface.ts b/packages/core-dsr/src/data-rectify.interface.ts new file mode 100644 index 0000000..42e9cb2 --- /dev/null +++ b/packages/core-dsr/src/data-rectify.interface.ts @@ -0,0 +1,24 @@ +/** + * GDPR Art. 16 (right to rectification). + * + * Allows a subject to correct inaccurate personal data held about them. + * Implementations verify the field is PII-tagged before updating and emit a + * RESTRICT audit entry with `reason: "art-16-request"` as the tamper-evident + * record of the correction. + */ +export interface IDataRectify { + /** + * Update a single PII field for the given subject in the specified collection. + * + * @param subjectId - The subject's canonical ID. + * @param collection - Payload collection slug (e.g. "users"). + * @param field - Name of the field to update (must be `custom.pii`-tagged). + * @param value - New value; must satisfy the field's Payload field type. + */ + updateSubjectField( + subjectId: string, + collection: string, + field: string, + value: unknown, + ): Promise; +} diff --git a/packages/core-dsr/src/dsr-types.ts b/packages/core-dsr/src/dsr-types.ts new file mode 100644 index 0000000..8f22f6a --- /dev/null +++ b/packages/core-dsr/src/dsr-types.ts @@ -0,0 +1,75 @@ +import type { AuditEntry } from "@repo/core-shared/audit"; + +export type DsrFormat = "json" | "json-ld"; + +export type DeletionMode = "soft" | "cascade-hard"; + +export type DeletionReason = + | "art-17-request" + | "admin-expunge" + | "retention-policy"; + +export type DeletionAction = "deleted" | "redacted" | "pseudonymized"; + +/** Row reference from a collection where the subject appears as a non-owner link. */ +export type SubjectReference = { + rowId: string; + /** Field name in the collection that links to the subject. */ + linkedField: string; + /** Slug of the collection containing the reference. */ + linkedThrough: string; +}; + +/** Per-collection data bucket within a UserDataBundle. */ +export type CollectionDataBucket = { + /** Rows directly owned by the subject (kind: "self" | "owner"). */ + asSelf?: Array>; + /** Rows referencing the subject without owning the row (kind: "reference"). */ + asReference?: SubjectReference[]; +}; + +/** + * GDPR Art. 15/20 export payload. + * + * `data` is keyed by Payload collection slug. asSelf contains exportable-PII- + * filtered rows the subject owns; asReference lists row IDs + link coordinates + * for rows that merely reference the subject. + */ +export type UserDataBundle = { + subjectId: string; + /** ISO 8601 timestamp of when the export was produced. */ + exportedAt: string; + format: DsrFormat; + data: Record; + /** Audit entries scoped to this subject's activity. */ + auditLog?: AuditEntry[]; + /** JSON-LD @context URI or inline object; populated when format === "json-ld". */ + "@context"?: string | Record; +}; + +/** Per-collection summary of what the deletion touched. */ +export type DeletionAffected = { + collection: string; + rowsAffected: number; + action: DeletionAction; + /** PII field names that were NULLed when action === "redacted". */ + fields?: string[]; +}; + +/** + * Immutable proof of a completed GDPR Art. 17 deletion / erasure request. + * + * The `auditEntryId` links back to the audit log entry created at deletion + * time, forming a tamper-evident chain for regulatory inspection. + */ +export type DeletionCertificate = { + /** Subject ID, or "erased-{hash}" if the ID itself was purged. */ + subjectId: string; + mode: DeletionMode; + /** ISO 8601 timestamp of the deletion. */ + timestamp: string; + reason: DeletionReason; + affected: DeletionAffected[]; + /** ID of the audit log entry that recorded this operation. */ + auditEntryId: string; +}; diff --git a/packages/core-dsr/src/index.ts b/packages/core-dsr/src/index.ts new file mode 100644 index 0000000..b023864 --- /dev/null +++ b/packages/core-dsr/src/index.ts @@ -0,0 +1,16 @@ +export type { + DsrFormat, + DeletionMode, + DeletionReason, + DeletionAction, + SubjectReference, + CollectionDataBucket, + UserDataBundle, + DeletionAffected, + DeletionCertificate, +} from "./dsr-types"; + +export type { IDataExport } from "./data-export.interface"; +export type { IDataDelete } from "./data-delete.interface"; +export type { IDataRectify } from "./data-rectify.interface"; +export type { IProcessingRestriction } from "./processing-restriction.interface"; diff --git a/packages/core-dsr/src/processing-restriction.interface.ts b/packages/core-dsr/src/processing-restriction.interface.ts new file mode 100644 index 0000000..40f344b --- /dev/null +++ b/packages/core-dsr/src/processing-restriction.interface.ts @@ -0,0 +1,25 @@ +/** + * GDPR Art. 18 (right to restriction of processing). + * + * Toggles and reads the `processingRestrictedAt` flag on the subject's user + * record. When restricted, downstream use cases should call `isRestricted` + * before processing personal data and short-circuit if true. + * + * Emits RESTRICT / UNRESTRICT audit entries on every state change. + */ +export interface IProcessingRestriction { + /** + * Grant or revoke processing restriction for the given subject. + * + * @param subjectId - The subject's canonical ID. + * @param granted - true to restrict processing; false to lift restriction. + */ + setRestriction(subjectId: string, granted: boolean): Promise; + + /** + * Return whether processing is currently restricted for the given subject. + * + * @param subjectId - The subject's canonical ID. + */ + isRestricted(subjectId: string): Promise; +} diff --git a/packages/core-dsr/tsconfig.json b/packages/core-dsr/tsconfig.json new file mode 100644 index 0000000..8facef5 --- /dev/null +++ b/packages/core-dsr/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "@repo/core-typescript/base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/core-dsr/turbo.json b/packages/core-dsr/turbo.json new file mode 100644 index 0000000..dcb8fb3 --- /dev/null +++ b/packages/core-dsr/turbo.json @@ -0,0 +1,4 @@ +{ + "extends": ["//"], + "tags": ["core"] +} diff --git a/packages/core-dsr/vitest.config.ts b/packages/core-dsr/vitest.config.ts new file mode 100644 index 0000000..2ee07c1 --- /dev/null +++ b/packages/core-dsr/vitest.config.ts @@ -0,0 +1,9 @@ +import path from "node:path"; +import { mergeConfig } from "vitest/config"; +import { nodeVitestConfig } from "@repo/core-typescript/vitest.base.node"; + +export default mergeConfig(nodeVitestConfig, { + resolve: { + alias: { "@": path.resolve(__dirname, "./src") }, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4e7e811..c4d6150 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -633,6 +633,31 @@ importers: specifier: ^3.0.0 version: 3.2.4(@types/debug@4.1.13)(@types/node@25.5.2)(happy-dom@20.8.9)(jiti@2.6.1)(jsdom@25.0.1)(lightningcss@1.32.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)(yaml@2.9.0) + packages/core-dsr: + dependencies: + "@repo/core-shared": + specifier: workspace:* + version: link:../core-shared + devDependencies: + "@repo/core-eslint": + specifier: workspace:* + version: link:../core-eslint + "@repo/core-testing": + specifier: workspace:* + version: link:../core-testing + "@repo/core-typescript": + specifier: workspace:* + version: link:../core-typescript + "@vitest/coverage-v8": + specifier: ^3.0.0 + version: 3.2.4(vitest@3.2.4(@types/debug@4.1.13)(@types/node@25.5.2)(happy-dom@20.8.9)(jiti@2.6.1)(jsdom@25.0.1)(lightningcss@1.32.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)(yaml@2.9.0)) + typescript: + specifier: ^5.8.0 + version: 5.9.3 + vitest: + specifier: ^3.0.0 + version: 3.2.4(@types/debug@4.1.13)(@types/node@25.5.2)(happy-dom@20.8.9)(jiti@2.6.1)(jsdom@25.0.1)(lightningcss@1.32.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)(yaml@2.9.0) + packages/core-eslint: dependencies: globals: diff --git a/turbo/generators/config.ts b/turbo/generators/config.ts index 51c331a..63255b2 100644 --- a/turbo/generators/config.ts +++ b/turbo/generators/config.ts @@ -797,11 +797,26 @@ import noRealtimeHandlerReexport from "./rules/no-realtime-handler-reexport.js"; }, printConsentNextSteps, ], + dsr: () => [ + () => { + assertOptionalPackageNotPresent("core-dsr"); + return "Guard passed — packages/core-dsr does not exist yet."; + }, + ...emitTemplateTree("core-package/dsr", "packages/core-dsr"), + () => { + addToTranspilePackages( + "apps/web-next/next.config.mjs", + "@repo/core-dsr", + ); + return "Added @repo/core-dsr to transpilePackages."; + }, + printDsrNextSteps, + ], }; plop.setGenerator("core-package", { description: - "Scaffold an optional core package (realtime, events, trpc, ui, audit, analytics, consent)", + "Scaffold an optional core package (realtime, events, trpc, ui, audit, analytics, consent, dsr)", prompts: [ { type: "list", @@ -811,6 +826,7 @@ import noRealtimeHandlerReexport from "./rules/no-realtime-handler-reexport.js"; "analytics", "audit", "consent", + "dsr", "events", "realtime", "trpc", @@ -1564,6 +1580,25 @@ function printConsentNextSteps(): string { ].join("\n"); } +function printDsrNextSteps(): string { + return [ + "─────────────────────────────────────────────────────────────", + "@repo/core-dsr scaffolded into packages/core-dsr/.", + "", + "Next steps:", + "", + " 1. pnpm install # link the new workspace package", + "", + " 2. Implement DSR interfaces and types in packages/core-dsr/src/", + " (see story 06-core-dsr)", + "", + " 3. Add @repo/core-dsr to feature package.json files that need DSR", + "", + " 4. pnpm typecheck && pnpm lint && pnpm test", + "─────────────────────────────────────────────────────────────", + ].join("\n"); +} + function coreUiComponentActions(a: { tier: "atom" | "molecule" | "organism"; name: string; diff --git a/turbo/generators/templates/core-package/dsr/AGENTS.md.hbs b/turbo/generators/templates/core-package/dsr/AGENTS.md.hbs new file mode 100644 index 0000000..3d4d766 --- /dev/null +++ b/turbo/generators/templates/core-package/dsr/AGENTS.md.hbs @@ -0,0 +1,32 @@ +# @repo/core-dsr + +Optional core package providing GDPR Data Subject Rights (DSR) interfaces and implementations. Scaffold via `pnpm turbo gen core-package dsr`. + +## Structure + +``` +src/ + data-export.interface.ts # IDataExport — exportSubjectData + data-delete.interface.ts # IDataDelete — deleteSubjectData + data-rectify.interface.ts # IDataRectify — updateSubjectField + processing-restriction.interface.ts # IProcessingRestriction — setRestriction, isRestricted + dsr-types.ts # UserDataBundle, DeletionCertificate, DSR value types + contexts/ + user-data.jsonld # schema.org JSON-LD @context + index.ts # Barrel export +``` + +## Design + +Four interfaces map directly to GDPR Articles 15–18 + 20: + +- `IDataExport` (Art. 15/20) — export a subject's data as `UserDataBundle` +- `IDataDelete` (Art. 17) — soft-delete or cascade-hard-delete subject data; returns `DeletionCertificate` +- `IDataRectify` (Art. 16) — update a specific field for a subject +- `IProcessingRestriction` (Art. 18) — toggle and read the processing restriction flag + +Implementations walk `custom.pii`-tagged fields and `custom.subject`-linked collections. Row semantics: +- `kind: "self" | "owner"` → directly owned by the subject (export full; delete hard or soft) +- `kind: "reference"` → references the subject from another entity (export redacted; redact link on delete) + +See `docs/architecture/agent-first-workflow-and-conformance.md` for the DI conventions. diff --git a/turbo/generators/templates/core-package/dsr/eslint.config.js.hbs b/turbo/generators/templates/core-package/dsr/eslint.config.js.hbs new file mode 100644 index 0000000..7440d8f --- /dev/null +++ b/turbo/generators/templates/core-package/dsr/eslint.config.js.hbs @@ -0,0 +1,3 @@ +import baseConfig from "@repo/core-eslint/base"; + +export default baseConfig; diff --git a/turbo/generators/templates/core-package/dsr/package.json.hbs b/turbo/generators/templates/core-package/dsr/package.json.hbs new file mode 100644 index 0000000..59d8dce --- /dev/null +++ b/turbo/generators/templates/core-package/dsr/package.json.hbs @@ -0,0 +1,27 @@ +{ + "name": "@repo/core-dsr", + "version": "0.0.1", + "private": true, + "type": "module", + "exports": { + ".": "./src/index.ts" + }, + "scripts": { + "build": "tsc --noEmit", + "lint": "eslint .", + "typecheck": "tsc --noEmit", + "test": "vitest run --passWithNoTests" + }, + "dependencies": { + "@repo/core-shared": "workspace:*", + "zod": "^3.24.0" + }, + "devDependencies": { + "@repo/core-eslint": "workspace:*", + "@repo/core-testing": "workspace:*", + "@repo/core-typescript": "workspace:*", + "@vitest/coverage-v8": "^3.0.0", + "typescript": "^5.8.0", + "vitest": "^3.0.0" + } +} diff --git a/turbo/generators/templates/core-package/dsr/src/index.ts.hbs b/turbo/generators/templates/core-package/dsr/src/index.ts.hbs new file mode 100644 index 0000000..6041d37 --- /dev/null +++ b/turbo/generators/templates/core-package/dsr/src/index.ts.hbs @@ -0,0 +1,2 @@ +// placeholder — populated by story 06-core-dsr +export {}; diff --git a/turbo/generators/templates/core-package/dsr/tsconfig.json.hbs b/turbo/generators/templates/core-package/dsr/tsconfig.json.hbs new file mode 100644 index 0000000..8facef5 --- /dev/null +++ b/turbo/generators/templates/core-package/dsr/tsconfig.json.hbs @@ -0,0 +1,12 @@ +{ + "extends": "@repo/core-typescript/base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/turbo/generators/templates/core-package/dsr/turbo.json.hbs b/turbo/generators/templates/core-package/dsr/turbo.json.hbs new file mode 100644 index 0000000..dcb8fb3 --- /dev/null +++ b/turbo/generators/templates/core-package/dsr/turbo.json.hbs @@ -0,0 +1,4 @@ +{ + "extends": ["//"], + "tags": ["core"] +} diff --git a/turbo/generators/templates/core-package/dsr/vitest.config.ts.hbs b/turbo/generators/templates/core-package/dsr/vitest.config.ts.hbs new file mode 100644 index 0000000..2ee07c1 --- /dev/null +++ b/turbo/generators/templates/core-package/dsr/vitest.config.ts.hbs @@ -0,0 +1,9 @@ +import path from "node:path"; +import { mergeConfig } from "vitest/config"; +import { nodeVitestConfig } from "@repo/core-typescript/vitest.base.node"; + +export default mergeConfig(nodeVitestConfig, { + resolve: { + alias: { "@": path.resolve(__dirname, "./src") }, + }, +});