# DSAR Full Context > All generated markdown documentation pages flattened into one file. ## Included Pages - [Guides](https://dsar-sdk.dev/docs/guides): Task-oriented DSAR setup, lifecycle, deployment, and operational guides. - [Getting Started](https://dsar-sdk.dev/docs/guides/getting-started): This guide is the fastest way to run DSAR locally, inspect the HTTP contract, and make your first request through the runtime. - [Request Lifecycle](https://dsar-sdk.dev/docs/guides/request-lifecycle): This guide connects the DSAR lifecycle into one operator-facing and subject-facing workflow. - [Examples and Deployment](https://dsar-sdk.dev/docs/guides/examples-and-deployment): DSAR includes runnable examples for local development, integration experiments, and product embedding patterns. - [Package build metrics](https://dsar-sdk.dev/docs/guides/package-build-metrics): Compile times and bundle sizes for each package using tsdown v0.20.3 (rolldown v1.0.0-rc.3). Compile time = tsdown "Build complete" duration; bundle size = total file size in dist/ excluding source maps. - [Architecture Docs](https://dsar-sdk.dev/docs/architecture): These documents describe DSAR's runtime model, contract boundaries, package layout, and documentation guarantees. - [DSAR Auth Model](https://dsar-sdk.dev/docs/architecture/auth-model): DSAR now treats authentication as two separate runtime lanes: - [Backend Runtime Core (`dsarInstance`)](https://dsar-sdk.dev/docs/architecture/backend-runtime-core): This document captures T05 runtime boundaries, route surface, and error contract for integrators. - [API Contract Surface (T06)](https://dsar-sdk.dev/docs/architecture/api-contract-surface): This document defines the backend API contract source-of-truth and how OpenAPI/docs are produced. - [Adapter Contracts (T15 Foundation)](https://dsar-sdk.dev/docs/architecture/adapter-contracts): This document defines the provider-neutral adapter contract foundation for DSAR runtime integrations. - [Tenant-Safe Persistence (T07)](https://dsar-sdk.dev/docs/architecture/tenant-safe-persistence): This document records the T07 persistence shape, tenant ownership rules, and migration baseline. - [Policy Pack Specification](https://dsar-sdk.dev/docs/architecture/policy-pack-spec): This document defines the schema and evaluator contract for @dsar/policy-engine. - [Policy Versioning and Upgrades](https://dsar-sdk.dev/docs/architecture/policy-versioning-and-upgrades): This document defines the T04 policy lifecycle model for immutable versioning, scoped pinning, and approval-gated upgrades. - [Contracts and Versioning](https://dsar-sdk.dev/docs/architecture/contracts-and-versioning): This document defines the canonical contract taxonomy and semver policy for @dsar/schema. - [Error Code Architecture](https://dsar-sdk.dev/docs/architecture/error-codes): DSAR uses package-owned error catalogs with globally unique identifiers. - [Monorepo Packages and Conventions](https://dsar-sdk.dev/docs/architecture/monorepo-packages): This document defines the DSAR workspace package map, ownership, dependency rules, and conventions for adding packages. **Packages are created in their implementing tickets, not skeleton-first.** T01 establishes only the workspace and this documentation. - [Workspace Validation](https://dsar-sdk.dev/docs/architecture/workspace-validation): Run these from repo root after a clean clone. All commands must exit 0 with zero packages. - [Integrations](https://dsar-sdk.dev/docs/integrations): Integration guides for inbound channels plus auth, outbound, and adapter-specific setup. - [Inbound](https://dsar-sdk.dev/docs/integrations/inbound): DSAR uses inbound adapters to receive data subject access requests from external sources. Each adapter verifies webhook authenticity, normalises the payload into a canonical capture format, and routes it to the correct tenant and jurisdiction. - [Inbound Resend](https://dsar-sdk.dev/docs/integrations/inbound/resend): @dsar/inbound-resend accepts Resend email.received webhook events and maps them into canonical DSAR request capture input. Emails sent to configured addresses are automatically verified, routed, and captured as DSAR requests. - [Inbound Slack](https://dsar-sdk.dev/docs/integrations/inbound/slack): @dsar/inbound-slack accepts Slack webhook deliveries and maps them into canonical DSAR request capture input. Supports messages, slash commands, shortcuts, block actions, and modal submissions. - [Outbound Resend (`@dsar/outbound-resend`)](https://dsar-sdk.dev/docs/integrations/outbound/resend): @dsar/outbound-resend provides built-in outbound DSAR notifications using the Resend API. - [Storage Filesystem Adapter Integration](https://dsar-sdk.dev/docs/integrations/storage/filesystem): This document describes how to register and use @dsar/storage-filesystem with backend runtime. - [Storage S3 Adapter Integration](https://dsar-sdk.dev/docs/integrations/storage/s3): This document describes how to register and use @dsar/storage-s3 with backend runtime. - [Storage Vercel Blob Adapter Integration](https://dsar-sdk.dev/docs/integrations/storage/vercel-blob): This document describes how to register and use @dsar/storage-vercel-blob with backend runtime. - [Redis Integration](https://dsar-sdk.dev/docs/integrations/rate-limit/redis): Use @dsar/redis for Redis-backed DSAR runtime integrations. - [Upstash Integration](https://dsar-sdk.dev/docs/integrations/rate-limit/upstash): Use @dsar/upstash for Upstash-backed DSAR runtime integrations. - [Unkey Integration](https://dsar-sdk.dev/docs/integrations/auth/unkey): @dsar/auth-unkey is an optional helper package for the DSAR bearer-token lane. It does not replace DSAR's authorization or subject-ownership checks. - [Reference](https://dsar-sdk.dev/docs/reference): Reference docs for DSAR APIs, developer surfaces, storage, persistence, testing, and error catalogs. - [API Reference](https://dsar-sdk.dev/docs/reference/api): These pages describe the DSAR HTTP surface exposed by @dsar/backend. - [Status API](https://dsar-sdk.dev/docs/reference/api/status): Return the current runtime health payload. - [Init API](https://dsar-sdk.dev/docs/reference/api/init): Initialize the DSAR runtime context. - [Core Request API](https://dsar-sdk.dev/docs/reference/api/requests): This page covers the request lifecycle endpoints that are not already documented in the dedicated verification, manifest, delivery, appeals, audit, subject, and retention pages. - [Verification API](https://dsar-sdk.dev/docs/reference/api/verification): Verification endpoints are workflow controls inside DSAR. They are not a general-purpose login system for subject portals or dashboards. In production, the host application authenticates the end user first, then DSAR uses these verification routes only when policy or risk requires extra proof. - [Manifest API](https://dsar-sdk.dev/docs/reference/api/manifest): Get the fulfilment manifest for a request. - [Delivery API](https://dsar-sdk.dev/docs/reference/api/delivery): Transition a request from in_progress to fulfilled. This marks the DSAR as complete and triggers a request_fulfilled notification to the data subject. - [Appeals API](https://dsar-sdk.dev/docs/reference/api/appeals): Create an appeal for a request. - [Audit API](https://dsar-sdk.dev/docs/reference/api/audit): Export the immutable audit chain for a request. - [Subjects API](https://dsar-sdk.dev/docs/reference/api/subjects): Look up a subject profile by matching requests. - [Retention Policy API](https://dsar-sdk.dev/docs/reference/api/retention): List retention policies for a tenant. - [Policies API](https://dsar-sdk.dev/docs/reference/api/policies): These endpoints expose the policy catalog plus upgrade and custom-policy workflows. - [Webhooks API](https://dsar-sdk.dev/docs/reference/api/webhooks): These public endpoints accept inbound provider events and map them into DSAR intake flows. - [SDK and Runtime Modes](https://dsar-sdk.dev/docs/reference/developer/sdk-and-runtime): DSAR exposes several public surfaces depending on whether you are hosting the runtime, calling it, or abstracting over multiple environments. - [DSAR CLI](https://dsar-sdk.dev/docs/reference/developer/cli): @dsar/cli provides a command surface that maps to DSAR backend HTTP endpoints for agent and script usage. - [TSDoc Authoring Standard](https://dsar-sdk.dev/docs/reference/developer/tsdoc): This repository uses TSDoc to make public APIs self-documenting in editor hover, autocomplete, and generated declarations. - [Persistence](https://dsar-sdk.dev/docs/reference/persistence): DSAR uses persistence drivers to store request state, audit events, policy assignments, and all other domain records in a database. Each driver implements the same PersistenceDriver contract, so you can swap databases without changing application code. - [SQLite](https://dsar-sdk.dev/docs/reference/persistence/sqlite): @dsar/persistence-sqlite provides a SQLite driver for DSAR persistence. Supports Bun and Node runtimes with in-memory default for fast local development and testing. - [Postgres](https://dsar-sdk.dev/docs/reference/persistence/pg): @dsar/persistence-pg provides a Postgres driver for DSAR persistence with advisory-lock migration protection, connection pooling, and full domain record support. - [Storage](https://dsar-sdk.dev/docs/reference/storage): DSAR uses storage adapters to persist fulfilment artifacts — the files, documents, and data packages assembled during request processing. Each adapter implements the same StorageAdapterContract, so you can swap providers without changing application code. - [Filesystem Storage](https://dsar-sdk.dev/docs/reference/storage/filesystem): @dsar/storage-filesystem stores DSAR fulfilment artifacts on the local filesystem. Ideal for development, testing, and single-server deployments. - [S3 Storage](https://dsar-sdk.dev/docs/reference/storage/s3): @dsar/storage-s3 connects DSAR to any S3-compatible object store — AWS S3, MinIO, Cloudflare R2, DigitalOcean Spaces, and more. - [Vercel Blob Storage](https://dsar-sdk.dev/docs/reference/storage/vercel-blob): @dsar/storage-vercel-blob stores DSAR fulfilment artifacts in Vercel's managed blob storage service. Zero infrastructure setup when deploying on Vercel. - [Acceptance And Parity Readiness](https://dsar-sdk.dev/docs/reference/testing/acceptance-and-parity): This checklist turns the GA-readiness ticket work into a concrete release gate for the current DSAR repo state. - [DSAR-BE-1001: AUTH_ACTOR_CONTEXT_MISSING](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1001): The request targets a protected endpoint, but DSAR could not resolve an authenticated actor from bearer auth. - [DSAR-BE-1002: AUTH_APPROVER_ROLE_FORBIDDEN](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1002): The actor is authenticated but does not have the role required for an approver-only operation. - [DSAR-BE-1003: AUTH_REQUEST_ACCESS_FORBIDDEN](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1003): The caller is authenticated, but the resolved principal is not allowed to access the requested route or DSAR record. - [DSAR-BE-1101: REQUEST_BODY_INVALID_JSON](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1101): A handler expected JSON, but the request body could not be parsed. - [DSAR-BE-1102: REQUEST_ROUTE_PARAM_MISSING](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1102): A route parameter required by server-side handler logic is absent. - [DSAR-BE-1103: REQUEST_BASE_PATH_INVALID](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1103): Backend runtime was configured with an invalid `basePath`. - [DSAR-BE-1199: REQUEST_VALIDATION_FAILED](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1199): Request validation failed, but no narrower boundary reason code was attached. - [DSAR-BE-1200: REQUEST_RATE_LIMITED](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1200): A public intake endpoint exceeded a configured rate limit. - [DSAR-BE-1201: REQUEST_ROUTE_NOT_FOUND](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1201): No backend route is registered for the incoming method/path combination. - [DSAR-BE-1202: POLICY_ACTIVATION_NOT_FOUND](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1202): No active policy activation was found for the tenant/workspace scope. - [DSAR-BE-1203: POLICY_UPGRADE_PROPOSAL_NOT_FOUND](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1203): The requested policy upgrade proposal was not found for the current tenant/workspace scope. - [DSAR-BE-1204: DELIVERY_ARTIFACT_NOT_FOUND](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1204): No fulfilment artifact exists for the target request. Delivery operations require a fulfilment callback to have been recorded first. - [DSAR-BE-1205: DELIVERY_TOKEN_INVALID](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1205): The delivery token is missing, expired, or does not match the expected value. Delivery downloads and step-up challenge completions require a valid token. - [DSAR-BE-1206: MANIFEST_ARTIFACT_UPLOAD_FAILED](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1206): Upload of a fulfilment manifest artifact to storage failed. The file could not be persisted to the configured storage adapter. - [DSAR-BE-1207: MANIFEST_ARTIFACT_DOWNLOAD_FAILED](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1207): Download of a fulfilment manifest artifact from storage failed. The requested file could not be retrieved. - [DSAR-BE-1208: MANIFEST_ARTIFACT_REPLACE_FAILED](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1208): Replacement of an existing fulfilment manifest artifact failed. The artifact could not be overwritten in storage. - [DSAR-BE-1209: FULFILMENT_MANIFEST_NOT_APPROVED](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1209): The fulfilment endpoint requires an approved manifest before the request can transition to `fulfilled` status. The manifest's `validationState` is not `"approved"`. - [DSAR-BE-1210: FULFILMENT_NO_ARTIFACTS](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1210): A fulfilment guard determined that no artifacts exist in the manifest. This error is available for integrations or policy guards that require artifacts before fulfilment (e.g. access or portability requests). Request types that do not produce artifacts (deletion, rectification, restriction, objection) are not subject to this guard by default. - [DSAR-BE-1301: POLICY_JURISDICTION_UNMAPPED](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1301): No policy pack mapping exists for the requested jurisdiction. - [DSAR-BE-1302: POLICY_ENFORCEMENT_REFUSAL_BLOCKED](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1302): The active policy for this request does not permit refusal. The `refusalEligible` flag in the policy evaluation decision is `false`. - [DSAR-BE-1303: POLICY_UPGRADE_APPROVAL_REQUIRED](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1303): A policy upgrade must be approved before it can be applied. - [DSAR-BE-1304: RETENTION_CLASS_INVALID](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1304): The provided retention class is not a recognized value. Retention policies must target one of the predefined data classes. - [DSAR-BE-1401: LIFECYCLE_TRANSITION_DISALLOWED](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1401): The requested lifecycle action is not allowed from the request's current status. - [DSAR-BE-1402: LIFECYCLE_STATUS_UNKNOWN](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1402): The current lifecycle status value is not recognized by the transition state machine. - [DSAR-BE-1403: LIFECYCLE_RATIONALE_MISSING](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1403): The lifecycle action requires a non-empty rationale but none was provided. - [DSAR-BE-1410: PERSISTENCE_TENANT_SCOPE_MISSING](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1410): A backend persistence operation was attempted without the required tenant scope. Every database query must be scoped to a tenant to enforce data isolation. - [DSAR-BE-1411: PERSISTENCE_ENTITY_NOT_FOUND](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1411): A persistence lookup for a specific entity returned no results within the backend request pipeline. - [DSAR-BE-1412: PERSISTENCE_OPERATION_UNSUPPORTED](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1412): The persistence layer does not support the requested operation for the given entity or context within the backend request pipeline. - [DSAR-BE-1413: PERSISTENCE_INVALID_RECORD](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1413): A record retrieved from the database violates the expected domain contract (e.g. an enum field contains an unrecognised value). - [DSAR-BE-1414: PERSISTENCE_SQL_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1414): A raw SQL query executed by the persistence layer failed. - [DSAR-BE-1500: INTERNAL_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1500): An unhandled backend runtime exception occurred. - [DSAR-BE-1599: INTERNAL_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-be-1599): The runtime emitted an error code that is not present in the backend catalog and fell back to uncataloged handling. - [DSAR-CLI-1500: CLI_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-cli-1500): An unhandled CLI runtime exception occurred. - [DSAR-CLI-1599: CLI_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-cli-1599): The runtime emitted an error code that is not present in the CLI catalog and fell back to uncataloged handling. - [DSAR-CORE-1500: CORE_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-core-1500): An unhandled core runtime exception occurred. - [DSAR-CORE-1599: CORE_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-core-1599): The runtime emitted an error code that is not present in the core catalog and fell back to uncataloged handling. - [DSAR-FS-1001: STORAGE_FILESYSTEM_RETRY_EXHAUSTED](https://dsar-sdk.dev/docs/reference/errors/dsar-fs-1001): A filesystem storage operation failed after exhausting all configured retry attempts. - [DSAR-FS-1500: STORAGE_FILESYSTEM_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-fs-1500): An unhandled filesystem storage runtime exception occurred. - [DSAR-FS-1599: STORAGE_FILESYSTEM_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-fs-1599): The runtime emitted an error code that is not present in the filesystem storage catalog and fell back to uncataloged handling. - [DSAR-GRD-1500: GUARDS_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-grd-1500): An unhandled guards runtime exception occurred. - [DSAR-GRD-1599: GUARDS_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-grd-1599): The runtime emitted an error code that is not present in the guards catalog and fell back to uncataloged handling. - [DSAR-IN-1001: INBOUND_RESEND_CONTENT_FETCH_FAILED](https://dsar-sdk.dev/docs/reference/errors/dsar-in-1001): The inbound Resend adapter failed to retrieve the content of a received email from the Resend API. - [DSAR-IN-1500: INBOUND_RESEND_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-in-1500): An unhandled inbound Resend adapter runtime exception occurred. - [DSAR-IN-1599: INBOUND_RESEND_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-in-1599): The runtime emitted an error code that is not present in the inbound Resend catalog and fell back to uncataloged handling. - [DSAR-OUT-1001: OUTBOUND_RESEND_CONFIG_INVALID](https://dsar-sdk.dev/docs/reference/errors/dsar-out-1001): The outbound Resend adapter configuration failed validation. The adapter cannot initialize with the provided settings. - [DSAR-OUT-1500: OUTBOUND_RESEND_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-out-1500): An unhandled outbound Resend adapter runtime exception occurred. - [DSAR-OUT-1599: OUTBOUND_RESEND_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-out-1599): The runtime emitted an error code that is not present in the outbound Resend catalog and fell back to uncataloged handling. - [DSAR-PE-1500: POLICY_ENGINE_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-pe-1500): An unhandled policy engine runtime exception occurred. - [DSAR-PE-1599: POLICY_ENGINE_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-pe-1599): The runtime emitted an error code that is not present in the policy engine catalog and fell back to uncataloged handling. - [DSAR-PG-1500: PERSISTENCE_PG_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-pg-1500): An unhandled PostgreSQL persistence runtime exception occurred. - [DSAR-PG-1599: PERSISTENCE_PG_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-pg-1599): The runtime emitted an error code that is not present in the PostgreSQL persistence catalog and fell back to uncataloged handling. - [DSAR-PP-1001: POLICY_PACKS_CHECKSUM_FAILED](https://dsar-sdk.dev/docs/reference/errors/dsar-pp-1001): Computing a SHA-256 checksum for a policy pack failed. - [DSAR-PP-1500: POLICY_PACKS_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-pp-1500): An unhandled policy packs runtime exception occurred. - [DSAR-PP-1599: POLICY_PACKS_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-pp-1599): The runtime emitted an error code that is not present in the policy packs catalog and fell back to uncataloged handling. - [DSAR-PS-1001: PERSISTENCE_TENANT_SCOPE_MISSING](https://dsar-sdk.dev/docs/reference/errors/dsar-ps-1001): A persistence operation was attempted without the required tenant scope context. - [DSAR-PS-1002: PERSISTENCE_ENTITY_NOT_FOUND](https://dsar-sdk.dev/docs/reference/errors/dsar-ps-1002): A persistence lookup for a specific entity returned no results. - [DSAR-PS-1003: PERSISTENCE_OPERATION_UNSUPPORTED](https://dsar-sdk.dev/docs/reference/errors/dsar-ps-1003): The persistence layer does not support the requested operation for the given entity or context. - [DSAR-PS-1004: PERSISTENCE_INVALID_RECORD](https://dsar-sdk.dev/docs/reference/errors/dsar-ps-1004): A record retrieved from the database violates the expected domain contract (e.g. an enum field contains an unrecognised value). - [DSAR-PS-1500: PERSISTENCE_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-ps-1500): An unhandled persistence layer runtime exception occurred. - [DSAR-PS-1599: PERSISTENCE_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-ps-1599): The runtime emitted an error code that is not present in the persistence catalog and fell back to uncataloged handling. - [DSAR-S3-1500: STORAGE_S3_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-s3-1500): An unhandled S3 storage runtime exception occurred. - [DSAR-S3-1599: STORAGE_S3_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-s3-1599): The runtime emitted an error code that is not present in the S3 storage catalog and fell back to uncataloged handling. - [DSAR-SCH-1500: SCHEMA_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-sch-1500): An unhandled schema runtime exception occurred. - [DSAR-SCH-1599: SCHEMA_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-sch-1599): The runtime emitted an error code that is not present in the schema catalog and fell back to uncataloged handling. - [DSAR-SDK-1101: SDK_NETWORK_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-sdk-1101): The SDK could not complete the HTTP request due to a network-level failure. - [DSAR-SDK-1102: SDK_TIMEOUT](https://dsar-sdk.dev/docs/reference/errors/dsar-sdk-1102): The SDK HTTP request exceeded the configured timeout before completing. - [DSAR-SDK-1201: SDK_HTTP_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-sdk-1201): The server returned an HTTP error status (4xx or 5xx) that the SDK mapped to this code. - [DSAR-SDK-1301: SDK_INVALID_ENVELOPE](https://dsar-sdk.dev/docs/reference/errors/dsar-sdk-1301): The SDK received an HTTP response that could not be parsed as a valid error envelope. - [DSAR-SDK-1500: SDK_RETRY_FAILED](https://dsar-sdk.dev/docs/reference/errors/dsar-sdk-1500): The SDK exhausted retries and the request still failed. - [DSAR-SDK-1599: SDK_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-sdk-1599): The SDK emitted an error code that is not present in the SDK catalog and fell back to uncataloged handling. - [DSAR-SQL-1500: PERSISTENCE_SQLITE_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-sql-1500): An unhandled SQLite persistence runtime exception occurred. - [DSAR-SQL-1599: PERSISTENCE_SQLITE_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-sql-1599): The runtime emitted an error code that is not present in the SQLite persistence catalog and fell back to uncataloged handling. - [DSAR-VB-1001: STORAGE_VERCEL_BLOB_FETCH_FAILED](https://dsar-sdk.dev/docs/reference/errors/dsar-vb-1001): Fetching the binary payload of a Vercel Blob object failed after a successful `HEAD` request. - [DSAR-VB-1002: STORAGE_VERCEL_BLOB_RETRY_EXHAUSTED](https://dsar-sdk.dev/docs/reference/errors/dsar-vb-1002): A Vercel Blob storage operation failed after exhausting all configured retry attempts. - [DSAR-VB-1500: STORAGE_VERCEL_BLOB_RUNTIME_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-vb-1500): An unhandled Vercel Blob storage runtime exception occurred. - [DSAR-VB-1599: STORAGE_VERCEL_BLOB_UNCATALOGED_ERROR](https://dsar-sdk.dev/docs/reference/errors/dsar-vb-1599): The runtime emitted an error code that is not present in the Vercel Blob storage catalog and fell back to uncataloged handling. - [DSAR Docs](https://dsar-sdk.dev/docs): DSAR ships generated OpenAPI at GET /spec.json and interactive HTTP docs at GET /docs, but the markdown docs in this folder explain how the runtime, integrations, and request lifecycle fit together. - [Alpha Warning](https://dsar-sdk.dev/docs/_shared/alpha-warning): Shared alpha-status warning included across DSAR documentation pages. ## Content # Guides URL: https://dsar-sdk.dev/docs/guides Task-oriented DSAR setup, lifecycle, deployment, and operational guides. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. Task-oriented guides for setting up DSAR, understanding request flow, and shipping deployments. ## Guides * [Getting Started](./getting-started.md) for the fastest path to a working DSAR environment. * [Request Lifecycle](./request-lifecycle.md) for the end-to-end operator and subject workflow. * [Examples and Deployment](./examples-and-deployment.md) for runnable setups and deployment patterns. * [Package Build Metrics](./package-build-metrics.md) for package size and build output details. # Getting Started URL: https://dsar-sdk.dev/docs/guides/getting-started This guide is the fastest way to run DSAR locally, inspect the HTTP contract, and make your first request through the runtime. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This guide is the fastest way to run DSAR locally, inspect the HTTP contract, and make your first request through the runtime. ## Prerequisites * Bun `1.3+` * A local checkout of this workspace * One terminal for the runtime and one for callers such as the CLI or examples ## Fastest Local Path The quickest way to see the full surface is the kitchen-sink runtime plus the dashboard and subject-portal examples. ```sh bunx turbo run dev --filter=./examples/kitchen-sink --filter=./examples/dashboard --filter=./examples/subject-portal ``` Supporting example READMEs: * `examples/kitchen-sink/README.md` * `examples/dashboard/README.md` * `examples/subject-portal/README.md` ## Verify the Runtime Once the runtime is up, inspect these endpoints: * `GET /status` for health * `GET /spec.json` for the generated OpenAPI document * `GET /docs` for interactive HTTP reference If you mount DSAR at a base path such as `/api/v1`, the same endpoints become `/api/v1/status`, `/api/v1/spec.json`, and `/api/v1/docs`. ## Create Your First Request ### CLI ```sh dsar requests create --api-url http://kitchen-sink.localhost:1355/api/v1 ``` Use `DSAR_API_TOKEN` when your runtime expects machine access credentials. ### Node SDK ```ts import { createNodeSdk } from "@dsar/node-sdk"; const client = createNodeSdk({ baseUrl: "http://kitchen-sink.localhost:1355/api/v1", token: process.env.DSAR_API_TOKEN, }); const created = await client.requests.create({ intakeSource: { channel: "api", rawText: "Please provide my personal data.", receivedAt: new Date().toISOString(), }, jurisdiction: "eu", }); created.unwrap(); ``` ## Choose the Right Runtime Surface * `@dsar/backend`: embed the HTTP runtime into your own service * `@dsar/node-sdk`: call DSAR from server-side application code * `@dsar/cli`: script or explore the HTTP surface from the terminal * `@dsar/core`: select `managed`, `self-hosted`, `custom`, or `offline` client modes behind a stable application-facing contract See [SDK and Runtime Modes](../reference/developer/sdk-and-runtime.md) for the comparison. ## Next Steps * Read [Request Lifecycle](./request-lifecycle.md) for the end-to-end workflow * Use [API Reference](../reference/api) for endpoint details * Use [Integration Guides](../integrations/integrations) to wire auth, storage, and inbound/outbound adapters # Request Lifecycle URL: https://dsar-sdk.dev/docs/guides/request-lifecycle This guide connects the DSAR lifecycle into one operator-facing and subject-facing workflow. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This guide connects the DSAR lifecycle into one operator-facing and subject-facing workflow. ## Lifecycle Overview ```mermaid flowchart TD runtimeInit[RuntimeInit] --> intake[RequestIntake] intake --> review[QueueAndReview] review --> verification[VerificationIfNeeded] verification --> fulfilment[FulfilmentAndManifest] fulfilment --> delivery[DeliveryAndDownload] delivery --> appeals[AppealsIfRaised] delivery --> audit[AuditAndNotifications] appeals --> audit ``` ## 1. Initialize and Intake * `POST /init` bootstraps runtime initialization when your deployment expects an explicit init step. * `POST /requests` records a request from an intake payload. * `POST /requests/capture` captures the request and immediately returns due-date context in the lifecycle response. See [Init API](../reference/api/init.md) and [Core Request API](../reference/api/requests.md). ## 2. Review, Explain, and Enrich Operators typically use these endpoints while triaging the request: * `GET /requests` * `GET /requests/:id` * `GET /requests/:id/timeline` * `GET /requests/:id/clock/explain` * `PUT /requests/:id/requestor` * `POST /requests/:id/clarifications/request` * `POST /requests/:id/clarifications/receive` * `POST /requests/:id/extensions` * `POST /requests/:id/refusals` * `POST /requests/:id/acknowledgements` * `POST /requests/:id/closures` See [Core Request API](../reference/api/requests.md). ## 3. Verify Identity or Authority If policy or risk requires stronger proof: * `POST /requests/:id/authority/submit` * `POST /requests/:id/authority/approve` * `POST /requests/:id/authority/reject` * `POST /requests/:id/verification/request` * `POST /requests/:id/verification/evidence` * `POST /requests/:id/verification/evidence/upload` * `POST /requests/:id/verification/approve` * `POST /requests/:id/verification/reject` * `GET /requests/:id/verification-case` See [Verification API](../reference/api/verification.md). ## 4. Assemble the Fulfilment Package Once the request is moving toward completion: * `GET /requests/:id/manifest` * `POST /requests/:id/manifest/validate` * `POST /requests/:id/manifest/artifact/upload` * `GET /requests/:id/manifest/artifact/download` * `PUT /requests/:id/manifest/artifact/:artifactId/replace` * `POST /requests/:id/fulfilment` * `POST /requests/:id/fulfilment/callback` See [Manifest API](../reference/api/manifest.md) and [Delivery API](../reference/api/delivery.md). ## 5. Deliver and Track Access DSAR supports prepared delivery plus token-gated access: * `POST /requests/:id/delivery/prepare` * `POST /requests/:id/delivery/address/verify` * `POST /requests/:id/delivery/step-up/challenge` * `POST /requests/:id/delivery/step-up/complete` * `GET /requests/:id/artifacts/:artifactId/download` * `GET /requests/:id/delivery/logs` See [Delivery API](../reference/api/delivery.md). ## 6. Appeal, Audit, and Notifications After delivery, the request may still branch into follow-up workflows: * `POST /requests/:id/appeals` * `GET /requests/:id/appeals` * `POST /requests/:id/appeals/:appealId/decide` * `GET /requests/:id/audit/export` * `POST /requests/:id/audit/verify` * `GET /requests/:id/notifications` * `POST /requests/:id/notifications/:eventId/replay` See [Appeals API](../reference/api/appeals.md), [Audit API](../reference/api/audit.md), and [Core Request API](../reference/api/requests.md). ## Auth Reminder Verification routes are workflow controls, not a browser login system. Keep machine credentials on the server side and use trusted host identity projection for dashboard or portal experiences when the host product already authenticated the user. See [Auth Model](../architecture/auth-model.md). # Examples and Deployment URL: https://dsar-sdk.dev/docs/guides/examples-and-deployment DSAR includes runnable examples for local development, integration experiments, and product embedding patterns. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. DSAR includes runnable examples for local development, integration experiments, and product embedding patterns. ## Example Catalog |Example|Purpose|When to use it| |--|--|--| |`examples/kitchen-sink`|Full local runtime with SQLite, filesystem artifacts, and walkthrough scripts|Start here when you want broad lifecycle coverage fast| |`examples/dashboard`|Operator-facing Next.js app|Explore admin and operator flows| |`examples/subject-portal`|Subject-facing Next.js app|Explore request submission, verification, and appeals| |`examples/local-storage`|Runtime wired to filesystem storage|Validate local artifact persistence| |`examples/vercel-storage`|Runtime wired to Vercel Blob plus an upload demo|Validate Blob-backed artifact storage and demo uploads| ## Recommended Local Stack For the broadest local setup, run: ```sh bunx turbo run dev --filter=./examples/kitchen-sink --filter=./examples/dashboard --filter=./examples/subject-portal ``` Then use: * `http://kitchen-sink.localhost:1355/api/v1/status` * `http://kitchen-sink.localhost:1355/api/v1/spec.json` * `http://kitchen-sink.localhost:1355/api/v1/docs` * `http://dashboard.localhost:1355` * `http://subject-portal.localhost:1355` ## Deployment Patterns ### Self-Hosted Runtime Embed `@dsar/backend` into your own service, choose a persistence layer, then register storage, inbound, outbound, and auth integrations as needed. Start with: * [Backend Runtime Core](../architecture/backend-runtime-core.md) * [Integration Guides](../integrations/integrations) ### Server-Side Product Integration Use `@dsar/node-sdk` or `@dsar/core` from trusted backend code in your product. This is the preferred shape for dashboards, automation, and subject portals. ### Browser-Facing Portals Do not expose DSAR machine credentials in the browser. Authenticate the user in the host app first, then call DSAR from a server action, route handler, or backend service. See [Auth Model](../architecture/auth-model.md). ## Infrastructure Scope This workspace does not currently provide one canonical container or production infrastructure recipe. The examples are intended as composition references for runtime wiring, auth boundaries, and storage choices rather than turnkey production deployment manifests. See [Testing Acceptance and Parity](../reference/testing/acceptance-and-parity.md). # Package build metrics URL: https://dsar-sdk.dev/docs/guides/package-build-metrics Compile times and bundle sizes for each package using tsdown v0.20.3 (rolldown v1.0.0-rc.3). Compile time = tsdown "Build complete" duration; bundle size = total file size in dist/ excluding source maps. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. Compile times and bundle sizes for each package using tsdown v0.20.3 (rolldown v1.0.0-rc.3). Compile time = tsdown "Build complete" duration; bundle size = total file size in `dist/` excluding source maps. |Package|Compile|Bundle| |--|--|--| |@dsar/backend|2.25 s|246.4 KB| |@dsar/cli|2.73 s|38.7 KB| |@dsar/core|1.51 s|11.6 KB| |@dsar/guards|1.21 s|3.6 KB| |@dsar/inbound-resend|1.53 s|21.6 KB| |@dsar/internals-error-codes|—|— (src)| |@dsar/node-sdk|1.21 s|44.3 KB| |@dsar/outbound-resend|1.37 s|14.7 KB| |@dsar/persistence|1.35 s|55.4 KB| |@dsar/persistence-pg|1.22 s|2.4 KB| |@dsar/persistence-sqlite|1.34 s|3.0 KB| |@dsar/policy-engine|2.30 s|26.1 KB| |@dsar/policy-packs|2.34 s|57.4 KB| |@dsar/schema|1.39 s|37.0 KB| |@dsar/storage-filesystem|1.44 s|19.8 KB| |@dsar/storage-s3|1.64 s|26.9 KB| |@dsar/storage-vercel-blob|1.41 s|19.3 KB| |dsar|1.78 s|1.0 KB| **Totals:** 16 bundled packages, 628.2 KB combined bundle (excl. source maps, excl. `dsar` proxy re-exports; `@dsar/internals-error-codes` omitted because it is source-only). *Generated on 2026-02-26. Individual package builds (sequential, no turbo concurrency) for consistent timing. Bundler: tsdown v0.20.3 / rolldown v1.0.0-rc.3. Bundle sizes use actual file sizes (÷ 1024 for KB) excluding `.map` files.* ## Delta from previous measurement (2026-02-25) Compared against the tsdown column from the prior snapshot. |Package|Bundle (prev)|Bundle (now)|Δ| |--|--|--|--| |@dsar/backend|226.5 KB|246.4 KB|+8.8%| |@dsar/persistence|54.1 KB|55.4 KB|+2.4%| |@dsar/node-sdk|44.1 KB|44.3 KB|+0.5%| |All other packages|—|—|±0.0%| Only packages with measurable bundle-size changes are listed. The `dsar` proxy package is new (re-exports all subpackages). # Architecture Docs URL: https://dsar-sdk.dev/docs/architecture These documents describe DSAR's runtime model, contract boundaries, package layout, and documentation guarantees. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. These documents describe DSAR's runtime model, contract boundaries, package layout, and documentation guarantees. ## Runtime and Security * [Backend Runtime Core](./backend-runtime-core.md) * [Auth Model](./auth-model.md) * [Tenant-Safe Persistence](./tenant-safe-persistence.md) ## Contracts and Versioning * [API Contract Surface](./api-contract-surface.md) * [Contracts and Versioning](./contracts-and-versioning.md) * [Policy Pack Specification](./policy-pack-spec.md) * [Policy Versioning and Upgrades](./policy-versioning-and-upgrades.md) * [Adapter Contracts](./adapter-contracts.md) ## Workspace and Package Layout * [Monorepo Packages and Conventions](./monorepo-packages.md) * [Workspace Validation](./workspace-validation.md) ## Troubleshooting and Catalogs * [Error Code Architecture](./error-codes.md) For a docs-site entrypoint, return to [Docs Home](../). # DSAR Auth Model URL: https://dsar-sdk.dev/docs/architecture/auth-model DSAR now treats authentication as two separate runtime lanes: > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. DSAR now treats authentication as two separate runtime lanes: ## API-Key Access Use bearer auth for machine-to-machine traffic: * CLI * Node SDK * backend services * dashboard-to-DSAR calls * automation and partner integrations This lane is configured with: * `staticBearerTokens` for local development and simple self-hosting * `resolveBearerToken` for hosted or dynamic key verification ## Trusted Host Identity Use `resolveTrustedRequestIdentity` for user-facing portals where the host app already owns the login session. * The host authenticates the subject or operator. * The host normalizes that session into DSAR's request identity shape. * DSAR applies tenant scoping plus route authorization. This keeps DSAR out of the business of owning dashboard or subject login flows. ## Authorization Rules Authentication only proves who is calling. Authorization decides what they may do. * `operator` and `service` principals can use staff-only routes. * `subject` principals may only use subject-owned routes. * Subject-owned routes now enforce request ownership in the backend. * Protected routes fail closed when `tenantId` is missing. ## Deployment Defaults Hosted managed: * host-owned dashboard login * host-owned subject portal login * DSAR API keys for machine access * optional `@dsar/auth-unkey` for hosted bearer verification Simple self-hosted: * one tenant-scoped `DSAR_API_TOKEN` * optional extra demo tokens for local dashboard/subject examples Advanced self-hosted: * custom `resolveBearerToken` * optional `resolveTrustedRequestIdentity` # Backend Runtime Core (`dsarInstance`) URL: https://dsar-sdk.dev/docs/architecture/backend-runtime-core This document captures T05 runtime boundaries, route surface, and error contract for integrators. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This document captures T05 runtime boundaries, route surface, and error contract for integrators. ## Runtime usage * Factory: `dsarInstance(options)` * Primary boundary: `handler(request) => Promise` * Mounting: any fetch-compatible runtime (Workers, Bun, Node adapters) * Runtime internals: `@effect/platform` web handler boundary via `HttpApp.toWebHandler` * Runtime repo integration: `runtimeReposFromPersistence()` bridges `@dsar/persistence` into `RuntimeServicesTag` ## Route module map and ownership * `packages/backend/src/routes/init.ts` - runtime initialization surface * `packages/backend/src/routes/requests.ts` - request lifecycle and capability-upgrade route categories (stubbed in T05) * `packages/backend/src/routes/subjects.ts` - subject lookup placeholder surface * `packages/backend/src/routes/policies.ts` - policy upgrade placeholder surface * `packages/backend/src/routes/status.ts` - health/status surface Representative capability-upgrade paths mounted in T05: * `/requests/:id/clock/explain` * `/requests/:id/verification/*` * `/requests/:id/fulfilment/callback` * `/requests/:id/appeals*` * `/tenants/:tenantId/retention` * `/requests/:id/audit/export` ## Error envelope contract All errors follow: * `ok: false` * `error.id: string` (stable backend identifier, `DSAR-BE-xxxx`) * `error.code: string` (deterministic boundary code, e.g. `AUTH_ACTOR_CONTEXT_MISSING`, `REQUEST_VALIDATION_FAILED`, `REQUEST_ROUTE_NOT_FOUND`) * `error.docsUrl: string` (canonical link to error catalog entry) * `error.message: string` * `error.status: number` * `error.trace?: object` (safe metadata only) Canonical catalog: `docs/architecture/error-codes.md` ## Base path behavior * `options.basePath` normalizes trailing slashes. * Incoming request paths are stripped against `basePath` before route matching. * Non-matching base path requests return normalized `REQUEST_ROUTE_NOT_FOUND`. * Matching requests continue through shared auth/context handling and normalized envelope conversion. ## Contract and docs endpoints (T06) * Runtime exposes generated OpenAPI at `/spec.json`. * Runtime exposes interactive docs at `/docs`. * Both endpoints honor `basePath` mounting, e.g. `/api/v1/spec.json` and `/api/v1/docs`. * Spec generation is driven from `packages/backend/src/http-api/api.ts` HttpApi contracts. # API Contract Surface (T06) URL: https://dsar-sdk.dev/docs/architecture/api-contract-surface This document defines the backend API contract source-of-truth and how OpenAPI/docs are produced. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This document defines the backend API contract source-of-truth and how OpenAPI/docs are produced. ## Source of truth * Contract source: `packages/backend/src/http-api/api.ts` * Contract model: `@effect/platform` `HttpApi` * Schema source: `@dsar/schema` Effect schemas reused in endpoint payload/success shapes ## Generated surfaces * Machine-readable spec: `GET /spec.json` * Interactive docs: `GET /docs` Both endpoints are basePath-aware through `dsarInstance({ basePath })`. Examples: * root mount: * `/spec.json` * `/docs` * `basePath: "/api/v1"`: * `/api/v1/spec.json` * `/api/v1/docs` ## Security declaration model * OpenAPI security scheme name: `BearerAuth` * Scheme type: `http` bearer * Protected operations declare bearer security via OpenAPI overrides. * Public operations (`/init`, `/status`) explicitly set empty security requirements. ## Drift guard strategy * `packages/backend/test/openapi.test.ts` validates: * spec endpoint returns OpenAPI 3.1.0 JSON * required capability-upgrade paths exist * bearer security scheme exists * docs endpoint includes basePath-aware spec URL * snapshot for spec stability (`toMatchSnapshot`) This keeps SDK generation inputs and developer docs aligned with route contracts. # Adapter Contracts (T15 Foundation) URL: https://dsar-sdk.dev/docs/architecture/adapter-contracts This document defines the provider-neutral adapter contract foundation for DSAR runtime integrations. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This document defines the provider-neutral adapter contract foundation for DSAR runtime integrations. ## Goals * Keep DSAR core runnable with **zero adapters registered** * Isolate adapter failures so core request handling remains stable * Normalize provider-specific failures into a consistent contract * Enable independent child-ticket delivery (`T15B`, `T15C`, `T15D`) ## Contract Modules * `packages/backend/src/adapters/contract.ts` * capability types: `notifications`, `storage`, `inbound` * lifecycle hooks: `validateConfig`, `init`, `healthCheck`, `diagnostics` * capability-specific invocation surfaces * `packages/backend/src/adapters/errors.ts` * normalized error model (`AdapterInvocationError`) * retriable classification for retry policies * `packages/backend/src/adapters/registry.ts` * adapter registration/resolution * capability lookups and health summaries * `packages/backend/src/adapters/events.ts` * operational event contract for adapter failures (`adapter_failure`) ## Runtime Integration Runtime adapter bindings are transformed into registry entries at `dsarInstance` construction time. Services resolve adapters via the registry and can still operate with fallback behavior when no adapter is available. This enforces T15/T09 MVP behavior: * notification **generation** is mandatory * notification **delivery** is best-effort and may fail independently * delivery attempts can resolve to `delivered`, `failed`, or `skipped` (for disabled/unconfigured optional channels) ## Error Normalization Matrix * Timeout/connection/rate-limit patterns map to retriable categories * Auth/config/validation issues map to non-retriable categories * Unknown failures are represented explicitly as `unknown` ## Child Ticket Guidance * `T15B` (`@dsar/storage-s3`): implement `storage` contract conformance * `T15C` (`@dsar/outbound-resend`): implement `notifications` contract conformance * `T15D` (`@dsar/inbound-resend`): reference implementation for inbound contract All implementations should pass shared tests in: * `packages/backend/test/adapters/conformance/contract.test.ts` # Tenant-Safe Persistence (T07) URL: https://dsar-sdk.dev/docs/architecture/tenant-safe-persistence This document records the T07 persistence shape, tenant ownership rules, and migration baseline. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This document records the T07 persistence shape, tenant ownership rules, and migration baseline. ## Runtime model * Package: `@dsar/persistence` * Storage abstraction: `@effect/sql` * Driver packages: * SQLite: `@dsar/persistence-sqlite` * Postgres: `@dsar/persistence-pg` * Scope enforcement: mandatory `TenantContext` service ## Tenant ownership map All tenant-owned records include `tenant_id` and must be queried with tenant scope: * `requests` * `request_clock_segments` * `request_timeline_events` * `policy_assignments` * `verification_evidence` * `fulfillment_artifacts` * `retention_policies` * `audit_events` ## Repository boundary Repositories are exposed only through the `Persistence` Effect service: * requests * timeline * policyAssignments * verificationEvidence * fulfillmentArtifacts * retentionPolicies * auditEvents Direct SQL usage outside this package is out of scope by convention. ## Migration manifest * `0001_initial` - creates tenant-safe tables and baseline indexes for T07 entities. ## Rollback notes * Current migration strategy is forward-only for MVP. * Rollback in development/test is performed by dropping the SQLite file and re-applying migrations. * Postgres startup keeps migration execution in runtime, with advisory lock coordination to avoid concurrent migration runners. # Policy Pack Specification URL: https://dsar-sdk.dev/docs/architecture/policy-pack-spec This document defines the schema and evaluator contract for @dsar/policy-engine. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This document defines the schema and evaluator contract for `@dsar/policy-engine`. ## Policy pack schema Policy packs are versioned, machine-readable contracts with deterministic sections: * `packId`, `version`, `jurisdiction`, `effectiveAt` * `sections.clock` * `sections.representation` * `sections.verification` * `sections.response` * `sections.delivery` * `sections.appeals` * `sections.retention` * `sections.audit` ### Clock section Required fields: * `start`: `"receipt" | "verification_complete"` * `verificationEffect`: `"stop_clock" | "no_stop_clock"` * `clarificationEffect`: `"stop_clock" | "no_stop_clock"` * `ackRequired`: `boolean` * `ackDeadlineBusinessDays?`: `number` * `responseDeadlineDays`: `number` * `extension`: `{ enabled, maxAdditionalDays, requiresJustification }` * `rules`: deterministic override rules with `id`, `precedence`, `when`, `apply` Rule precedence is deterministic: 1. sort by `precedence` descending 2. tie-break by `id` ascending 3. apply merged rule overrides from lowest to highest precedence so highest precedence wins ## Evaluator interface `evaluatePolicy(input)` returns an Effect program with deterministic output. Input envelope includes: * policy pack payload * jurisdiction + policy version * request type and requestor type * authority evidence signal * timeline context (`receivedAt`, `now`, pauses, extensions) * actor/context signals (`isComplex`, `requiresVerification`) Output envelope includes: * `decision`: actionable booleans (verification required, appeal eligibility, etc.) * `clock`: base/final deadlines and applied pause/extension contributions * `requiredActions` * `requiredNotices` * `matchedRuleIds` * `explainabilityTrace` ## Explainability trace contract Every decision includes machine-readable trace entries with: * `code` (`clock.base`, `clock.rule.applied`, `clock.pause.applied`, `clock.extension.applied`, `clock.final`) * `message` * optional `details` payload This enables replay and clock explain APIs to show exactly how due dates were produced. ## Fixture matrix Current fixture coverage: * `uk-access` * `eu-clarification-pause` * `us-no-stop-verification` * `edge-repeated-clarifications` * `edge-extension-near-deadline` * `edge-partial-refusal-precedence` * `policy-packs/uk-deadline-baseline` * `policy-packs/eu-clarification-vs-verification` * `policy-packs/us-extension-cap` * `policy-packs/us-co-high-risk-verification` * `policy-packs/us-va-refusal-appeal` These vectors validate: * deterministic outputs * precedence behavior * stop-clock / no-stop-clock behavior * extension cap handling * explainability trace shape and stable ordering ## Launch catalog and known gaps First-party launch coverage includes: * UK baseline pack (`uk`) * EU baseline pack (`eu`) * Initial US set: baseline US (`us`), California (`us-ca`), Virginia (`us-va`), Colorado (`us-co`) Known gaps: * Additional US state packs are not yet implemented in the launch catalog. * State-specific refusal categories and exemptions remain future additions. ## Jurisdiction hard-gate contract Request intake now requires a top-level `jurisdiction` and resolves an active policy via: 1. workspace/tenant scoped pin (if present) 2. latest available pack for the same jurisdiction 3. hard-fail with `POLICY_JURISDICTION_UNMAPPED` when no mapping exists The hard-fail envelope includes structured guidance so clients can route users/admins: * `subject_contact_admin` * `admin_register_policy_pack` * `admin_activate_policy_pack` ## Custom policy lifecycle events Custom policy authoring and activation emit dedicated policy audit events: * `custom_policy_registered` * `custom_policy_activated` * `custom_policy_deactivated` These events are emitted by `@dsar/policy-packs` services and consumed by backend policy routes. # Policy Versioning and Upgrades URL: https://dsar-sdk.dev/docs/architecture/policy-versioning-and-upgrades This document defines the T04 policy lifecycle model for immutable versioning, scoped pinning, and approval-gated upgrades. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This document defines the T04 policy lifecycle model for immutable versioning, scoped pinning, and approval-gated upgrades. ## Components * `@dsar/policy-packs`: Registry, pinning resolution, legal-impact diffing, proposal workflow, and audit events. * `@dsar/backend`: Route handler stubs for `propose`, `approve`, and `apply` operations. ## Lifecycle 1. Publish policy version into immutable registry (`name`, `jurisdiction`, `version`, `checksum`, `publishedAt`). 2. Propose tenant/workspace upgrade from `fromVersion` to `toVersion`. 3. Review categorized diff output (deadline/verification/appeals/retention/communication). 4. Approver with role `admin` or `compliance_admin` approves proposal. 5. Apply atomically updates pin to target version and emits audit event. ## Diff Expectations Diff output includes: * deadline-impacting clock changes (base deadline, clarification/verification pause semantics, extension allowances) * verification requirements and delete-after-processing behavior * appeals requirements and deadlines * retention minimum changes for key artefact classes * communication requirements (for example manifest requirement changes) `clockBehaviorSummary` is included for approval/apply visibility and audit traceability. # Contracts and Versioning URL: https://dsar-sdk.dev/docs/architecture/contracts-and-versioning This document defines the canonical contract taxonomy and semver policy for @dsar/schema. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This document defines the canonical contract taxonomy and semver policy for `@dsar/schema`. ## Type taxonomy and stability |Domain|Contract examples|Stability| |--|--|--| |Request|`Request`, `RequestType`, `RequestStatus`, `IntakeSource`, `Requestor`, `Authority`, `CapturedIntake`|Public-stable| |Policy|`PolicyPackVersion`, `JurisdictionCode`, `RequestClock`, `ClockSegment`|Public-stable| |Verification|`VerificationLevel`, `VerificationCase`|Public-stable| |Fulfillment|`FulfillmentArtifact`, `ArtifactManifest`, `FulfillmentManifest`, `RefusalReasonCode`|Public-stable| |Delivery|`DeliveryPackage` and delivery challenge/log contracts|Public-stable| |Appeals|`Appeal`|Public-stable| |Retention|`RetentionPolicy`|Public-stable| |Audit/Event|`AuditEvent`, lifecycle transition contracts|Public-stable| |Internal|helper metadata and utility schemas used to support public contracts|Internal-evolving| ## Semver contract policy * Additive fields and additive enum members are **minor** changes. * Renaming or removing fields is a **major** change. * Contract behavior changes (same shape, different semantics) require migration notes and are treated as **major** unless explicitly backward compatible. * Optional metadata fields should be used when extension points are required without breaking public contracts. ## Lifecycle transition contract `LifecycleTransition` is the canonical transition payload and includes: * state movement: `from`, `to` * rationale: `reasonCode`, optional `rationale` * accountability: optional `actor` * temporal context: `occurredAt` * legal clock mutation details: optional `legalClockMutation` * approval linkage: optional `approval` This contract is shared by backend runtime, audit/event pipelines, and downstream SDK/CLI workflows. ## Public export map All public symbols are exported from `@dsar/schema` (and mirrored via `@dsar/schema/types` for type-path compatibility): * Request contracts: `RequestSchema`, `Request`, `RequestType`, `RequestStatus`, `IntakeSource`, `Requestor`, `Authority`, `CapturedIntake`. * Policy/clock contracts: `PolicyPackVersion`, `JurisdictionCode`, `RequestClock`, `ClockSegment`. * Verification contracts: `VerificationCase`, `VerificationLevel`. * Fulfillment contracts: `FulfillmentArtifact`, `ArtifactManifest`, `FulfillmentManifest`, `RefusalReasonCode`. * Delivery contracts: `DeliveryPackage` and delivery challenge/log schemas. * Appeals contracts: `Appeal`. * Retention contracts: `RetentionPolicy`. * Audit contracts: `AuditEvent`, hash-chain fields (`prevHash`, `hash`, `hashAlg`, `sequence`). * Cross-cutting contracts: `LifecycleTransition`, `ErrorEnvelope`, `ResponseMetadata`. ## Example payloads ### Request payload (MVP intake provenance) ```json { "id": "req_1", "type": "access", "status": "captured", "intakeSource": { "type": "portal", "receivedAt": "2026-02-17T12:00:00.000Z" }, "subject": { "subjectId": "sub_1" }, "createdAt": "2026-02-17T12:00:00.000Z", "updatedAt": "2026-02-17T12:00:00.000Z" } ``` ### VerificationCase payload (MVP) ```json { "id": "ver_1", "method": "email_link", "status": "pending", "requestedAt": "2026-02-17T12:00:00.000Z", "pauseClock": true } ``` ### FulfillmentManifest payload (MVP) ```json { "artifacts": [ { "id": "artifact_1", "type": "profile_data", "title": "Profile export", "mediaType": "application/json", "sizeBytes": 1024, "sourceSystem": "core-db", "sha256": "abc123" } ], "dataCategories": ["profile"], "redactionsApplied": [], "thirdPartyExclusions": [] } ``` # Error Code Architecture URL: https://dsar-sdk.dev/docs/architecture/error-codes DSAR uses package-owned error catalogs with globally unique identifiers. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. DSAR uses package-owned error catalogs with globally unique identifiers. * Each package owns its catalog in `src/types/error-codes.ts`. * `@dsar/internals-error-codes` is factory-only (`createErrorRegistry`, `createErrorCodeSchema`, and shared types). * Docs coverage and ID uniqueness are validated by `scripts/check-error-doc-coverage.mjs`. ## Namespace Registry |package|id prefix|fallback code example| |--|--|--| |`@dsar/backend`|`DSAR-BE-*`|`INTERNAL_UNCATALOGED_ERROR`| |`@dsar/node-sdk`|`DSAR-SDK-*`|`SDK_UNCATALOGED_ERROR`| |`@dsar/cli`|`DSAR-CLI-*`|`CLI_UNCATALOGED_ERROR`| |`@dsar/core`|`DSAR-CORE-*`|`CORE_UNCATALOGED_ERROR`| |`@dsar/policy-engine`|`DSAR-PE-*`|`POLICY_ENGINE_UNCATALOGED_ERROR`| |`@dsar/policy-packs`|`DSAR-PP-*`|`POLICY_PACKS_UNCATALOGED_ERROR`| |`@dsar/persistence`|`DSAR-PS-*`|`PERSISTENCE_UNCATALOGED_ERROR`| |`@dsar/persistence-pg`|`DSAR-PG-*`|`PERSISTENCE_PG_UNCATALOGED_ERROR`| |`@dsar/persistence-sqlite`|`DSAR-SQL-*`|`PERSISTENCE_SQLITE_UNCATALOGED_ERROR`| |`@dsar/storage-s3`|`DSAR-S3-*`|`STORAGE_S3_UNCATALOGED_ERROR`| |`@dsar/storage-filesystem`|`DSAR-FS-*`|`STORAGE_FILESYSTEM_UNCATALOGED_ERROR`| |`@dsar/storage-vercel-blob`|`DSAR-VB-*`|`STORAGE_VERCEL_BLOB_UNCATALOGED_ERROR`| |`@dsar/inbound-resend`|`DSAR-IN-*`|`INBOUND_RESEND_UNCATALOGED_ERROR`| |`@dsar/outbound-resend`|`DSAR-OUT-*`|`OUTBOUND_RESEND_UNCATALOGED_ERROR`| |`@dsar/guards`|`DSAR-GRD-*`|`GUARDS_UNCATALOGED_ERROR`| |`@dsar/schema`|`DSAR-SCH-*`|`SCHEMA_UNCATALOGED_ERROR`| ## Backend Catalog The canonical backend catalog is emitted by `@dsar/backend` from `packages/backend/src/types/error-codes.ts`. ## Backend Envelope fields All non-success responses include: * `error.id` - stable backend error identifier (`DSAR-BE-xxxx`) * `error.code` - semantic machine-readable code * `error.docsUrl` - canonical documentation link for the identifier (`https://dsar-sdk.dev/errors/dsar-be-xxxx`) * `error.message` - human-readable summary * `error.status` - HTTP status * `error.trace` - optional diagnostics-only payload (e.g. `trace.lifecycle` for transition errors) ## Catalog |id|code|status|meaning|retriable|docs| |--|--|--|--|--|--| |`DSAR-BE-1001`|`AUTH_ACTOR_CONTEXT_MISSING`|`401`|Required actor header is missing on a protected endpoint.|no|`docs/errors/dsar-be-1001.md`| |`DSAR-BE-1002`|`AUTH_APPROVER_ROLE_FORBIDDEN`|`403`|Actor role is not allowed to perform an approver action.|no|`docs/errors/dsar-be-1002.md`| |`DSAR-BE-1101`|`REQUEST_BODY_INVALID_JSON`|`400`|Request body cannot be parsed as valid JSON.|no|`docs/errors/dsar-be-1101.md`| |`DSAR-BE-1102`|`REQUEST_ROUTE_PARAM_MISSING`|`400`|A route parameter required by the handler is missing.|no|`docs/errors/dsar-be-1102.md`| |`DSAR-BE-1103`|`REQUEST_BASE_PATH_INVALID`|`400`|Runtime base path configuration is invalid.|no|`docs/errors/dsar-be-1103.md`| |`DSAR-BE-1199`|`REQUEST_VALIDATION_FAILED`|`400`|Request validation failed without a narrower boundary tag.|no|`docs/errors/dsar-be-1199.md`| |`DSAR-BE-1201`|`REQUEST_ROUTE_NOT_FOUND`|`404`|Incoming path/method does not map to any registered route.|no|`docs/errors/dsar-be-1201.md`| |`DSAR-BE-1202`|`POLICY_ACTIVATION_NOT_FOUND`|`404`|No active policy activation was found for the given scope.|no|`docs/errors/dsar-be-1202.md`| |`DSAR-BE-1203`|—|—|Reserved (unassigned).|—|—| |`DSAR-BE-1204`|`DELIVERY_ARTIFACT_NOT_FOUND`|`404`|No fulfilment artifact exists for the target request.|no|`docs/errors/dsar-be-1204.md`| |`DSAR-BE-1205`|`DELIVERY_TOKEN_INVALID`|`403`|Delivery token is missing, expired, or does not match.|no|`docs/errors/dsar-be-1205.md`| |`DSAR-BE-1206`|`MANIFEST_ARTIFACT_UPLOAD_FAILED`|`400`|Manifest artifact upload failed.|no|`docs/errors/dsar-be-1206.md`| |`DSAR-BE-1207`|`MANIFEST_ARTIFACT_DOWNLOAD_FAILED`|`404`|Manifest artifact download failed.|no|`docs/errors/dsar-be-1207.md`| |`DSAR-BE-1208`|`MANIFEST_ARTIFACT_REPLACE_FAILED`|`400`|Manifest artifact replacement failed.|no|`docs/errors/dsar-be-1208.md`| |`DSAR-BE-1209`|`FULFILMENT_MANIFEST_NOT_APPROVED`|`409`|Manifest must be approved before fulfilling.|no|`docs/errors/dsar-be-1209.md`| |`DSAR-BE-1210`|`FULFILMENT_NO_ARTIFACTS`|`409`|At least one artifact required to fulfil.|no|`docs/errors/dsar-be-1210.md`| |`DSAR-BE-1301`|`POLICY_JURISDICTION_UNMAPPED`|`400`|No policy pack is mapped to the provided jurisdiction.|no|`docs/errors/dsar-be-1301.md`| |`DSAR-BE-1302`|`POLICY_ENFORCEMENT_REFUSAL_BLOCKED`|`403`|Refusal blocked by active policy.|no|`docs/errors/dsar-be-1302.md`| |`DSAR-BE-1303`|—|—|Reserved (unassigned).|—|—| |`DSAR-BE-1304`|`RETENTION_CLASS_INVALID`|`400`|Provided retention class is not a recognized value.|no|`docs/errors/dsar-be-1304.md`| |`DSAR-BE-1401`|`LIFECYCLE_TRANSITION_DISALLOWED`|`409`|Requested lifecycle action is not allowed in current state.|no|`docs/errors/dsar-be-1401.md`| |`DSAR-BE-1402`|`LIFECYCLE_STATUS_UNKNOWN`|`409`|Current lifecycle status value is unknown/unsupported.|no|`docs/errors/dsar-be-1402.md`| |`DSAR-BE-1403`|`LIFECYCLE_RATIONALE_MISSING`|`400`|Lifecycle transition requires a non-empty rationale.|no|`docs/errors/dsar-be-1403.md`| |`DSAR-BE-1500`|`INTERNAL_RUNTIME_ERROR`|`500`|Unhandled backend runtime exception.|yes|`docs/errors/dsar-be-1500.md`| |`DSAR-BE-1599`|`INTERNAL_UNCATALOGED_ERROR`|`500`|Runtime emitted an unknown code; fallback mapping applied.|yes|`docs/errors/dsar-be-1599.md`| ## Logging behavior `toErrorResponse` (in `packages/backend/src/middleware/errors.ts`) logs all mapped and unmapped errors server-side using structured logs including: * `id` * `code` * `status` * `docsUrl` * `request` (method, path, query, sanitized headers, optional body preview) * sanitized `error` payload (only `name`, `message`, `code`, and `stack` in development) ### Header and query redaction Sensitive headers (`authorization`, `cookie`, `proxy-authorization`, `set-cookie`, `x-api-key`) are replaced with `[REDACTED]` before logging. Query parameters matching sensitive names (`token`, `secret`, `password`, `api_key`, `apikey`, `auth`, `access_token`, `key`) are also redacted. ### Body preview limits Request body previews use two related constants: `BODY_PREVIEW_LIMIT` (default **4096 bytes**) is the maximum number of bytes included in the preview text, and `BODY_PREVIEW_MAX_BYTES` (`BODY_PREVIEW_LIMIT + 1`) is the stream read cap that reads one extra byte to detect whether the body was truncated. Bodies exceeding the limit are either: * omitted with a descriptive message when `content-length` declares a size beyond `BODY_PREVIEW_LIMIT`, or * truncated after streaming up to `BODY_PREVIEW_MAX_BYTES` with a `truncated: true` flag in the log payload. Binary content types (`application/octet-stream`, `multipart/form-data`) are excluded entirely with `[binary content omitted]`. GET and HEAD requests skip body capture. # Monorepo Packages and Conventions URL: https://dsar-sdk.dev/docs/architecture/monorepo-packages This document defines the DSAR workspace package map, ownership, dependency rules, and conventions for adding packages. **Packages are created in their implementing tickets, not skeleton-first.** T01 establishes only the workspace and this documentation. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This document defines the DSAR workspace package map, ownership, dependency rules, and conventions for adding packages. **Packages are created in their implementing tickets, not skeleton-first.** T01 establishes only the workspace and this documentation. ## Package map and ownership |Package|Purpose| |--|--| |`dsar`|Umbrella package with subpath exports for runtime, SDK, CLI, storage, inbound, outbound, and auth helpers| |`@dsar/backend`|Backend runtime, OpenAPI surface, and HTTP route groups| |`@dsar/core`|Stable application-facing client contract with `managed` and `self-hosted` HTTP-backed modes, `custom` handler-driven mode, and `offline` fixture-backed mode; see [docs/developer/sdk-and-runtime.md](../reference/developer/sdk-and-runtime.md)| |`@dsar/node-sdk`|Typed server-side SDK for the DSAR HTTP API| |`@dsar/cli`|Terminal interface and parity layer over backend endpoints| |`@dsar/auth-unkey`|Optional Unkey-backed bearer verification for machine access credentials| |`@dsar/persistence`|Tenant-safe persistence services and repository contracts| |`@dsar/persistence-pg`|PostgreSQL persistence implementation| |`@dsar/persistence-sqlite`|SQLite persistence implementation| |`@dsar/storage-filesystem`|Local filesystem artifact storage adapter| |`@dsar/storage-s3`|S3-backed artifact storage adapter| |`@dsar/storage-vercel-blob`|Vercel Blob artifact storage adapter| |`@dsar/inbound-resend`|Inbound Resend webhook intake adapter| |`@dsar/inbound-slack`|Inbound Slack webhook intake adapter| |`@dsar/outbound-resend`|Outbound Resend notification adapter| |`@dsar/schema`|Canonical domain model, Effect schemas, and shared TypeScript types| |`@dsar/policy-engine`|Policy evaluator interfaces and contracts| |`@dsar/policy-packs`|Policy registry, pinning, diffing, and upgrade flows| All packages live under `packages/*` and are created when their implementing ticket ships. Do not add empty package stubs in advance. Runnable product examples live under `examples/*`, including `kitchen-sink`, `dashboard`, `subject-portal`, `local-storage`, and `vercel-storage`. ## Effect-based packages and convention The following are implemented with [Effect](https://effect.website/): runtime, services, and (where applicable) SDK/CLI internals. * **`@dsar/backend`** — HTTP via `@effect/platform` (HttpApi, HttpServer, HttpRouter); route handlers are Effect programs. * **`@dsar/auth-unkey`** — Optional hosted bearer-verification helper consumed by runtime auth configuration. * **Lifecycle and audit** (T08, T09) — Durable workflows, audit pipeline, notification events. * **`@dsar/policy-engine`** — Policy evaluation as Effect services. * **`@dsar/persistence`** (T07) — DB and repository layer as Effect Layers. * **Adapter layer and all adapter packages** (T15, T15B–D) — Vendor-neutral adapters as Effect services. * **Internally:** `@dsar/node-sdk`, `@dsar/cli`, `@dsar/core` use Effect for internals; public API can be Promise-based with Effect run at the boundary. **Conventions:** * Run Effect at the **boundary** (e.g. `Effect.runPromise`) when exposing to Node or HTTP. * Provide shared dependencies (DB, adapters, config) via **Layers**; avoid global mutable state. * Use Effect for **typed errors** and **retries**; do not swallow errors as untyped `any`. * **CLI:** Use `@effect/cli` (Command, Args, Options, CliApp) for type-safe commands and help. * **Durable workflows:** Use `@effect/workflow` (Workflow, Activity, DurableClock, etc.) where lifecycle, fulfilment, or notifications need long-running or retriable steps. ## Public API responsibility (per package) * **`@dsar/schema`** — Exports only: Effect schemas, inferred TS types, and versioned contract types. No runtime behaviour. * **`@dsar/policy-engine`** — Evaluator interface and policy pack types; no pack implementations. * **`@dsar/policy-packs`** — Registry/pinning/diff/upgrade flows and policy lifecycle audit records. * **`@dsar/backend`** — HTTP server, routes, and backend-only services; does not depend on UI or dashboard packages. * **`@dsar/auth-unkey`** — Optional helper for mapping verified Unkey keys into DSAR request identities. * **`@dsar/core`** — Shared engine and client logic; consumed by SDK and CLI. * **`@dsar/node-sdk`** — Node-facing API (Promise/async) that wraps Effect programs; exports for programmatic use. * **`@dsar/cli`** — CLI entrypoint and commands; uses core and SDK where appropriate. * **Adapters** — Vendor-neutral interfaces in the adapter layer; each adapter package implements one or more adapters. ## Dependency rules * **Allowed directions** * **`@dsar/schema`** may be imported by any other package (foundational). * **`@dsar/policy-engine`** may be used by backend, policy-packs, core, and adapters where policy evaluation is needed. * **Backend** must not import UI/dashboard or portal packages. * **`@dsar/auth-unkey`** may depend on vendor SDKs but stays optional and must not become a required runtime dependency for self-hosted DSAR setups. * **SDK and CLI** may depend on schema, core, and (where appropriate) backend client or types; they must not depend on UI packages. * **Adapters** depend on schema and adapter contracts; they must not depend on backend HTTP or UI. * **Exports-only usage**\ Packages must consume each other only via **public exports** (declared in `package.json` `exports`). No deep imports into internal paths (e.g. `@dsar/schema/src/private`). * **Guardrails**\ When packages exist, enforce dependency direction and exports-only usage via lint rules or CI (e.g. no `backend` → UI imports, no cross-package deep imports). ## No-skeleton rule Packages are **not** created in T01. Each package is created in the ticket that implements it (e.g. T02 creates `@dsar/schema`). Do not add empty `packages/*` directories or stub `package.json` files before implementation. ## Package creation checklist When an implementing ticket adds a new package under `packages/`, it must: 1. **`package.json`** — Name (e.g. `@dsar/schema`), `version`, `type: "module"`, `exports`, and scripts: `build`, `typecheck`, `test`, `lint`, `format` as required by the root Turborepo pipeline. 2. **`src/index.ts`** — Main entry; re-export public API only. 3. **`tsconfig.json`** — Extends root `tsconfig.base.json` (e.g. `"extends": "../../tsconfig.base.json"`), with `include`, `compilerOptions.rootDir`/`outDir` set for that package. Use strict and ESM-compatible settings from the base. 4. **`README.md`** — Short description, usage, and (if applicable) link to docs. 5. **Scripts** — Implement the same task names as in root `turbo.json` (`build`, `typecheck`, `test`, `lint`, `format`) so that `turbo run build`, `turbo run typecheck`, etc. from root include the new package. After adding a package, root `turbo run typecheck` and `turbo run build` must include it and pass. No circular internal dependencies. ## TypeScript base and package extension The root **`tsconfig.base.json`** defines strict, ESM/Bundler-oriented defaults. Each package extends it: ```json { "extends": "../../tsconfig.base.json", "compilerOptions": { "rootDir": "src", "outDir": "dist" }, "include": ["src"] } ``` Packages may override `include`, `exclude`, `rootDir`, and `outDir` as needed; do not relax strict or module options without an explicit reason. # Workspace Validation URL: https://dsar-sdk.dev/docs/architecture/workspace-validation Run these from repo root after a clean clone. All commands must exit 0 with zero packages. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. Run these from repo root after a clean clone. All commands must exit 0 with zero packages. ## Commands ```bash bun install turbo run build turbo run typecheck turbo run test turbo run lint turbo run format ``` ## Expected behaviour (zero packages) * **`bun install`** — Installs root devDependencies (turbo, typescript, @biomejs/biome). No workspace packages yet. * **`turbo run build`** — Turbo runs `build` in 0 packages; succeeds. * **`turbo run typecheck`** — Turbo runs `typecheck` in 0 packages; succeeds. * **`turbo run test`** — Turbo runs `test` in 0 packages; succeeds. * **`turbo run lint`** — Turbo runs `lint` in 0 packages; succeeds. * **`turbo run format`** — Turbo runs `format` in 0 packages; succeeds. ## Root workspace files (T01 deliverables) * `package.json` — Workspace definition, scripts, devDependencies. * `turbo.json` — Task graph (build, typecheck, test, lint, format). * `tsconfig.base.json` — Shared TypeScript base for packages. * `biome.jsonc` — Lint/format config (Biome). * `.gitignore` — Ignore patterns for repo. * `docs/architecture/monorepo-packages.md` — Package map, ownership, Effect conventions, dependency rules, package creation checklist. * `docs/architecture/workspace-validation.md` — This file. Once the first implementing ticket (e.g. T02) adds a package under `packages/*`, root `build` and `typecheck` will run that package's tasks; the package must follow the conventions in `monorepo-packages.md`. # Integrations URL: https://dsar-sdk.dev/docs/integrations Integration guides for inbound channels plus auth, outbound, and adapter-specific setup. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. Integration-focused documentation for inbound channels and DSAR adapter setup. ## Sections * [Inbound](./inbound) for channel-specific intake flows such as Resend and Slack. * [Integrations](./integrations) for auth, outbound delivery, and storage or persistence adapter guidance. # Inbound URL: https://dsar-sdk.dev/docs/integrations/inbound DSAR uses inbound adapters to receive data subject access requests from external sources. Each adapter verifies webhook authenticity, normalises the payload into a canonical capture format, and routes it to the correct tenant and jurisdiction. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. DSAR uses inbound adapters to receive data subject access requests from external sources. Each adapter verifies webhook authenticity, normalises the payload into a canonical capture format, and routes it to the correct tenant and jurisdiction. ## Available Adapters |Adapter|Package|Source| |:--|:--|:--| |[Resend](./resend.md)|`@dsar/inbound-resend`|Email via Resend inbound webhooks| |[Slack](./slack.md)|`@dsar/inbound-slack`|Slack messages, commands, shortcuts, and modals| ## How Inbound Works 1. An external event arrives at a DSAR webhook endpoint (e.g. `POST /webhooks/inbound/resend`). 2. The adapter verifies the request signature. 3. The adapter resolves a route to determine `tenantId`, `workspaceId`, and `jurisdiction`. 4. The event is normalised into a canonical `NormalizedInboundPayload`. 5. The backend's `captureRequestLifecycle()` creates or deduplicates the DSAR request. ## Intake Mapping All inbound adapters produce a consistent capture payload: * `jurisdiction` — resolved from route configuration * `intakeSource.type` — adapter-specific (e.g. `inbound_email`, `slack`) * `intakeSource.receivedAt` — authoritative timestamp from the source * `intakeSource.rawContextRef` — source-specific reference for traceability * `requestor.email` — parsed from the source when available ## Idempotency Inbound adapters derive deterministic idempotency keys so replayed webhook deliveries return the original request ID instead of creating duplicates. ## Stub Mode During development, skip inbound configuration: ```ts const runtime = dsarInstance({ adapters: { inbound: "stub", // ... }, }); ``` ## Related * [Getting Started](/docs/guides/getting-started) * [Request Lifecycle](/docs/guides/request-lifecycle) * [Adapter Contracts](/docs/architecture/adapter-contracts) # Inbound Resend URL: https://dsar-sdk.dev/docs/integrations/inbound/resend @dsar/inbound-resend accepts Resend email.received webhook events and maps them into canonical DSAR request capture input. Emails sent to configured addresses are automatically verified, routed, and captured as DSAR requests. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. `@dsar/inbound-resend` accepts Resend `email.received` webhook events and maps them into canonical DSAR request capture input. Emails sent to configured addresses are automatically verified, routed, and captured as DSAR requests. ## Installation |Package manager|Command| |:--|:--| |npm|`npm install @dsar/inbound-resend`| |pnpm|`pnpm add @dsar/inbound-resend`| |yarn|`yarn add @dsar/inbound-resend`| |bun|`bun add @dsar/inbound-resend`| ## Setup 1. **Configure Resend inbound emails** — set up a receiving domain in Resend and point the webhook to your DSAR instance. 2. **Create the adapter:** ```ts import { makeResendInboundAdapter } from "@dsar/inbound-resend"; const inbound = makeResendInboundAdapter({ webhookSecret: process.env.RESEND_WEBHOOK_SECRET!, fetchEmailContent: true, apiKey: process.env.RESEND_API_KEY, routeMap: { "privacy@tenant-a.example": { tenantId: "tenant-a", jurisdiction: "uk", }, }, defaultRoute: { tenantId: "tenant-default", jurisdiction: "eu", }, }); ``` 3. **Register with the backend:** ```ts import { dsarInstance } from "@dsar/backend"; const runtime = dsarInstance({ adapters: { inbound, notifications: "stub", storage: "stub", }, }); ``` Webhook endpoint: `POST /webhooks/inbound/resend` Required headers: `svix-id`, `svix-timestamp`, `svix-signature` ## Configuration |Option|Default|Description| |:--|:--|:--| |`webhookSecret`|—|Resend webhook secret for Svix signature verification (required)| |`apiKey`|—|Resend API key (needed when `fetchEmailContent` is enabled)| |`fetchEmailContent`|`false`|Fetch plain text / HTML body via Resend receiving API| |`routeMap`|—|Recipient address routing map| |`defaultRoute`|—|Fallback route when no recipient match found| ## Intake Mapping |Field|Value| |:--|:--| |`jurisdiction`|From recipient route resolution| |`intakeSource.type`|`inbound_email`| |`intakeSource.receivedAt`|Authoritative email timestamp| |`intakeSource.rawContextRef`|Resend `email_id` or `message_id`| |`requestor.email`|Parsed sender email| ## Idempotency Idempotency key format: `inbound-resend:{sourceId}:{tenantId}:{workspaceId|*}` Replayed webhook deliveries return the original request ID. ## Failure Modes * **Invalid signature or malformed payload** — `REQUEST_VALIDATION_FAILED` * **Missing recipient route and no default route** — `REQUEST_VALIDATION_FAILED` * **Non-DSAR intent** — accepted with `status: ignored_non_dsar` ## Related * [Inbound Overview](/docs/integrations/inbound) * [Inbound Slack](/docs/integrations/inbound/slack) * [Resend Inbound Emails](https://resend.com/blog/inbound-emails) * [Resend Receiving Docs](https://resend.com/docs/dashboard/receiving/introduction) # Inbound Slack URL: https://dsar-sdk.dev/docs/integrations/inbound/slack @dsar/inbound-slack accepts Slack webhook deliveries and maps them into canonical DSAR request capture input. Supports messages, slash commands, shortcuts, block actions, and modal submissions. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. `@dsar/inbound-slack` accepts Slack webhook deliveries and maps them into canonical DSAR request capture input. Supports messages, slash commands, shortcuts, block actions, and modal submissions. ## Installation |Package manager|Command| |:--|:--| |npm|`npm install @dsar/inbound-slack`| |pnpm|`pnpm add @dsar/inbound-slack`| |yarn|`yarn add @dsar/inbound-slack`| |bun|`bun add @dsar/inbound-slack`| ## Setup 1. **Create a Slack app** with the Events API enabled. 2. **Point the webhook** to your DSAR endpoint: `POST /webhooks/inbound/slack`. 3. **Subscribe to events** — app mentions, DMs, slash commands, shortcuts, block actions, or modal submissions. 4. **Install the app** into the target workspace and capture the signing secret and bot token. 5. **Verify the endpoint** — trigger Slack's URL verification flow and confirm the DSAR endpoint echoes the `challenge` response with HTTP `200`. ## Quickstart ```ts import { dsarInstance } from "@dsar/backend"; import { makeSlackInboundAdapter } from "@dsar/inbound-slack"; const inbound = makeSlackInboundAdapter({ signingSecret: process.env.SLACK_SIGNING_SECRET!, botToken: process.env.SLACK_BOT_TOKEN, teamRoutes: { T123: { jurisdiction: "uk", tenantId: "tenant-a", channels: { CPRIVACY: { jurisdiction: "uk", tenantId: "tenant-a", workspaceId: "workspace-1", }, }, commands: { "/dsar": { jurisdiction: "uk", tenantId: "tenant-a", }, }, }, }, }); const runtime = dsarInstance({ adapters: { inbound, notifications: "stub", storage: "stub", }, }); ``` Webhook endpoint: `POST /webhooks/inbound/slack` Required headers: `x-slack-signature`, `x-slack-request-timestamp` ## Configuration |Option|Default|Description| |:--|:--|:--| |`signingSecret`|—|Slack app signing secret (required)| |`botToken`|—|Bot token for profile lookup and Chat SDK| |`userName`|—|Bot username for Chat SDK adapter| |`replayToleranceSeconds`|`300`|Maximum age for signed requests| |`dedupeTtlMs`|`300000`|Chat SDK dedupe window| |`defaultRoute`|—|Fallback route for unmatched events| |`teamRoutes`|—|Route map keyed by Slack team ID| ## Supported Surfaces * Events API messages, app mentions, DMs, and thread replies * Slash commands * Shortcuts and message actions * Block actions * Modal submissions * URL verification challenge ## Intake Mapping |Field|Value| |:--|:--| |`intakeSource.type`|`slack`| |`intakeSource.channel`|`slack:{channelName\|channelId\|surface}`| |`intakeSource.rawContextRef`|`slack:{teamId}:{channelId}:{threadOrEvent}`| |`intakeSource.rawText`|Normalised message/command/modal text| |`requestor.name`|Slack display name when available| |`requestor.email`|Resolved from Slack profile when `botToken` is configured| ## Idempotency Idempotency key format: `inbound-slack:{sourceId}:{tenantId}:{workspaceId|*}` URL verification returns the raw Slack challenge response and does not create a DSAR request. ## Failure Modes * **Invalid signature, stale timestamp, or malformed payload** — `REQUEST_VALIDATION_FAILED` * **Missing route and no default route** — `REQUEST_VALIDATION_FAILED` * **Non-DSAR conversational events** — accepted with `status: ignored_non_dsar` ## Related * [Inbound Overview](/docs/integrations/inbound) * [Inbound Resend](/docs/integrations/inbound/resend) * [Slack Events API](https://api.slack.com/events-api) # Outbound Resend (`@dsar/outbound-resend`) URL: https://dsar-sdk.dev/docs/integrations/outbound/resend @dsar/outbound-resend provides built-in outbound DSAR notifications using the Resend API. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. `@dsar/outbound-resend` provides built-in outbound DSAR notifications using the Resend API. ## Package setup ```ts import { dsarInstance } from "@dsar/backend"; import { makeOutboundResendAdapter } from "@dsar/outbound-resend"; const outboundResend = makeOutboundResendAdapter({ apiKey: process.env.RESEND_API_KEY ?? "", from: "DSAR ", replyTo: "support@example.com", subjectPrefix: "[DSAR]", }); const runtime = dsarInstance({ adapters: { inbound: "stub", notifications: outboundResend, storage: "stub", }, config: { notificationWebhook: { url: "https://tenant.example/webhooks/notifications", signingSecret: "whsec_xxx", retryMaxAttempts: 3, retryDelayMs: 500, timeoutMs: 3000, }, }, }); ``` ## Channel behavior Notification generation remains mandatory; delivery channels execute independently: * Webhook channel (`notificationWebhook`) dispatches signed payloads. * Built-in email channel dispatches via `@dsar/outbound-resend` when enabled. * Delivery outcomes are persisted as `pending`, `delivered`, `failed`, or `skipped`. ## Email enable/disable precedence Built-in email enablement resolves in this order (last match wins): 1. `notificationWebhook.disableBuiltInEmail` (legacy global disable) 2. `outboundResend.enabled` (global) 3. `outboundResend.tenants[tenantId].enabled` (tenant override) 4. `outboundResend.tenants[tenantId].workspaces[workspaceId].enabled` (workspace override) Example config: ```ts config: { notificationWebhook: { url: "https://tenant.example/webhooks/notifications", signingSecret: "whsec_xxx", retryMaxAttempts: 3, retryDelayMs: 500, timeoutMs: 3000, disableBuiltInEmail: true, }, outboundResend: { enabled: false, fallbackRecipient: "ops@example.com", tenants: { "tenant-default": { enabled: false, fallbackRecipient: "compliance@example.com", workspaces: { "workspace-a": { enabled: true, }, }, }, }, }, } ``` ## Recipient resolution order Per event/request: 1. `request.requestor.email` 2. `request.capture.subject.email` 3. Workspace/tenant/global `outboundResend.fallbackRecipient` If no recipient resolves, the email attempt is recorded as `skipped`. ## Retry and failure semantics * Retriable channel failures follow `notificationWebhook.retryMaxAttempts` and `retryDelayMs`. * `skipped` outcomes do not retry. * Adapter errors are normalized to DSAR categories (`timeout`, `rate_limit`, `network`, `auth`, `validation`, `config`, `unknown`). # Storage Filesystem Adapter Integration URL: https://dsar-sdk.dev/docs/integrations/storage/filesystem This document describes how to register and use @dsar/storage-filesystem with backend runtime. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This document describes how to register and use `@dsar/storage-filesystem` with backend runtime. ## Runtime Registration ```ts import { dsarInstance } from "@dsar/backend"; import { makeFilesystemStorageAdapter } from "@dsar/storage-filesystem"; const runtime = dsarInstance({ adapters: { inbound: "stub", notifications: "stub", storage: makeFilesystemStorageAdapter({ baseDir: "./.dsar-artifacts", prefix: "artifacts", retryMaxAttempts: 1, }), }, }); ``` ## Config Fields * `baseDir` (required): local directory used to store artifacts and sidecar metadata. * `prefix` (optional, default `artifacts`): key prefix used by deterministic key builder. * `retryMaxAttempts` (optional, default `1`): retries for retriable filesystem failures (`ETIMEDOUT`, `EAGAIN`, etc.). ## Key Strategy Reference Default deterministic key layout: `//////` Fallback behavior: * missing `requestId` => `request-unknown` * missing `manifestId` => `manifest-unknown` * missing `category` => `uncategorized` * missing name/id => `artifact.bin` ## Error and Retry Behavior Matrix |Category|Retriable|Examples| |--|--|--| |`timeout`|yes|operation timeout (`ETIMEDOUT`)| |`network`|yes|temporary resource pressure (`EAGAIN`, `EBUSY`)| |`validation`|no|invalid key/path traversal, missing object| |`config`|no|base directory permission/configuration issues| |`unknown`|no|unmatched filesystem errors| ## Manifest Linkage Storage operations preserve manifest-linked metadata on artifact references: * `requestId` * `manifestId` * `manifestHash` * `manifestSignature` Manifest metadata is stored in sidecar JSON files alongside artifacts so metadata remains available across runtime restarts. # Storage S3 Adapter Integration URL: https://dsar-sdk.dev/docs/integrations/storage/s3 This document describes how to register and use @dsar/storage-s3 with backend runtime. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This document describes how to register and use `@dsar/storage-s3` with backend runtime. ## Runtime Registration ```ts import { dsarInstance } from "@dsar/backend"; import { makeS3StorageAdapter } from "@dsar/storage-s3"; const runtime = dsarInstance({ adapters: { inbound: "stub", notifications: "stub", storage: makeS3StorageAdapter({ bucket: "dsar-artifacts", region: "us-east-1", prefix: "artifacts", retryMaxAttempts: 3, timeoutMs: 3000, }), }, }); ``` ## Config Fields * `bucket` (required) * `region` (required) * `endpoint` (optional for S3-compatible providers) * `accessKeyId`, `secretAccessKey`, `sessionToken` (optional explicit credentials) * `forcePathStyle` (optional) * `prefix` (optional, default `artifacts`) * `timeoutMs` (optional, default `3000`) * `retryMaxAttempts` (optional, default `3`) ## Key Strategy Reference Default deterministic key layout: `//////` Fallback behavior: * missing `requestId` => `request-unknown` * missing `manifestId` => `manifest-unknown` * missing `category` => `uncategorized` * missing name/id => `artifact.bin` ## Error and Retry Behavior Matrix |Category|Retriable|Examples| |--|--|--| |`timeout`|yes|timeout, aborted request| |`rate_limit`|yes|throttling, 429| |`network`|yes|socket/connection failures| |`auth`|no|unauthorized, access denied| |`validation`|no|malformed key/input| |`config`|no|invalid adapter config| |`unknown`|no|unmatched provider errors| ## Manifest Linkage Storage operations preserve manifest-linked metadata on artifact references: * `requestId` * `manifestId` * `manifestHash` * `manifestSignature` This metadata is available via `putObject` results and `headObject`/`getObject` metadata for review and audit correlation paths. # Storage Vercel Blob Adapter Integration URL: https://dsar-sdk.dev/docs/integrations/storage/vercel-blob This document describes how to register and use @dsar/storage-vercel-blob with backend runtime. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This document describes how to register and use `@dsar/storage-vercel-blob` with backend runtime. ## Runtime Registration ```ts import { dsarInstance } from "@dsar/backend"; import { makeVercelBlobStorageAdapter } from "@dsar/storage-vercel-blob"; const runtime = dsarInstance({ adapters: { inbound: "stub", notifications: "stub", storage: makeVercelBlobStorageAdapter({ prefix: "artifacts", readWriteToken: process.env.BLOB_READ_WRITE_TOKEN, retryMaxAttempts: 3, timeoutMs: 3000, }), }, }); ``` ## Config Fields * `readWriteToken` (optional, defaults to `process.env.BLOB_READ_WRITE_TOKEN`) * `prefix` (optional, default `artifacts`) * `addRandomSuffix` (optional, default `false`) * `allowOverwrite` (optional, default `false`) * `cacheControlMaxAge` (optional) * `timeoutMs` (optional, default `10000`) * `retryMaxAttempts` (optional, default `3`) ## Key Strategy Reference Default deterministic key layout: `//////` Fallback behavior: * missing `requestId` => `request-unknown` * missing `manifestId` => `manifest-unknown` * missing `category` => `uncategorized` * missing name/id => `artifact.bin` ## Error and Retry Behavior Matrix |Category|Retriable|Examples| |--|--|--| |`timeout`|yes|request abort, blob service unavailable| |`rate_limit`|yes|blob rate limiting / throttling| |`network`|yes|fetch/socket connectivity failures| |`auth`|no|invalid token, store suspended/not found| |`validation`|no|malformed input/config| |`config`|no|adapter setup invalid| |`unknown`|no|unmatched provider errors| ## Manifest Linkage Storage operations preserve manifest-linked metadata on artifact references: * `requestId` * `manifestId` * `manifestHash` * `manifestSignature` For providers that do not expose arbitrary object metadata, the adapter keeps in-process reference metadata and falls back to deterministic key parsing for `requestId` and `manifestId`. ## Caching and Overwrite Notes * Vercel Blob `put(...)` requires `access: "public"` and serves content through CDN cache. * Prefer immutable pathnames and keep `allowOverwrite` disabled unless you explicitly need mutation. * If overwrite is enabled, cached clients may still observe stale content until cache expiry (`cacheControlMaxAge`). # Redis Integration URL: https://dsar-sdk.dev/docs/integrations/rate-limit/redis Use @dsar/redis for Redis-backed DSAR runtime integrations. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. `@dsar/redis` provides Redis-backed DSAR runtime integrations. It currently exports a Redis-backed `RateLimitStore` for public intake endpoints. Use it when a runtime has multiple Node/server instances and the default in-memory store would not share counters. ## Install ```sh bun add @dsar/redis ioredis ``` `ioredis` is a peer dependency so host applications control the Redis client version and connection setup. ## Runtime Wiring ```ts import { dsarInstance } from "@dsar/backend"; import { makeRedisRateLimitStore } from "@dsar/redis"; import Redis from "ioredis"; const redis = new Redis(process.env.REDIS_URL!); const runtime = dsarInstance({ config: { rateLimit: { intake: { ip: { limit: 60, windowMs: 60_000, }, tenant: { limit: 300, windowMs: 60_000, }, }, store: makeRedisRateLimitStore({ client: redis, keyPrefix: "dsar:rate-limit", }), }, }, repos: { persistence: /* see examples/config/runtime.config.example.ts or provide runtimeReposFromPersistence(...) output */, }, }); ``` ## Behavior * Uses the backend fixed-window rate-limit contract. * Shares IP and tenant counters across runtime instances. * Returns the same `429` and `Retry-After` behavior as the default store. * Automatically expires Redis keys after the configured window. * Applies `keyPrefix` before DSAR's route/scope key. Use an empty string only when the host application already namespaces keys. ## Production Notes * Use this package for Node/server deployments. * Use `@dsar/upstash` for fetch/edge-oriented deployments. * Keep `config.rateLimit.onLimitExceeded` wired to your metrics pipeline when you need visibility into abusive or misconfigured public intake sources. # Upstash Integration URL: https://dsar-sdk.dev/docs/integrations/rate-limit/upstash Use @dsar/upstash for Upstash-backed DSAR runtime integrations. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. `@dsar/upstash` provides Upstash-backed DSAR runtime integrations. It currently exports an Upstash Redis-backed `RateLimitStore` for public intake endpoints. Use it for serverless or edge-friendly deployments where a fetch-based Redis client is preferred. ## Install ```sh bun add @dsar/upstash @upstash/redis ``` `@upstash/redis` is a peer dependency so host applications control the client version and environment variable setup. ## Runtime Wiring ```ts import { dsarInstance } from "@dsar/backend"; import { makeUpstashRateLimitStore } from "@dsar/upstash"; import { Redis } from "@upstash/redis"; const redis = Redis.fromEnv(); const runtime = dsarInstance({ config: { rateLimit: { intake: { ip: { limit: 60, windowMs: 60_000, }, tenant: { limit: 300, windowMs: 60_000, }, }, store: makeUpstashRateLimitStore({ client: redis, keyPrefix: "dsar:rate-limit", }), }, }, repos: { persistence: /* see examples/config/runtime.config.example.ts or provide runtimeReposFromPersistence(...) output */, }, }); ``` ## Behavior * Uses the backend fixed-window rate-limit contract. * Shares IP and tenant counters across runtime instances. * Returns the same `429` and `Retry-After` behavior as the default store. * Automatically expires Upstash Redis keys after the configured window. * Applies `keyPrefix` before DSAR's route/scope key. Use an empty string only when the host application already namespaces keys. ## Production Notes * Use this package for serverless and fetch-oriented deployments. * Use `@dsar/redis` for long-running Node/server deployments with `ioredis`. * Keep `config.rateLimit.onLimitExceeded` wired to your metrics pipeline when you need visibility into abusive or misconfigured public intake sources. # Unkey Integration URL: https://dsar-sdk.dev/docs/integrations/auth/unkey @dsar/auth-unkey is an optional helper package for the DSAR bearer-token lane. It does not replace DSAR's authorization or subject-ownership checks. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. `@dsar/auth-unkey` is an optional helper package for the DSAR bearer-token lane. It does not replace DSAR's authorization or subject-ownership checks. ## Install ```sh bun add @dsar/auth-unkey ``` ## Runtime Wiring ```ts import { dsarInstance } from "@dsar/backend"; import { makeUnkeyBearerResolver } from "@dsar/auth-unkey"; const runtime = dsarInstance({ config: { auth: { resolveBearerToken: makeUnkeyBearerResolver({ rootKey: process.env.UNKEY_ROOT_KEY!, permissions: "dsar.api", fallbackPrincipalKind: "service", fallbackRole: "admin", }), staticBearerTokens: { [process.env.DSAR_API_TOKEN!]: { actorId: "local-admin", principalKind: "operator", role: "admin", tenantId: "tenant-default", }, }, }, }, repos: { persistence: /* see examples/config/runtime.config.example.ts or examples/kitchen-sink/runtime.config.ts for end-to-end wiring, or provide a service matching the @dsar/persistence PersistenceService contract used by runtimeReposFromPersistence(...) */, }, }); ``` Validate `process.env.UNKEY_ROOT_KEY` and `process.env.DSAR_API_TOKEN` at startup before calling `makeUnkeyBearerResolver(...)` or building `staticBearerTokens`. The example uses non-null assertions for brevity, but production runtimes should fail fast with a clear configuration error when `UNKEY_ROOT_KEY` or `DSAR_API_TOKEN` is missing instead of crashing later at request time. ## Default Mapping `makeUnkeyBearerResolver()` maps verified keys into DSAR identities like this: * `data.identity.externalId` or `data.keyId` -> `actorId` * `data.meta.tenantId` -> `tenantId` * `data.meta.workspaceId` -> `workspaceId` * `data.meta.role` or first role in `data.roles` -> `role` * `data.meta.principalKind` -> `principalKind` * `data.meta.email` or `data.identity.email` -> `email` If `tenantId` is missing, the resolver returns no identity and DSAR rejects the request. ## Custom Mapping Use `mapIdentity` when your Unkey metadata shape differs from the DSAR default: ```ts const resolver = makeUnkeyBearerResolver({ rootKey: process.env.UNKEY_ROOT_KEY!, mapIdentity: async ({ defaultIdentity, result }) => { if (!defaultIdentity) { return undefined; } return { ...defaultIdentity, principalKind: "operator", role: "admin", }; }, }); ``` ## Hosted Safety Rules * Keep browser-held DSAR keys out of subject portals. * Bind every accepted key to a tenant in Unkey metadata. * Treat Unkey as credential verification only; DSAR still enforces route access. # Reference URL: https://dsar-sdk.dev/docs/reference Reference docs for DSAR APIs, developer surfaces, storage, persistence, testing, and error catalogs. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. Reference material for DSAR runtime APIs, SDK and CLI surfaces, adapter contracts, storage and persistence drivers, testing expectations, and error catalogs. ## Sections * [API Reference](./api) for the DSAR HTTP surface. * [Developer](./developer) for CLI, SDK, and runtime guidance. * [Error Codes](./errors) for the generated error catalog. * [Persistence](./persistence) for Postgres and SQLite drivers. * [Storage](./storage) for S3, filesystem, and Vercel Blob adapters. * [Testing](./testing/acceptance-and-parity.md) for parity and acceptance expectations. # API Reference URL: https://dsar-sdk.dev/docs/reference/api These pages describe the DSAR HTTP surface exposed by @dsar/backend. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. These pages describe the DSAR HTTP surface exposed by `@dsar/backend`. ## Runtime and System * [Init API](./init.md) for `POST /init` * [Status API](./status.md) for `GET /status` * [Policies API](./policies.md) for policy discovery and upgrade lifecycle * [Webhooks API](./webhooks.md) for inbound Resend and Slack entrypoints ## Request Lifecycle * [Core Request API](./requests.md) for intake, queue/detail reads, legal-clock explainability, clarifications, authority, notifications, and other lifecycle controls * [Verification API](./verification.md) for verification cases and evidence * [Manifest API](./manifest.md) for fulfilment manifest reads, validation, and artifact operations * [Delivery API](./delivery.md) for delivery preparation, step-up, callback, and download flows * [Appeals API](./appeals.md) for request appeal handling * [Audit API](./audit.md) for immutable audit export and verification ## Tenant and Subject Scope * [Subjects API](./subjects.md) for `GET /subjects/:subjectId` * [Retention API](./retention.md) for tenant retention policy reads and writes ## Cross-Cutting Guides * [Request Lifecycle](../../guides/request-lifecycle.md) for an end-to-end workflow view * [Auth Model](../../architecture/auth-model.md) for subject, operator, and service principal behavior * [API Contract Surface](../../architecture/api-contract-surface.md) for generated OpenAPI and `/docs` # Status API URL: https://dsar-sdk.dev/docs/reference/api/status Return the current runtime health payload. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## GET /status Return the current runtime health payload. This is a public endpoint and does not require bearer authentication in the generated HTTP contract. **Response:** ```json { "service": "dsar", "status": "ok" } ``` Use `GET /status` for health probes, smoke tests, and quick validation that the runtime and base path are mounted as expected. Related surfaces: * Node SDK: `client.system.status()` * CLI: `dsar status` * See also [API Contract Surface](../../architecture/api-contract-surface.md) # Init API URL: https://dsar-sdk.dev/docs/reference/api/init Initialize the DSAR runtime context. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## POST /init Initialize the DSAR runtime context. This is a public endpoint and does not require bearer authentication in the generated HTTP contract. **Request body:** None required. **Response:** ```json { "initialized": true } ``` Use this endpoint when your deployment or smoke tests expect an explicit runtime-bootstrap step before traffic begins. Related surfaces: * Node SDK: `client.system.init()` * CLI: `dsar init` * Generated docs: `GET /docs` # Core Request API URL: https://dsar-sdk.dev/docs/reference/api/requests This page covers the request lifecycle endpoints that are not already documented in the dedicated verification, manifest, delivery, appeals, audit, subject, and retention pages. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This page covers the request lifecycle endpoints that are not already documented in the dedicated verification, manifest, delivery, appeals, audit, subject, and retention pages. ## Shared Intake Payload Request creation and capture use the same intake body: * `jurisdiction` (string, required) * `intakeSource` (object, required) * `intakeSource.channel` (string, required) * `intakeSource.rawText` (string, required) * `intakeSource.receivedAt` (string, required) * `intakeSource.contact` (string, optional) * `intakeSource.sourceEvidence` (array, optional) * `requestor` (object, optional) * `requestor.type` (string, required when present) * `requestor.name` (string, optional) * `requestor.email` (string, optional) * `requestor.relation` (string, optional) * `authority` (object, optional) * `authority.evidenceArtifacts` (array, required when present) * `authority.status` (string, required when present) * `authority.verifiedAt` (string, optional) * `receivedAt` (string, optional) `intakeSource.receivedAt` is the timestamp from the original external intake channel and is required for provenance. The top-level `receivedAt` is the time DSAR recorded or ingested the request and may be later than the intake-source timestamp or omitted entirely. ## POST /requests Create a request. **Response (202):** ```json { "id": "req-123", "receivedAt": "2026-01-01T00:00:00.000Z", "status": "received" } ``` ## POST /requests/capture Capture intake and return due-date context immediately. **Response (202):** ```json { "dueAt": "2026-02-01T00:00:00.000Z", "id": "req-123", "receivedAt": "2026-01-01T00:00:00.000Z", "status": "received" } ``` ## GET /requests List requests in the queue. **Query parameters:** * `limit` (number, optional) * `offset` (number, optional) * `status` (string, optional) * `sortBy` (string, optional) * `sortOrder` (string, optional) * `atRiskDays` (number, optional) **Response (200):** ```json { "items": [], "limit": 25, "offset": 0, "sortBy": "receivedAt", "sortOrder": "desc", "total": 0 } ``` ## GET /requests/:id Return a request detail record. **Response (200):** ```json { "appeals": [], "authority": { "evidenceArtifacts": [], "status": "not_required" }, "clockMode": "active", "dueAt": "2026-02-01T00:00:00.000Z", "id": "req-123", "receivedAt": "2026-01-01T00:00:00.000Z", "requestor": { "type": "subject" }, "status": "in_progress" } ``` ## GET /requests/:id/timeline Return the request timeline. **Response (200):** ```json { "events": [ { "createdAt": "2026-01-01T00:00:00.000Z", "eventType": "request_created", "id": "evt-123", "payload": {} } ], "requestId": "req-123" } ``` ## GET /requests/:id/clock/explain Explain how DSAR calculated the current deadline. The response includes the base deadline, final due date, policy pack/version, extensions, pauses, and segmented legal-clock history. **Response (200):** ```json { "baseDeadline": "2026-01-31T00:00:00.000Z", "clock": { "clockMode": "receipt", "dueAt": "2026-02-05T00:00:00.000Z", "receivedAt": "2026-01-01T00:00:00.000Z", "segments": [ { "actor": "system", "countsTowardDeadline": true, "from": "2026-01-01T00:00:00.000Z", "policyVersion": "1.0.0", "reason": "base", "to": "2026-01-31T00:00:00.000Z" } ] }, "extensions": [ { "additionalDays": 5, "justification": "policy_extension" } ], "finalDueAt": "2026-02-05T00:00:00.000Z", "pauses": [ { "duration": "2 days", "reason": "verification" } ], "policyPack": "gdpr-eu", "policyVersion": "1.0.0", "requestId": "req-123" } ``` ## Lifecycle Transition Endpoints These endpoints all return the common lifecycle response shape: ```json { "dueAt": "2026-02-01T00:00:00.000Z", "id": "req-123", "status": "in_progress" } ``` ### POST /requests/:id/clarifications/request Pause progress and request clarification from the subject or requestor. ### POST /requests/:id/clarifications/receive Record that the clarification was received and let the workflow continue. ### POST /requests/:id/extensions Extend the legal deadline for the request. ### POST /requests/:id/refusals Refuse the request. **Request body:** * `message` (string, optional) * `rationale` (string, optional) * `reason` (string, optional) ### POST /requests/:id/closures Close the request. ### POST /requests/:id/acknowledgements Record that the request was acknowledged. ## PUT /requests/:id/requestor Replace or set the requestor snapshot. **Request body:** * `type` (string, required) * `name` (string, optional) * `email` (string, optional) * `relation` (string, optional) **Response (202):** Lifecycle response envelope. ## Authority Endpoints Use these endpoints when a representative or agent must prove authority to act for the data subject. ### POST /requests/:id/authority/submit **Request body:** * `evidenceArtifacts` (array, required) * `status` (string, required) * `verifiedAt` (string, optional) ### POST /requests/:id/authority/approve Approve submitted authority evidence. ### POST /requests/:id/authority/reject Reject submitted authority evidence. All three endpoints return the lifecycle response envelope. ## Notification History ### GET /requests/:id/notifications List notification events and delivery attempts for a request. **Response (200):** ```json { "events": [ { "attempts": [ { "attempt": 1, "channel": "email", "createdAt": "2026-01-01T00:00:00.000Z", "destination": "user@example.com", "status": "delivered" } ], "createdAt": "2026-01-01T00:00:00.000Z", "eventId": "evt-123", "eventType": "request_fulfilled", "status": "delivered" } ], "requestId": "req-123" } ``` ### POST /requests/:id/notifications/:eventId/replay Replay one notification event. **Response (202):** ```json { "eventId": "evt-123", "status": "replayed" } ``` ## Related Pages * [Verification API](./verification.md) * [Manifest API](./manifest.md) * [Delivery API](./delivery.md) * [Appeals API](./appeals.md) * [Audit API](./audit.md) * [Request Lifecycle](../../guides/request-lifecycle.md) # Verification API URL: https://dsar-sdk.dev/docs/reference/api/verification Verification endpoints are workflow controls inside DSAR. They are not a general-purpose login system for subject portals or dashboards. In production, the host application authenticates the end user first, then DSAR uses these verification routes only when policy or risk requires extra proof. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. Verification endpoints are workflow controls inside DSAR. They are not a general-purpose login system for subject portals or dashboards. In production, the host application authenticates the end user first, then DSAR uses these verification routes only when policy or risk requires extra proof. ## POST /requests/:id/verification/request Create a verification case. Pauses the legal clock per policy. **Response (202):** ```json { "requestId": "req-123", "status": "verification_pending" } ``` ## POST /requests/:id/verification/evidence Submit verification evidence. `existing_auth` means "the host app has already authenticated this person" as a verification method inside the DSAR workflow. It does not mean DSAR owns the upstream session or browser login. **Request body:** * `level` (string): "reasonable" | "enhanced" * `evidenceArtifacts` (array): Evidence file references * `methodsAllowed` (array): Allowed verification methods * `reasonForDoubt` (string, optional) **Response (202):** ```json { "requestId": "req-123", "evidenceId": "ev-456", "level": "reasonable", "status": "pending", "surface": "verification_evidence" } ``` ## POST /requests/:id/verification/evidence/upload Upload a binary evidence artifact for the active verification case. **Request headers:** * `x-evidence-filename` (string, optional): URL-encoded original filename * `x-evidence-content-type` (string, optional): MIME type of the uploaded file * `x-evidence-level` (string, optional): evidence assurance level to associate with the upload **Request body:** Raw binary file content **Response (202):** ```json { "artifactKey": "verification/req-123/evidence/passport.pdf", "evidenceId": "ev-456", "requestId": "req-123", "status": "pending" } ``` If you use `@dsar/node-sdk`, `verificationEvidenceUpload()` sets the upload headers for you from the file name, content type, and optional level. ## POST /requests/:id/verification/approve Approve verification and resume the legal clock. **Response (202):** ```json { "requestId": "req-123", "status": "in_progress" } ``` ## POST /requests/:id/verification/reject Reject verification. **Response (202):** ```json { "requestId": "req-123", "status": "refused" } ``` ## GET /requests/:id/verification-case Read the current verification case. **Response (200):** ```json { "id": "verification-req-123", "status": "pending", "level": "reasonable", "method": "manual", "pauseClock": true, "requestedAt": "2026-01-01T00:00:00.000Z" } ``` # Manifest API URL: https://dsar-sdk.dev/docs/reference/api/manifest Get the fulfilment manifest for a request. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## GET /requests/:id/manifest Get the fulfilment manifest for a request. **Response (200):** ```json { "artifacts": [], "dataCategories": [], "redactionsApplied": [], "thirdPartyExclusions": [] } ``` ## POST /requests/:id/manifest/validate Record the manifest review decision for the latest fulfilment manifest attached to the request. **Request body:** * `action` (string, required): `"approved"` | `"rejected"` This matches the current backend validation body schema used by `POST /requests/:id/manifest/validate`. **Response (202):** ```json { "id": "req-123", "status": "approved" } ``` ## POST /requests/:id/manifest/artifact/upload Upload a binary file as a fulfilment manifest artifact. The file is persisted to the configured storage adapter and a record is added to the manifest's `artifacts` array. **Request headers:** * `x-artifact-filename` (string, required): URL-encoded filename * `x-artifact-content-type` (string, required): MIME type of the file * `x-artifact-title` (string, optional): Human-readable title (defaults to filename) * `x-artifact-type` (string, optional): Artifact category — `profile_data`, `account_data`, `support_tickets`, `audit_logs`, or `other` (defaults to `other`) **Request body:** Raw binary file content **Response (202):** ```json { "artifactId": "art-456", "artifactKey": "manifest/req-123/art-456/data-export.csv", "requestId": "req-123" } ``` **Error codes:** * `MANIFEST_ARTIFACT_UPLOAD_FAILED` (DSAR-BE-1206): Storage not configured, empty body, or storage write failure ## GET /requests/:id/manifest/artifact/download Download a manifest artifact file from storage. **Query parameters:** * `artifactId` (string, required): The manifest artifact identifier returned by upload or replace operations **Response (200):** Binary file content with appropriate `Content-Type` and `Content-Disposition` headers. **Error codes:** * `MANIFEST_ARTIFACT_DOWNLOAD_FAILED` (DSAR-BE-1207): Key not found, key doesn't match request, or storage read failure ## PUT /requests/:id/manifest/artifact/:artifactId/replace Replace an existing manifest artifact in-place. Used for the redaction workflow: download an artifact, redact sensitive data locally, and re-upload the modified version. **Request headers:** * `x-artifact-filename` (string, required): URL-encoded filename * `x-artifact-content-type` (string, required): MIME type of the replacement file **Request body:** Raw binary file content **Response (202):** ```json { "artifactId": "art-456", "artifactKey": "manifest/req-123/art-456/data-export.csv", "replaced": true, "requestId": "req-123" } ``` **Error codes:** * `MANIFEST_ARTIFACT_REPLACE_FAILED` (DSAR-BE-1208): Artifact ID not found in manifest, empty body, or storage overwrite failure # Delivery API URL: https://dsar-sdk.dev/docs/reference/api/delivery Transition a request from in_progress to fulfilled. This marks the DSAR as complete and triggers a request_fulfilled notification to the data subject. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## POST /requests/:id/fulfilment Transition a request from `in_progress` to `fulfilled`. This marks the DSAR as complete and triggers a `request_fulfilled` notification to the data subject. **Prerequisites:** * The request must be in `in_progress` status. * If a fulfilment manifest exists, its `validationState` must be `"approved"`. For request types that do not produce artifacts (e.g. deletion, rectification), no manifest is required. **Request body:** None required. **Response (202):** ```json { "id": "req-123", "status": "fulfilled", "dueAt": "2026-04-04T13:58:00.000Z" } ``` **Error codes:** * `FULFILMENT_MANIFEST_NOT_APPROVED` (DSAR-BE-1209): A manifest exists but has not been approved yet * `LIFECYCLE_TRANSITION_DISALLOWED` (DSAR-BE-1401): Request is not in `in_progress` status **CLI:** ```sh dsar requests fulfilment create ``` ## POST /requests/:id/fulfilment/callback Accept a fulfilment callback payload that carries the generated artifact manifest back into the request workflow. `POST /requests/:id/fulfilment/callback` does **not** finalize the request. The current implementation records the callback payload, creates or updates a pending manifest record, appends audit and notification events, and returns a `"recorded"` status. Call `POST /requests/:id/fulfilment` separately when the request is ready to transition to `fulfilled`. **Request body:** * `manifest` (object, required) * `manifest.artifacts` (array, required) * `manifest.supplementaryInfoInline` (string, optional) * `manifest.supplementaryInfoRef` (string, optional) **Response (202):** ```json { "requestId": "req-123", "status": "recorded" } ``` After `POST /requests/:id/fulfilment/callback`, use `POST /requests/:id/manifest/validate` if manifest review is enabled, then call `POST /requests/:id/fulfilment` to complete fulfilment and emit the final fulfilment notification. ## POST /requests/:id/delivery/prepare Prepare delivery of fulfilled data. Requires a fulfilment artifact to exist. **Request body:** * `channel` (string): "portal" | "email" | "secure\_remote\_access" * `securityLevel` (string): "standard" | "token" **Response (202):** ```json { "requestId": "req-123", "artifactId": "art-456", "deliveryPrepare": { "channel": "portal", "preparedAt": "...", "preparedBy": "..." }, "surface": "delivery_prepare" } ``` ## POST /requests/:id/delivery/address/verify Verify a delivery address. **Request body:** * `email` (string, optional) **Response (200):** ```json { "requestId": "req-123", "email": "user@example.com", "verified": true } ``` ## POST /requests/:id/delivery/step-up/challenge Issue a step-up verification challenge. Returns a token valid for 24 hours. **Response (202):** ```json { "requestId": "req-123", "token": "challenge-token-uuid", "expiresAt": "2026-02-26T00:00:00.000Z" } ``` > The `expiresAt` value is always 24 hours from issuance. ## POST /requests/:id/delivery/step-up/complete Complete a step-up challenge by submitting the token. **Request body:** * `token` (string, required) **Response (202):** ```json { "requestId": "req-123", "status": "completed" } ``` ## GET /requests/:id/artifacts/:artifactId/download Download a delivery artifact. **Request headers:** * `x-delivery-token` (string, required): Opaque token obtained from the step-up challenge flow. Issue a challenge via `POST /requests/:id/delivery/step-up/challenge`, then complete it via `POST /requests/:id/delivery/step-up/complete`. The token from the challenge response must be passed here. Tokens expire 24 hours after issuance; the gate must be in `completed` status. **Response (200):** ```json { "requestId": "req-123", "artifactId": "art-456", "artifact": {} } ``` ## GET /requests/:id/delivery/logs Get delivery attempt logs. **Response (200):** ```text { "requestId": "req-123", "logs": [ { "eventId": "evt-1", "eventType": "delivery_prepared", "attempts": [...] } ] } ``` # Appeals API URL: https://dsar-sdk.dev/docs/reference/api/appeals Create an appeal for a request. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## POST /requests/:id/appeals Create an appeal for a request. **Request body:** * `message` (string, required): free-text appeal rationale * `grounds` (string, optional) Create requests only accept the client-supplied appeal fields. Server-managed fields such as `id`, `status`, timestamps, and any decision metadata are returned by list/read models instead of being supplied during creation. **Response (202):** ```json { "appealId": "appeal-123", "requestId": "req-123", "status": "appeal_submitted" } ``` ## GET /requests/:id/appeals List appeals for a request. **Response (200):** ```json [ { "id": "appeal-123", "message": "Please review the refusal.", "status": "pending", "createdAt": "2026-01-01T00:00:00.000Z" } ] ``` ## POST /requests/:id/appeals/:appealId/decide Decide on an appeal. **Request body:** * `decision` (string): "approve" | "deny" | "partial" * `explanation` (string, optional) **Response (202):** ```json { "appealId": "appeal-123", "decision": "approve", "requestId": "req-123", "status": "appeal_decided" } ``` # Audit API URL: https://dsar-sdk.dev/docs/reference/api/audit Export the immutable audit chain for a request. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## GET /requests/:id/audit/export Export the immutable audit chain for a request. **Query parameters:** * `format` (string, optional): `"jsonl"` | `"csv"` **Response (202):** ```json { "requestId": "req-123", "format": "jsonl", "events": [], "rootHash": "sha256:..." } ``` ## POST /requests/:id/audit/verify Verify the integrity of an audit chain. **Request body:** * `hash` (string, required): expected hash for the target event or chain check * `prevHash` (string, optional): previous-link hash when verifying chain continuity * `sequence` (number, required): expected event sequence number **Response (202):** ```json { "mismatches": [ { "actualHash": "sha256:actual", "eventId": "evt-123", "expectedHash": "sha256:expected" } ], "status": "verified", "verified": true } ``` # Subjects API URL: https://dsar-sdk.dev/docs/reference/api/subjects Look up a subject profile by matching requests. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## GET /subjects/:subjectId Look up a subject profile by matching requests. The endpoint searches all requests for matching subject identifiers across: * `capture.subject.subjectId` * `capture.subject.externalRef` * `requestor.email` **Response (200):** ```json { "subjectId": "sub-123", "requests": [ { "id": "req-456", "status": "in_progress", "receivedAt": "2026-01-15T00:00:00.000Z" } ] } ``` # Retention Policy API URL: https://dsar-sdk.dev/docs/reference/api/retention List retention policies for a tenant. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## GET /tenants/:tenantId/retention List retention policies for a tenant. **Response (200):** ```json [ { "id": "ret-1", "class": "request_record", "minDays": 30, "maxDays": 365, "purgeEnabled": true, "legalHoldEnabled": false, "updatedAt": "2026-01-01T00:00:00.000Z" } ] ``` ## PUT /tenants/:tenantId/retention Create or update a retention policy. **Request body:** * `class` (string, required): Retention class — must be one of the values listed below * `minDays` (number, optional): Minimum retention period (default: 30) * `maxDays` (number, optional): Maximum retention period (default: 365) * `purgeEnabled` (boolean, optional): Auto-purge toggle (default: false) * `legalHoldEnabled` (boolean, optional): Legal hold toggle (default: false) **Response (202):** The upserted retention policy record. ### Retention Classes * `request_record` - DSAR request records * `audit_event` - Immutable audit events * `verification_evidence` - Identity verification artifacts * `fulfilment_artifact` - Response data packages * `delivery_log` - Delivery attempt records * `notification_log` - Notification generation/delivery records # Policies API URL: https://dsar-sdk.dev/docs/reference/api/policies These endpoints expose the policy catalog plus upgrade and custom-policy workflows. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. These endpoints expose the policy catalog plus upgrade and custom-policy workflows. ## GET /policies List policy packs visible to the current request context. **Response (200):** ```json [ { "jurisdiction": "eu", "name": "EU GDPR baseline", "packId": "gdpr-eu", "publishedAt": "2026-01-01T00:00:00.000Z", "version": "1.2.0" } ] ``` ## POST /policies/upgrades/propose Create a policy-upgrade proposal. The current OpenAPI contract does not declare a required request body for this endpoint. Treat it as a workflow trigger that creates a new proposal and returns the proposal ID and status. **Response (202):** ```json { "proposalId": "proposal-123", "status": "pending_approval" } ``` ## POST /policies/upgrades/:proposalId/approve Approve a pending policy-upgrade proposal. **Response (202):** ```json { "proposalId": "proposal-123", "status": "approved" } ``` ## POST /policies/upgrades/:proposalId/apply Apply an approved policy-upgrade proposal. **Response (202):** ```json { "proposalId": "proposal-123", "status": "applied" } ``` ## POST /policies/custom/register Register a custom policy pack. **Request body:** * `jurisdiction` (string, required) * `name` (string, required) * `version` (string, required) * `pack` (unknown, required): policy pack payload * `publishedAt` (string, optional) * `metadata` (object, required) * `metadata.changelog` (string, required) * `metadata.compatibilityNotes` (string, required) * `metadata.releaseType` (string, required): `"major"` | `"minor"` | `"patch"` **Response (202):** ```json { "jurisdiction": "eu", "name": "Internal Policy", "status": "registered", "version": "1.0.0" } ``` ## POST /policies/custom/activate Activate a registered custom policy pack for a tenant or workspace scope. **Request body:** * `jurisdiction` (string, required) * `tenantId` (string, required) * `version` (string, required) * `workspaceId` (string, optional) **Response (202):** ```json { "jurisdiction": "eu", "status": "activated", "tenantId": "tenant-1", "version": "1.0.0", "workspaceId": "workspace-1" } ``` ## POST /policies/custom/deactivate Deactivate a scoped custom policy assignment. **Request body:** * `tenantId` (string, required) * `workspaceId` (string, optional) **Response (202):** ```json { "status": "deactivated", "tenantId": "tenant-1", "workspaceId": "workspace-1" } ``` Related surfaces: * Node SDK: `client.policies.*` * CLI: `dsar policies list` and `dsar policies custom ...` * Architecture: [Policy Versioning and Upgrades](../../architecture/policy-versioning-and-upgrades.md) # Webhooks API URL: https://dsar-sdk.dev/docs/reference/api/webhooks These public endpoints accept inbound provider events and map them into DSAR intake flows. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. These public endpoints accept inbound provider events and map them into DSAR intake flows. ## POST /webhooks/inbound/resend Receive a Resend inbound webhook event. This endpoint is public in the HTTP contract so webhook providers can call it without a DSAR bearer token. Callers still need to satisfy the provider signature-verification requirements. See the related integration guide for the exact header and secret handling details. Resend uses svix headers and Slack uses signing-secret verification. **Request body:** * `created_at` (string, required): provider timestamp * `type` (string, required): provider event type * `data` (unknown, required): raw provider payload **Response (202):** ```json { "id": "req-123", "jurisdiction": "eu", "receivedAt": "2026-01-01T00:00:00.000Z", "sourceId": "resend-message-id", "status": "captured", "tenantId": "tenant-1", "workspaceId": "workspace-1" } ``` Possible `status` values: * `"captured"` when DSAR created or matched a request flow * `"ignored_non_dsar"` when the inbound event is not treated as DSAR intake ## POST /webhooks/inbound/slack Receive a Slack inbound webhook event. This endpoint is also public in the HTTP contract. Callers still need to satisfy the provider signature-verification requirements. See the related integration guide for the exact header and secret handling details. Resend uses svix headers and Slack uses signing-secret verification. **Request body:** Raw Slack webhook payload. **Responses:** * URL verification challenge: ```json { "challenge": "slack-challenge-token" } ``` * Accepted DSAR or ignored event: ```json { "callbackId": "cb-123", "channelId": "C123", "id": "req-123", "reason": "matched_subject_request", "sourceId": "slack-event-id", "status": "captured", "surface": "inbound_slack", "teamId": "T123" } ``` Related guides: * [Inbound Resend](../../integrations/integrations/inbound-resend.md) * [Inbound Slack](../../integrations/integrations/inbound-slack.md) # SDK and Runtime Modes URL: https://dsar-sdk.dev/docs/reference/developer/sdk-and-runtime DSAR exposes several public surfaces depending on whether you are hosting the runtime, calling it, or abstracting over multiple environments. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. DSAR exposes several public surfaces depending on whether you are hosting the runtime, calling it, or abstracting over multiple environments. ## Choose the Right Package |Package|Use when|Notes| |--|--|--| |`@dsar/backend`|You want to host DSAR as an HTTP runtime inside your own service|Exposes `dsarInstance()` plus generated `/spec.json` and `/docs`| |`@dsar/node-sdk`|You want typed server-side access to the DSAR HTTP API|Supports per-request headers, retries, timeouts, idempotency, and binary upload helpers| |`@dsar/cli`|You want terminal access, scripts, or parity checks against the HTTP surface|Maps closely to backend endpoints| |`@dsar/core`|You want one stable application-facing client contract across multiple environments|Switches behavior by mode| ## `@dsar/backend` Use `@dsar/backend` when DSAR is part of your own application or deployment. ```ts import { dsarInstance } from "@dsar/backend"; const runtime = dsarInstance({ basePath: "/api/v1" }); ``` Related docs: * [Backend Runtime Core](../../architecture/backend-runtime-core.md) * [API Contract Surface](../../architecture/api-contract-surface.md) * [Integration Guides](../../integrations/integrations) ## `@dsar/node-sdk` Use the Node SDK from trusted server-side code: ```ts import { createNodeSdk } from "@dsar/node-sdk"; const client = createNodeSdk({ baseUrl: "https://api.example.com/api/v1", token: process.env.DSAR_API_TOKEN, timeoutMs: 10_000, retryMaxAttempts: 2, }); ``` Highlights: * grouped namespaces such as `requests`, `subjects`, `policies`, `retention`, `audit`, `webhooks`, and `system` * per-request overrides for headers and idempotency * `unwrap()`, `expect()`, and `orElse()` helpers on results * binary helpers for verification evidence and fulfilment artifact flows ## `@dsar/cli` Use the CLI for operational access and parity with the HTTP contract. Examples: ```sh dsar status --api-url https://api.example.com/api/v1 dsar requests get req-123 --api-url https://api.example.com/api/v1 ``` Related docs: * [DSAR CLI](./cli.md) * [API Reference](../api) ## `@dsar/core` Modes `@dsar/core` lets application code depend on a stable interface while choosing a runtime mode: * `managed`: HTTP-backed client for a hosted DSAR deployment * `self-hosted`: HTTP-backed client for your own DSAR runtime * `custom`: supply your own handler for deterministic routing * `offline`: use fixtures without a backend dependency ```ts import { buildCoreClient } from "@dsar/core"; const client = buildCoreClient({ mode: "managed", baseUrl: "https://api.example.com/api/v1", token: process.env.DSAR_API_TOKEN, }); ``` ## Auth Guidance `DSAR_API_TOKEN` and other DSAR bearer credentials are machine-access credentials. Keep them server-side. For browser-facing subject portals or operator dashboards, authenticate the user in the host app first and then call DSAR from trusted backend code. See [Auth Model](../../architecture/auth-model.md). # DSAR CLI URL: https://dsar-sdk.dev/docs/reference/developer/cli @dsar/cli provides a command surface that maps to DSAR backend HTTP endpoints for agent and script usage. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. `@dsar/cli` provides a command surface that maps to DSAR backend HTTP endpoints for agent and script usage. ## Invocation Local workspace: ```sh dsar --help ``` Interactive wizard: ```sh dsar ``` When launched without command args, the CLI enters interactive mode and guides: 1. API URL/output/token setup 2. command domain + command selection 3. required params/body fields 4. execute/edit/cancel confirmation Published package flow: ```sh npx dsar --help ``` ## Environment and auth * `DSAR_API_URL` (required unless overridden by `--api-url`) * `DSAR_API_TOKEN` (optional bearer token) Global flags: * `--api-url`, `--token`, `--idempotency-key`, `--output`, `--json` ## CLI ↔ API mapping highlights * `init` -> `POST /init` * `status` -> `GET /status` * `subjects get ` -> `GET /subjects/{subjectId}` * `policies list` -> `GET /policies` * `policies custom register|activate|deactivate` -> custom policy endpoints * `webhooks inbound resend` -> `POST /webhooks/inbound/resend` * `requests create|capture` -> `POST /requests`, `POST /requests/capture` * `requests clock explain ` -> `GET /requests/{id}/clock/explain` * `requests verification ...` -> verification endpoints * `requests fulfilment create ` -> `POST /requests/{id}/fulfilment` * `requests delivery ...` -> delivery endpoints * `requests manifest ...` -> manifest endpoints * `requests appeals ...` -> appeals endpoints * `requests notifications list|replay ...` -> notification history and replay * `tenants retention get|put ` -> retention endpoints * `requests audit export|verify ` -> audit endpoints Full parity route map lives in: * `packages/cli/src/parity/route-map.ts` ## JSON output contract When `--output json` is used: * success: `{ ok: true, data, meta: { command } }` * failure: `{ ok: false, error: { code, message }, meta? }` Interactive mode still uses the same final output envelope after command execution. ## Notification replay Notification replay is part of the current CLI surface: * `dsar requests notifications list ` * `dsar requests notifications replay ` ## Parity policy Any new backend OpenAPI path + method pair must include: 1. route parity entry in `packages/cli/src/parity/route-map.ts` 2. callable CLI command mapping 3. passing parity test # TSDoc Authoring Standard URL: https://dsar-sdk.dev/docs/reference/developer/tsdoc This repository uses TSDoc to make public APIs self-documenting in editor hover, autocomplete, and generated declarations. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This repository uses TSDoc to make public APIs self-documenting in editor hover, autocomplete, and generated declarations. ## Scope Apply these rules to exported symbols in package source files: * `packages/*/src/**/*.{ts,tsx}` * `packages/internals/*/src/**/*.{ts,tsx}` Skip generated code and re-export-only barrel files. ## Required for Exported Symbols 1. Add a concise summary sentence on every exported declaration. 2. For exported function-like APIs, document each argument with `@param`. 3. For exported generic APIs, document each generic with `@typeParam`. 4. For exported non-void function-like APIs, add `@returns`. 5. For exported interfaces, document each property with a short property comment. ## Balanced Depth (Default) Use concise, accurate comments by default. Add richer sections only when they clarify important behavior. * Use `@remarks` for behavior caveats, defaults, and lifecycle semantics. * Use `@example` for high-impact entrypoints and integration setup APIs. * Use `@throws` when callers need to branch on failures. ## Formatting * Use TSDoc tags (not JSDoc type braces): * `@param name - Description` * `@typeParam T - Description` * `@returns Description` * Keep summaries imperative and behavior-focused. * Prefer documenting contract semantics over implementation details. ## Example ```ts /** * Creates a configured SDK client for DSAR API operations. * * @param config - Runtime configuration for endpoint calls and retries. * @returns A typed client grouped by DSAR API domains. */ export const createNodeSdk = (config?: NodeSdkConfig): NodeSdkClient => { // ... }; ``` ## Property Comment Pattern Use property-level comments so tooltips are visible during object construction: ```ts export interface NodeSdkConfig { /** DSAR API base URL override (falls back to environment). */ readonly baseUrl?: string; /** Auth token used for bearer authorization. */ readonly token?: string; } ``` # Persistence URL: https://dsar-sdk.dev/docs/reference/persistence DSAR uses persistence drivers to store request state, audit events, policy assignments, and all other domain records in a database. Each driver implements the same PersistenceDriver contract, so you can swap databases without changing application code. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. DSAR uses persistence drivers to store request state, audit events, policy assignments, and all other domain records in a database. Each driver implements the same `PersistenceDriver` contract, so you can swap databases without changing application code. ## Available Drivers |Driver|Package|Best For| |:--|:--|:--| |[Postgres](./pg.md)|`@dsar/persistence-pg`|Production deployments with advisory-lock migration protection| |[SQLite](./sqlite.md)|`@dsar/persistence-sqlite`|Local development, testing, and lightweight deployments| ## How Persistence Works The persistence layer is tenant-scoped — every database operation runs within a tenant context. The `withTenant` helper scopes Effect programs to a specific tenant: ```ts import { Persistence, withTenant } from "@dsar/persistence"; import { Effect } from "effect"; const program = Persistence.pipe( Effect.flatMap((p) => p.requests.list()), withTenant("tenant-1") ); ``` ## Domain Records The persistence layer manages these record types: |Record|Purpose| |:--|:--| |`RequestRecord`|DSAR request state and metadata| |`AuditEventRecord`|Tamper-evident audit trail| |`ClockSegmentRecord`|Compliance clock tracking| |`FulfillmentArtifactRecord`|Delivery artifact references| |`PolicyAssignmentRecord`|Jurisdiction policy bindings| |`VerificationEvidenceRecord`|Identity verification evidence| |`RetentionPolicyRecord`|Data retention schedules| |`NotificationEventRecord`|Notification lifecycle| |`ChatStateRecord`|Conversational state for inbound adapters| ## Choosing a Driver * **Starting out?** Use `persistence-sqlite` with in-memory mode for instant setup. * **Production?** Use `persistence-pg` for Postgres with advisory-lock migration protection. ## Wiring with the Backend ```ts import { dsarInstance, runtimeReposFromPersistence } from "@dsar/backend"; import { makeSqlitePersistenceService } from "@dsar/persistence-sqlite"; const persistence = await makeSqlitePersistenceService(); const runtime = dsarInstance({ repos: runtimeReposFromPersistence(persistence), }); ``` ## Related * [Getting Started](/docs/guides/getting-started) * [Request Lifecycle](/docs/guides/request-lifecycle) * [Architecture: Tenant-Safe Persistence](/docs/architecture/tenant-safe-persistence) # SQLite URL: https://dsar-sdk.dev/docs/reference/persistence/sqlite @dsar/persistence-sqlite provides a SQLite driver for DSAR persistence. Supports Bun and Node runtimes with in-memory default for fast local development and testing. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. `@dsar/persistence-sqlite` provides a SQLite driver for DSAR persistence. Supports Bun and Node runtimes with in-memory default for fast local development and testing. ## Installation |Package manager|Command| |:--|:--| |npm|`npm install @dsar/persistence-sqlite`| |pnpm|`pnpm add @dsar/persistence-sqlite`| |yarn|`yarn add @dsar/persistence-sqlite`| |bun|`bun add @dsar/persistence-sqlite`| ## Quickstart ### Standalone Service ```ts import { makeSqlitePersistenceService } from "@dsar/persistence-sqlite"; import { dsarInstance, runtimeReposFromPersistence } from "@dsar/backend"; // In-memory (default) — great for development and testing const persistence = await makeSqlitePersistenceService(); // File-based — persists across restarts const persistence = await makeSqlitePersistenceService({ filename: "./dsar.db", }); const runtime = dsarInstance({ repos: runtimeReposFromPersistence(persistence), }); ``` ### Effect Layer Composition ```ts import { Effect } from "effect"; import { Persistence, withTenant } from "@dsar/persistence"; import { makeSqlitePersistenceLayer } from "@dsar/persistence-sqlite"; const program = Persistence.pipe( Effect.flatMap((persistence) => persistence.requests.list()), withTenant("tenant-1"), Effect.provide(makeSqlitePersistenceLayer({ filename: ":memory:" })) ); await Effect.runPromise(program); ``` ## When to Use SQLite * **Local development** — in-memory mode starts instantly with zero configuration * **Testing** — each test gets a fresh in-memory database * **Lightweight deployments** — single-server setups where Postgres is overkill * **Prototyping** — get a working DSAR instance running in seconds For production multi-instance deployments, use [Postgres](/docs/reference/persistence/pg) instead. ## Related * [Persistence Overview](/docs/reference/persistence) * [Postgres Driver](/docs/reference/persistence/pg) * [Getting Started](/docs/guides/getting-started) # Postgres URL: https://dsar-sdk.dev/docs/reference/persistence/pg @dsar/persistence-pg provides a Postgres driver for DSAR persistence with advisory-lock migration protection, connection pooling, and full domain record support. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. `@dsar/persistence-pg` provides a Postgres driver for DSAR persistence with advisory-lock migration protection, connection pooling, and full domain record support. ## Installation |Package manager|Command| |:--|:--| |npm|`npm install @dsar/persistence-pg`| |pnpm|`pnpm add @dsar/persistence-pg`| |yarn|`yarn add @dsar/persistence-pg`| |bun|`bun add @dsar/persistence-pg`| ## Quickstart ### Standalone Service The simplest way to get started — creates a persistence service you can pass directly to the backend: ```ts import { makePgPersistenceService } from "@dsar/persistence-pg"; import { dsarInstance, runtimeReposFromPersistence } from "@dsar/backend"; const persistence = await makePgPersistenceService({ connectionUrl: "postgres://user:pass@localhost:5432/dsar", }); const runtime = dsarInstance({ repos: runtimeReposFromPersistence(persistence), }); ``` ### Effect Layer Composition For Effect-based applications, use the layer API for dependency injection: ```ts import { Effect } from "effect"; import { Persistence, withTenant } from "@dsar/persistence"; import { makePgPersistenceLayer } from "@dsar/persistence-pg"; const program = Persistence.pipe( Effect.flatMap((persistence) => persistence.requests.list()), withTenant("tenant-1"), Effect.provide( makePgPersistenceLayer({ config: { url: "postgres://user:pass@localhost:5432/dsar" }, }) ) ); await Effect.runPromise(program); ``` ## Migrations Migrations run automatically on startup with advisory-lock protection to prevent concurrent migration conflicts in multi-instance deployments. ## Related * [Persistence Overview](/docs/reference/persistence) * [SQLite Driver](/docs/reference/persistence/sqlite) * [Architecture: Tenant-Safe Persistence](/docs/architecture/tenant-safe-persistence) * [Getting Started](/docs/guides/getting-started) # Storage URL: https://dsar-sdk.dev/docs/reference/storage DSAR uses storage adapters to persist fulfilment artifacts — the files, documents, and data packages assembled during request processing. Each adapter implements the same StorageAdapterContract, so you can swap providers without changing application code. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. DSAR uses storage adapters to persist fulfilment artifacts — the files, documents, and data packages assembled during request processing. Each adapter implements the same `StorageAdapterContract`, so you can swap providers without changing application code. ## Available Adapters |Adapter|Package|Best For| |:--|:--|:--| |[S3](./s3.md)|`@dsar/storage-s3`|Production deployments with AWS, MinIO, R2, or any S3-compatible provider| |[Filesystem](./filesystem.md)|`@dsar/storage-filesystem`|Local development and single-server deployments| |[Vercel Blob](./vercel-blob.md)|`@dsar/storage-vercel-blob`|Zero-infrastructure deployments on Vercel| ## How Storage Works When a DSAR request reaches the fulfilment stage, the runtime assembles artifacts into a manifest and stores them through the configured adapter. Each artifact gets a deterministic key: ```text ////// ``` All adapters preserve manifest-linked metadata on artifact references: * `requestId` — the originating DSAR request * `manifestId` — the delivery manifest grouping artifacts * `manifestHash` — integrity hash of the manifest * `manifestSignature` — cryptographic signature when available ## Choosing an Adapter * **Starting out?** Use `storage-filesystem` for local development and testing. * **Deploying to Vercel?** Use `storage-vercel-blob` for managed storage with zero setup. * **Production at scale?** Use `storage-s3` with your preferred S3-compatible provider. ## Stub Mode During development, you can skip storage configuration entirely: ```ts const runtime = dsarInstance({ adapters: { storage: "stub", // ... }, }); ``` Stub mode accepts all storage operations without persisting data. ## Related * [Getting Started](/docs/guides/getting-started) * [Request Lifecycle](/docs/guides/request-lifecycle) * [Adapter Contracts](/docs/architecture/adapter-contracts) # Filesystem Storage URL: https://dsar-sdk.dev/docs/reference/storage/filesystem @dsar/storage-filesystem stores DSAR fulfilment artifacts on the local filesystem. Ideal for development, testing, and single-server deployments. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. `@dsar/storage-filesystem` stores DSAR fulfilment artifacts on the local filesystem. Ideal for development, testing, and single-server deployments. ## Installation |Package manager|Command| |:--|:--| |npm|`npm install @dsar/storage-filesystem`| |pnpm|`pnpm add @dsar/storage-filesystem`| |yarn|`yarn add @dsar/storage-filesystem`| |bun|`bun add @dsar/storage-filesystem`| ## Setup ```ts import { dsarInstance } from "@dsar/backend"; import { makeFilesystemStorageAdapter } from "@dsar/storage-filesystem"; const runtime = dsarInstance({ adapters: { inbound: "stub", notifications: "stub", storage: makeFilesystemStorageAdapter({ baseDir: "./.dsar-artifacts", prefix: "artifacts", retryMaxAttempts: 1, }), }, }); ``` ## Configuration |Option|Default|Description| |:--|:--|:--| |`baseDir`|—|Local directory for artifacts and sidecar metadata (required)| |`prefix`|`artifacts`|Key prefix used by the deterministic key builder| |`retryMaxAttempts`|`1`|Retries for retriable filesystem failures| ## Key Layout Default deterministic key format: ```text ////// ``` Fallback values: * missing `requestId` → `request-unknown` * missing `manifestId` → `manifest-unknown` * missing `category` → `uncategorized` * missing name/id → `artifact.bin` ## Error and Retry Behaviour |Category|Retriable|Examples| |:--|:--|:--| |`timeout`|yes|operation timeout (`ETIMEDOUT`)| |`network`|yes|temporary resource pressure (`EAGAIN`, `EBUSY`)| |`validation`|no|invalid key/path traversal, missing object| |`config`|no|base directory permission/configuration issues| |`unknown`|no|unmatched filesystem errors| ## Manifest Linkage Manifest metadata is stored in sidecar JSON files alongside artifacts so linkage survives process restarts. Each artifact reference preserves: * `requestId` * `manifestId` * `manifestHash` * `manifestSignature` ## Related * [Storage Overview](/docs/reference/storage) * [S3 Storage](/docs/reference/storage/s3) * [Vercel Blob Storage](/docs/reference/storage/vercel-blob) # S3 Storage URL: https://dsar-sdk.dev/docs/reference/storage/s3 @dsar/storage-s3 connects DSAR to any S3-compatible object store — AWS S3, MinIO, Cloudflare R2, DigitalOcean Spaces, and more. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. `@dsar/storage-s3` connects DSAR to any S3-compatible object store — AWS S3, MinIO, Cloudflare R2, DigitalOcean Spaces, and more. ## Installation |Package manager|Command| |:--|:--| |npm|`npm install @dsar/storage-s3`| |pnpm|`pnpm add @dsar/storage-s3`| |yarn|`yarn add @dsar/storage-s3`| |bun|`bun add @dsar/storage-s3`| ## Setup ```ts import { dsarInstance } from "@dsar/backend"; import { makeS3StorageAdapter } from "@dsar/storage-s3"; const runtime = dsarInstance({ adapters: { inbound: "stub", notifications: "stub", storage: makeS3StorageAdapter({ bucket: "dsar-artifacts", region: "us-east-1", prefix: "artifacts", retryMaxAttempts: 3, timeoutMs: 3000, }), }, }); ``` ## Configuration |Option|Default|Description| |:--|:--|:--| |`bucket`|—|S3 bucket name (required)| |`region`|—|AWS region (required)| |`endpoint`|—|Custom endpoint for S3-compatible providers| |`accessKeyId`|—|Explicit AWS access key| |`secretAccessKey`|—|Explicit AWS secret key| |`sessionToken`|—|Temporary session token| |`forcePathStyle`|`false`|Use path-style URLs (for MinIO, etc.)| |`prefix`|`artifacts`|Key prefix for all stored objects| |`timeoutMs`|`3000`|Request timeout in milliseconds| |`retryMaxAttempts`|`3`|Retry count for retriable failures| ## Key Layout Default deterministic key format: ```text ////// ``` Fallback values: * missing `requestId` → `request-unknown` * missing `manifestId` → `manifest-unknown` * missing `category` → `uncategorized` * missing name/id → `artifact.bin` ## Error and Retry Behaviour |Category|Retriable|Examples| |:--|:--|:--| |`timeout`|yes|timeout, aborted request| |`rate_limit`|yes|throttling, 429| |`network`|yes|socket/connection failures| |`auth`|no|unauthorised, access denied| |`validation`|no|malformed key/input| |`config`|no|invalid adapter config| |`unknown`|no|unmatched provider errors| ## Manifest Linkage Storage operations preserve manifest-linked metadata on artifact references: * `requestId` * `manifestId` * `manifestHash` * `manifestSignature` This metadata is available via `putObject` results and `headObject`/`getObject` metadata for review and audit correlation. ## Related * [Storage Overview](/docs/reference/storage) * [Filesystem Storage](/docs/reference/storage/filesystem) * [Vercel Blob Storage](/docs/reference/storage/vercel-blob) # Vercel Blob Storage URL: https://dsar-sdk.dev/docs/reference/storage/vercel-blob @dsar/storage-vercel-blob stores DSAR fulfilment artifacts in Vercel's managed blob storage service. Zero infrastructure setup when deploying on Vercel. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. `@dsar/storage-vercel-blob` stores DSAR fulfilment artifacts in Vercel's managed blob storage service. Zero infrastructure setup when deploying on Vercel. ## Installation |Package manager|Command| |:--|:--| |npm|`npm install @dsar/storage-vercel-blob`| |pnpm|`pnpm add @dsar/storage-vercel-blob`| |yarn|`yarn add @dsar/storage-vercel-blob`| |bun|`bun add @dsar/storage-vercel-blob`| ## Setup ```ts import { dsarInstance } from "@dsar/backend"; import { makeVercelBlobStorageAdapter } from "@dsar/storage-vercel-blob"; const runtime = dsarInstance({ adapters: { inbound: "stub", notifications: "stub", storage: makeVercelBlobStorageAdapter({ prefix: "artifacts", readWriteToken: process.env.BLOB_READ_WRITE_TOKEN, retryMaxAttempts: 3, timeoutMs: 3000, }), }, }); ``` ## Configuration |Option|Default|Description| |:--|:--|:--| |`readWriteToken`|`process.env.BLOB_READ_WRITE_TOKEN`|Vercel Blob read-write token| |`prefix`|`artifacts`|Key prefix for all stored objects| |`addRandomSuffix`|`false`|Append random suffix to keys| |`allowOverwrite`|`false`|Allow overwriting existing objects| |`cacheControlMaxAge`|—|CDN cache-control max age| |`timeoutMs`|`10000`|Request timeout in milliseconds| |`retryMaxAttempts`|`3`|Retry count for retriable failures| ## Key Layout Default deterministic key format: ```text ////// ``` Fallback values: * missing `requestId` → `request-unknown` * missing `manifestId` → `manifest-unknown` * missing `category` → `uncategorized` * missing name/id → `artifact.bin` ## Error and Retry Behaviour |Category|Retriable|Examples| |:--|:--|:--| |`timeout`|yes|request abort, blob service unavailable| |`rate_limit`|yes|blob rate limiting / throttling| |`network`|yes|fetch/socket connectivity failures| |`auth`|no|invalid token, store suspended/not found| |`validation`|no|malformed input/config| |`config`|no|adapter setup invalid| |`unknown`|no|unmatched provider errors| ## Caching and Overwrite Notes * Vercel Blob `put(...)` requires `access: "public"` and serves content through CDN cache. * Prefer immutable pathnames and keep `allowOverwrite` disabled unless you explicitly need mutation. * If overwrite is enabled, cached clients may still observe stale content until cache expiry (`cacheControlMaxAge`). ## Related * [Storage Overview](/docs/reference/storage) * [S3 Storage](/docs/reference/storage/s3) * [Filesystem Storage](/docs/reference/storage/filesystem) # Acceptance And Parity Readiness URL: https://dsar-sdk.dev/docs/reference/testing/acceptance-and-parity This checklist turns the GA-readiness ticket work into a concrete release gate for the current DSAR repo state. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. This checklist turns the GA-readiness ticket work into a concrete release gate for the current DSAR repo state. ## Release-blocking scenarios * Inbound intake to fulfilment: request capture, verification, fulfilment, and delivery must pass in automated API/E2E coverage. * Clarification pause/resume: legal-clock explain output must reflect pause and resume behavior. * Extension handling: justification-required extensions must be enforced and reflected in due-date calculations. * Refusal and appeal: refusal flow plus minimal appeal submission/decision coverage must pass. * Manifest review: fulfilment should remain blocked until manifest validation is approved when manifest review is enabled. * Notification visibility: generated notification events, delivery attempts, and replay flow must remain observable. ## Current evidence in repo * API lifecycle E2E coverage exists in `packages/backend/test/e2e/full-flow.api.e2e.test.ts`. * Route-level lifecycle coverage exists in `packages/backend/test/routes/requests-lifecycle.test.ts`. * Notification retry and built-in email behavior are covered in `packages/backend/test/services/notifications.service.test.ts`. * CLI/backend parity is guarded by `packages/cli/test/parity.test.ts` and `packages/cli/test/e2e/parity-guard.e2e.test.ts`. ## Gaps to keep tracking * Hosted vs self-hosted parity runs are still a roadmap item; there is no published parity report artifact yet. * Browser-driven acceptance scenarios are still thinner than the API-level coverage described in the readiness ticket. * Deployment packaging remains repo-specific; there is no canonical container or infra recipe in this workspace. ## Recommended release checklist * Run `bun test` or the workspace-equivalent backend, CLI, and SDK test targets with no skipped critical scenarios. * Verify OpenAPI generation and CLI parity stay in sync after any route change. * Smoke test `examples/kitchen-sink`, `examples/dashboard`, and `examples/subject-portal` against the same runtime configuration. * Confirm bearer-token identities are configured for admin and subject example clients before manual verification. * Review example docs for merge markers, stale auth guidance, and broken local URLs before tagging a release. # DSAR-BE-1001: AUTH_ACTOR_CONTEXT_MISSING URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1001 The request targets a protected endpoint, but DSAR could not resolve an authenticated actor from bearer auth. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The request targets a protected endpoint, but DSAR could not resolve an authenticated actor from bearer auth. ## Probable Causes * Client did not send `Authorization: Bearer ...` for a protected route. * Runtime bearer-token mapping is missing or the token is invalid. ## How to Fix 1. Send a valid DSAR bearer token and configure the runtime to resolve it. ## Retryable No. Retry only after fixing request authentication. ## Minimal Trigger Example ```http GET /api/v1/requests/req-1 HTTP/1.1 Host: localhost:4086 ``` # DSAR-BE-1002: AUTH_APPROVER_ROLE_FORBIDDEN URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1002 The actor is authenticated but does not have the role required for an approver-only operation. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The actor is authenticated but does not have the role required for an approver-only operation. ## Probable Causes * Request uses a member-level actor for an admin/approver endpoint. * Role propagation in gateway/session layer is incorrect. ## How to Fix 1. Use a bearer token whose resolved identity has a role that is allowed for the operation (for example, `admin`). 2. Verify the role mapping between your identity provider or token resolver and DSAR. ## Retryable No. Retry only after changing actor role context. ## Minimal Trigger Example ```http POST /api/v1/policies/custom/register HTTP/1.1 Host: localhost:4086 Authorization: Bearer member-token content-type: application/json {"jurisdiction":"uk","name":"custom-policy","version":"1.0.0","metadata":{"changelog":"init","compatibilityNotes":"none","releaseType":"minor"},"pack":{"jurisdiction":"uk","version":"1.0.0","effectiveAt":"2026-01-01T00:00:00.000Z","packId":"pack-uk-1","sections":{}}} ``` # DSAR-BE-1003: AUTH_REQUEST_ACCESS_FORBIDDEN URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1003 The caller is authenticated, but the resolved principal is not allowed to access the requested route or DSAR record. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The caller is authenticated, but the resolved principal is not allowed to access the requested route or DSAR record. ## Probable Causes * A subject principal attempted to use a staff-only route. * A subject principal tried to read or mutate another subject's request. * Principal-kind mapping in your bearer resolver or trusted identity projection is incorrect. ## How to Fix 1. Verify the caller resolves to the correct `principalKind` for the route. 2. For subject portals, authenticate the subject in the host app and project the matching subject identity to DSAR. 3. Ensure the request actually belongs to the subject before calling subject-owned routes. ## Retryable No. Retry only after changing the caller identity, principal kind, or target resource. ## Minimal Trigger Example ```http GET /api/v1/requests/req-other HTTP/1.1 Host: localhost:4086 Authorization: Bearer subject-token ``` # DSAR-BE-1101: REQUEST_BODY_INVALID_JSON URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1101 A handler expected JSON, but the request body could not be parsed. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A handler expected JSON, but the request body could not be parsed. ## Probable Causes * Body is malformed JSON. * `Content-Type` is JSON but payload is empty or truncated. ## How to Fix 1. Send syntactically valid JSON. 2. Ensure `Content-Type: application/json` matches the payload format. ## Retryable No. Retry only after correcting the payload. ## Minimal Trigger Example ```http POST /api/v1/requests/capture HTTP/1.1 Host: localhost:4086 Content-Type: application/json Authorization: Bearer test-token {invalid ``` # DSAR-BE-1102: REQUEST_ROUTE_PARAM_MISSING URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1102 A route parameter required by server-side handler logic is absent. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A route parameter required by server-side handler logic is absent. ## Probable Causes * Route path does not match the expected parameterized shape. * Client generated URL omitted a required segment. ## How to Fix 1. Verify URL includes all required path parameters. 2. Use SDK route helpers to build paths instead of string concatenation. ## Retryable No. Retry with corrected route path. ## Minimal Trigger Example ```http GET /api/v1/requests//timeline HTTP/1.1 Host: localhost:4086 Authorization: Bearer test-token ``` # DSAR-BE-1103: REQUEST_BASE_PATH_INVALID URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1103 Backend runtime was configured with an invalid `basePath`. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning Backend runtime was configured with an invalid `basePath`. ## Probable Causes * `basePath` does not start with `/`. * Environment variable provided malformed path. ## How to Fix 1. Set `basePath` to either empty/root or a slash-prefixed segment (`/api/v1`). 2. Validate deployment configuration before boot. ## Retryable No. Requires configuration change. ## Minimal Trigger Example ```ts dsarInstance({ basePath: "api/v1" }); ``` # DSAR-BE-1199: REQUEST_VALIDATION_FAILED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1199 Request validation failed, but no narrower boundary reason code was attached. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning Request validation failed, but no narrower boundary reason code was attached. ## Probable Causes * Payload shape is missing required fields. * Parameter, query, or body semantics violate route constraints. ## How to Fix 1. Inspect `error.message` and `error.trace` in the response. 2. Correct the payload/params according to OpenAPI schema. 3. Prefer SDK request builders to avoid drift from API contract. ## Retryable No. Retry only after correcting the request input. ## Minimal Trigger Example ```http POST /api/v1/requests HTTP/1.1 Host: localhost:4086 Content-Type: application/json Authorization: Bearer test-token {} ``` # DSAR-BE-1200: REQUEST_RATE_LIMITED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1200 A public intake endpoint exceeded a configured rate limit. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A public intake endpoint exceeded a configured rate limit. ## Probable Causes * A client submitted too many public intake requests in the configured window. * A tenant's public intake channel is receiving a burst above its configured limit. * A webhook provider is retrying aggressively after upstream failures. ## How to Fix 1. Wait for the `Retry-After` response header before retrying. 2. Check the public intake source for loops or retry storms. 3. Adjust runtime intake rate-limit configuration if the limit is too low. ## Retryable Yes. Retry after the number of seconds in the `Retry-After` header. ## Minimal Trigger Example ```http POST /api/v1/webhooks/inbound/resend HTTP/1.1 Host: localhost:4086 Content-Type: application/json X-Forwarded-For: 203.0.113.10 {} ``` # DSAR-BE-1201: REQUEST_ROUTE_NOT_FOUND URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1201 No backend route is registered for the incoming method/path combination. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning No backend route is registered for the incoming method/path combination. ## Probable Causes * Typo in endpoint path or wrong API version prefix. * Incorrect method (`POST` vs `GET`). ## How to Fix 1. Check path/method against OpenAPI docs. 2. Ensure base path is included (`/api/v1` when configured). ## Retryable No. Retry only after correcting route path or method. ## Minimal Trigger Example ```http GET /api/v1/unknown HTTP/1.1 Host: localhost:4086 ``` # DSAR-BE-1202: POLICY_ACTIVATION_NOT_FOUND URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1202 No active policy activation was found for the tenant/workspace scope. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning No active policy activation was found for the tenant/workspace scope. ## Probable Causes * Policy upgrade has not been activated for the target scope. * Request references a workspace without a policy activation. ## How to Fix 1. Activate a policy pack for the target tenant/workspace. 2. Re-run the request with a scope that has an active policy. ## Retryable No. Retry only after policy activation exists. ## Minimal Trigger Example ```http GET /api/v1/policies/active?tenantId=tenant-default HTTP/1.1 Host: localhost:4086 authorization: Bearer test-token ``` # DSAR-BE-1203: POLICY_UPGRADE_PROPOSAL_NOT_FOUND URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1203 The requested policy upgrade proposal was not found for the current tenant/workspace scope. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The requested policy upgrade proposal was not found for the current tenant/workspace scope. ## Probable Causes * The proposal ID is unknown or expired. * The proposal belongs to a different tenant or workspace. * The proposal was already applied, removed, or recreated under a different ID. ## How to Fix 1. List or create policy upgrade proposals for the authenticated tenant/workspace. 2. Retry the approve or apply operation with a proposal ID from that scoped result. 3. Confirm the caller is using the intended tenant and workspace context. ## Retryable No. Retry only after using a proposal ID that exists in the caller's scope. ## Minimal Trigger Example ```http POST /api/v1/policies/upgrades/proposal-unknown/approve HTTP/1.1 Host: localhost:4086 authorization: Bearer test-token ``` # DSAR-BE-1204: DELIVERY_ARTIFACT_NOT_FOUND URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1204 No fulfilment artifact exists for the target request. Delivery operations require a fulfilment callback to have been recorded first. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning No fulfilment artifact exists for the target request. Delivery operations require a fulfilment callback to have been recorded first. ## Probable Causes * The fulfilment callback has not been submitted for this request yet. * The request ID does not match any existing fulfilment artifact. * The artifact was purged by a retention policy. ## How to Fix 1. Submit a fulfilment callback for the request before attempting delivery operations. 2. Verify the request ID is correct and corresponds to a request with a recorded fulfilment artifact. ## Retryable No. Retry only after a fulfilment artifact has been created for the request. ## Minimal Trigger Example ```http POST /api/v1/requests/req-123/delivery/prepare HTTP/1.1 Host: localhost:4086 Authorization: Bearer test-token Content-Type: application/json {"channel": "portal", "securityLevel": "standard"} ``` # DSAR-BE-1205: DELIVERY_TOKEN_INVALID URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1205 The delivery token is missing, expired, or does not match the expected value. Delivery downloads and step-up challenge completions require a valid token. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The delivery token is missing, expired, or does not match the expected value. Delivery downloads and step-up challenge completions require a valid token. ## Probable Causes * The `x-delivery-token` header was not included in the artifact download request. * The step-up challenge token submitted does not match the issued token. * The token has expired. Tokens are valid for 24 hours (86 400 seconds) after issuance. This TTL is hardcoded in the backend; the policy field `tokenTtlSeconds` is not honored at runtime. ## How to Fix 1. Complete a step-up challenge to obtain a valid delivery token. 2. Include the token in the `x-delivery-token` header when downloading artifacts. 3. If the token has expired, request a new step-up challenge. ## Retryable No. A new valid token must be obtained before retrying. ## Minimal Trigger Example ```http GET /api/v1/requests/req-123/artifacts/art-456/download HTTP/1.1 Host: localhost:4086 authorization: Bearer test-token ``` # DSAR-BE-1206: MANIFEST_ARTIFACT_UPLOAD_FAILED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1206 Upload of a fulfilment manifest artifact to storage failed. The file could not be persisted to the configured storage adapter. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning Upload of a fulfilment manifest artifact to storage failed. The file could not be persisted to the configured storage adapter. ## Probable Causes * The storage adapter is not configured (running with "stub" storage). * The uploaded file body is empty (zero bytes). * The storage adapter encountered a write error (disk full, network timeout, permission denied). ## How to Fix 1. Ensure a real storage adapter is configured (not "stub") — check the backend configuration. 2. Verify the file is non-empty before uploading. 3. Check storage connectivity and permissions if the adapter is correctly configured. ## Retryable Yes — if the storage adapter was temporarily unavailable, retrying the upload may succeed. ## Minimal Trigger Example ```http POST /api/v1/requests/req-123/manifest/artifact/upload HTTP/1.1 Host: localhost:4086 authorization: Bearer test-token x-artifact-filename: data-export.csv x-artifact-content-type: text/csv Content-Type: text/csv ``` # DSAR-BE-1207: MANIFEST_ARTIFACT_DOWNLOAD_FAILED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1207 Download of a fulfilment manifest artifact from storage failed. The requested file could not be retrieved. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning Download of a fulfilment manifest artifact from storage failed. The requested file could not be retrieved. ## Probable Causes * The artifact (identified by `artifactId`) does not exist in storage. * The artifact's storage key does not belong to the target request (cross-request access denied). * The storage adapter is not configured (running with "stub" storage). * The storage adapter encountered a read error (network timeout, permission denied). ## How to Fix 1. Verify the `artifactId` is correct. The request query parameter uses `artifactId` to find an artifact entry in the manifest's `artifacts` array, then the server uses that artifact's `storageKey` for the actual storage lookup. 2. Ensure the resolved artifact storage key belongs to the correct request ID. 3. Check storage connectivity and permissions if the adapter is correctly configured. ## Retryable Yes — if the storage adapter was temporarily unavailable, retrying the download may succeed. ## Minimal Trigger Example ```http GET /api/v1/requests/req-123/manifest/artifact/download?artifactId=art-1 HTTP/1.1 Host: localhost:4086 Authorization: Bearer test-token ``` # DSAR-BE-1208: MANIFEST_ARTIFACT_REPLACE_FAILED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1208 Replacement of an existing fulfilment manifest artifact failed. The artifact could not be overwritten in storage. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning Replacement of an existing fulfilment manifest artifact failed. The artifact could not be overwritten in storage. ## Probable Causes * The artifact ID does not exist in the manifest's `artifacts` array. * No fulfilment manifest record exists for the target request. * The uploaded file body is empty (zero bytes). * The storage adapter is not configured (running with "stub" storage). * The storage adapter encountered a write error during overwrite. ## How to Fix 1. Verify the artifact ID exists in the manifest — use `GET /requests/:id/manifest` to inspect the artifacts list. 2. Ensure a fulfilment manifest has been created for the request before attempting replacement. 3. Verify the replacement file is non-empty. 4. Check storage connectivity and permissions if the adapter is correctly configured. ## Retryable Yes — if the storage adapter was temporarily unavailable, retrying the replacement may succeed. ## Minimal Trigger Example ```http PUT /api/v1/requests/req-123/manifest/artifact/art-456/replace HTTP/1.1 Host: localhost:4086 authorization: Bearer test-token x-artifact-filename: data-export-redacted.csv x-artifact-content-type: text/csv Content-Type: text/csv ``` # DSAR-BE-1209: FULFILMENT_MANIFEST_NOT_APPROVED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1209 The fulfilment endpoint requires an approved manifest before the request can transition to `fulfilled` status. The manifest's `validationState` is not `"approved"`. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The fulfilment endpoint requires an approved manifest before the request can transition to `fulfilled` status. The manifest's `validationState` is not `"approved"`. ## Probable Causes * The manifest has not been reviewed yet (`validationState` is `"pending"`). * The manifest was explicitly rejected and has not been re-approved. * Artifacts were uploaded but manifest validation was never triggered. ## How to Fix 1. Navigate to the request detail page and review the fulfilment manifest. 2. Approve the manifest via `POST /requests/:id/manifest/validate` with `{ "action": "approved" }`. 3. Retry the fulfilment action after approval. ## Retryable No. The manifest must be approved before retrying. ## Response Shape ```json { "ok": false, "error": { "id": "DSAR-BE-1209", "code": "FULFILMENT_MANIFEST_NOT_APPROVED", "docsUrl": "https://dsar-sdk.dev/errors/dsar-be-1209", "message": "Fulfilment blocked — manifest not approved", "status": 409, "trace": { "requestId": "req-123" } } } ``` ## Minimal Trigger Example ```http POST /api/v1/requests/req-123/fulfilment HTTP/1.1 Host: localhost:4086 content-type: application/json authorization: Bearer test-token ``` # DSAR-BE-1210: FULFILMENT_NO_ARTIFACTS URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1210 A fulfilment guard determined that no artifacts exist in the manifest. This error is available for integrations or policy guards that require artifacts before fulfilment (e.g. access or portability requests). Request types that do not produce artifacts (deletion, rectification, restriction, objection) are not subject to this guard by default. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A fulfilment guard determined that no artifacts exist in the manifest. This error is available for integrations or policy guards that require artifacts before fulfilment (e.g. access or portability requests). Request types that do not produce artifacts (deletion, rectification, restriction, objection) are not subject to this guard by default. ## Probable Causes * No fulfilment callback or artifact upload has been performed for this request. * Artifacts were uploaded to a different request ID. * A custom policy guard or integration enforces artifact presence. ## How to Fix 1. Upload at least one artifact via `POST /requests/:id/manifest/artifact/upload` or submit a fulfilment callback via `POST /requests/:id/fulfilment/callback`. 2. Verify artifacts are visible via `GET /requests/:id/manifest`. 3. Retry the fulfilment action. ## Retryable No. At least one artifact must exist before retrying. ## Response Shape ```json { "ok": false, "error": { "id": "DSAR-BE-1210", "code": "FULFILMENT_NO_ARTIFACTS", "docsUrl": "https://dsar-sdk.dev/errors/dsar-be-1210", "message": "Fulfilment blocked — no artifacts in manifest", "status": 409, "trace": { "requestId": "req-123" } } } ``` ## Minimal Trigger Example ```http POST /api/v1/requests/req-123/fulfilment HTTP/1.1 Host: localhost:4086 content-type: application/json authorization: Bearer test-token ``` # DSAR-BE-1301: POLICY_JURISDICTION_UNMAPPED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1301 No policy pack mapping exists for the requested jurisdiction. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning No policy pack mapping exists for the requested jurisdiction. ## Probable Causes * Jurisdiction code is unsupported or misspelled. * Policy mapping setup is incomplete. ## How to Fix 1. Use a jurisdiction with an existing policy mapping. 2. Register/activate a mapped pack for the requested jurisdiction. ## Retryable No. Retry only after policy mapping/configuration is corrected. ## Minimal Trigger Example ```http POST /api/v1/requests HTTP/1.1 Host: localhost:4086 Content-Type: application/json Authorization: Bearer test-token {"jurisdiction":"unknown-jurisdiction","intakeSource":{"type":"api"}} ``` # DSAR-BE-1302: POLICY_ENFORCEMENT_REFUSAL_BLOCKED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1302 The active policy for this request does not permit refusal. The `refusalEligible` flag in the policy evaluation decision is `false`. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The active policy for this request does not permit refusal. The `refusalEligible` flag in the policy evaluation decision is `false`. ## Probable Causes * The resolved policy pack explicitly disallows refusal for this request type, jurisdiction, or requestor context. * The request was captured under a policy version where refusal is not a permitted outcome. ## How to Fix 1. Review the active policy pack's rules to confirm whether refusal is intentionally blocked. 2. If refusal should be permitted, update the policy pack configuration or upgrade to a version that allows it. 3. If the request genuinely cannot be fulfilled, use an alternative resolution path (e.g., extension, partial fulfilment). ## Retryable No. The policy decision is computed and stored at capture time. Enforcement — including retries of the same refusal action — reuses that captured decision. The decision will only change if the request is re-captured under an updated policy pack or the capture payload is resubmitted against a new policy version. ## Minimal Trigger Example ```http POST /api/v1/requests/:id/refusals HTTP/1.1 Host: localhost:4086 content-type: application/json authorization: Bearer test-token {"rationale":"Manifestly unfounded request"} ``` # DSAR-BE-1303: POLICY_UPGRADE_APPROVAL_REQUIRED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1303 A policy upgrade must be approved before it can be applied. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A policy upgrade proposal exists, but it has not reached the approval state required for application. ## Probable Causes * The proposal was created but not approved. * The approval step failed or was performed against a different proposal ID. * The caller attempted to apply the proposal before the approval workflow completed. ## How to Fix 1. Approve the policy upgrade proposal for the same tenant/workspace scope. 2. Verify the approval response shows the expected proposal ID and status. 3. Re-run the apply operation after approval succeeds. ## Retryable Yes, after the proposal has been approved. ## Minimal Trigger Example ```http POST /api/v1/policies/upgrades/proposal-1/apply HTTP/1.1 Host: localhost:4086 authorization: Bearer test-token ``` # DSAR-BE-1304: RETENTION_CLASS_INVALID URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1304 The provided retention class is not a recognized value. Retention policies must target one of the predefined data classes. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The provided retention class is not a recognized value. Retention policies must target one of the predefined data classes. ## Probable Causes * The `class` field in the request body is missing or empty. * The value does not match any of the allowed retention classes: `request_record`, `audit_event`, `verification_evidence`, `fulfilment_artifact`, `delivery_log`, `notification_log`. ## How to Fix 1. Set the `class` field to one of the valid retention classes listed above. 2. Check for typos in the class name. ## Retryable No. Fix the request body before retrying. ## Minimal Trigger Example ```http PUT /api/v1/tenants/tenant-default/retention HTTP/1.1 Host: localhost:4086 Authorization: Bearer test-token Content-Type: application/json {"class": "invalid_class", "minDays": 30, "maxDays": 365} ``` # DSAR-BE-1401: LIFECYCLE_TRANSITION_DISALLOWED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1401 The requested lifecycle action is not allowed from the request's current status. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The requested lifecycle action is not allowed from the request's current status. ## Probable Causes * Client attempted transition out of order. * Request state changed between reads and writes. ## How to Fix 1. Read current lifecycle status before issuing transition command. 2. Inspect `error.trace.lifecycle.allowedTransitions` for valid next actions. 3. Follow documented transition matrix. ## Retryable No. Retry only with a valid transition for current state. ## Response Shape ```json { "ok": false, "error": { "id": "DSAR-BE-1401", "code": "LIFECYCLE_TRANSITION_DISALLOWED", "docsUrl": "https://dsar-sdk.dev/errors/dsar-be-1401", "message": "Lifecycle transition disallowed: cannot apply \"extension\" from \"captured\" state.", "status": 409, "trace": { "lifecycle": { "currentState": "captured", "attemptedTransition": "extension", "allowedTransitions": ["verification_request"] } } } } ``` ## Minimal Trigger Example ```http POST /api/v1/requests/req-1/refusals HTTP/1.1 Host: localhost:4086 Content-Type: application/json Authorization: Bearer test-token {"rationale":"refuse from invalid state"} ``` # DSAR-BE-1402: LIFECYCLE_STATUS_UNKNOWN URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1402 The current lifecycle status value is not recognized by the transition state machine. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The current lifecycle status value is not recognized by the transition state machine. ## Probable Causes * Persistence contains legacy or corrupted status value. * Manual data mutation introduced unsupported status. ## How to Fix 1. Normalize persisted lifecycle status to supported values. 2. Add migration for legacy status strings before transition calls. ## Retryable No. Retry only after correcting stored lifecycle status. ## Minimal Trigger Example ```ts applyLifecycleTransition({ requestId: "req-1", currentStatus: "legacy_state", action: "fulfil", }); ``` # DSAR-BE-1403: LIFECYCLE_RATIONALE_MISSING URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1403 The lifecycle action requires a non-empty rationale but none was provided. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The lifecycle action requires a non-empty rationale but none was provided. ## Probable Causes * Client omitted `rationale` in extension/refusal payload. * Rationale field was empty whitespace. ## How to Fix 1. Include a non-empty rationale string for rationale-required actions. 2. Validate rationale input client-side before dispatch. ## Retryable No. Retry only after providing a valid rationale payload. ## Minimal Trigger Example ```http POST /api/v1/requests/req-1/extensions HTTP/1.1 Host: localhost:4086 content-type: application/json authorization: Bearer test-token {"additionalDays":7} ``` # DSAR-BE-1410: PERSISTENCE_TENANT_SCOPE_MISSING URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1410 A backend persistence operation was attempted without the required tenant scope. Every database query must be scoped to a tenant to enforce data isolation. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A backend persistence operation was attempted without the required tenant scope. Every database query must be scoped to a tenant to enforce data isolation. ## Probable Causes * The request pipeline did not resolve or inject a tenant ID. * Middleware that sets tenant scope was bypassed or misconfigured. * A background job or internal service call omitted the tenant context. ## How to Fix 1. Ensure all persistence calls are wrapped with `withTenant(tenantId)`. 2. Verify tenant resolution middleware is active in the request pipeline. 3. For background jobs, explicitly provide the tenant ID from the job payload. ## Retryable No. The tenant scope must be provided before retrying. ## Response Shape ```json { "ok": false, "error": { "id": "DSAR-BE-1410", "code": "PERSISTENCE_TENANT_SCOPE_MISSING", "message": "Persistence operation is missing required tenant scope.", "status": 500, "trace": { "operation": "tenant_scope_lookup", "type": "MissingTenantScopeError" } } } ``` ## Minimal Trigger Example Any persistence query executed outside a `withTenant` scope. # DSAR-BE-1411: PERSISTENCE_ENTITY_NOT_FOUND URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1411 A persistence lookup for a specific entity returned no results within the backend request pipeline. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A persistence lookup for a specific entity returned no results within the backend request pipeline. ## Probable Causes * The entity ID does not exist in the database. * The entity was deleted or belongs to a different tenant. * A typo or stale reference in the request payload. ## How to Fix 1. Verify the entity ID is correct and exists for the current tenant. 2. Check whether the entity was recently deleted or archived. 3. Inspect `error.trace.entity` and `error.trace.id` for the lookup details. ## Retryable No. The entity must exist before the operation can succeed. ## Response Shape ```json { "ok": false, "error": { "id": "DSAR-BE-1411", "code": "PERSISTENCE_ENTITY_NOT_FOUND", "message": "Entity not found: request (req-123).", "status": 404, "trace": { "entity": "request", "id": "req-123", "type": "PersistenceEntityNotFoundError" } } } ``` ## Minimal Trigger Example ```http GET /api/v1/requests/nonexistent-id HTTP/1.1 Host: localhost:4086 ``` # DSAR-BE-1412: PERSISTENCE_OPERATION_UNSUPPORTED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1412 The persistence layer does not support the requested operation for the given entity or context within the backend request pipeline. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The persistence layer does not support the requested operation for the given entity or context within the backend request pipeline. ## Probable Causes * Attempted an operation that is not implemented by the current persistence adapter. * Called a write operation on a read-only entity or view. * Used a feature that requires a specific database backend not currently configured. ## How to Fix 1. Check `error.trace.operation` and `error.trace.reason` for specifics. 2. Verify the persistence adapter supports the intended operation. 3. Use an alternative approach or enable the required feature. ## Retryable No. The operation is structurally unsupported and requires a code or configuration change. ## Response Shape ```json { "ok": false, "error": { "id": "DSAR-BE-1412", "code": "PERSISTENCE_OPERATION_UNSUPPORTED", "message": "Persistence operation is not supported.", "status": 400, "trace": { "operation": "bulkDelete", "reason": "not implemented", "type": "UnsupportedPersistenceOperationError" } } } ``` ## Minimal Trigger Example Calling an unsupported persistence method through the backend API. # DSAR-BE-1413: PERSISTENCE_INVALID_RECORD URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1413 A record retrieved from the database violates the expected domain contract (e.g. an enum field contains an unrecognised value). > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A record retrieved from the database violates the expected domain contract (e.g. an enum field contains an unrecognised value). ## Probable Causes * Database was modified directly, bypassing application-level validation. * A migration introduced or removed valid enum values without updating all records. * Data corruption or encoding issue in the storage layer. ## How to Fix 1. Inspect `error.trace.entity` and `error.trace.field` for the offending record. 2. Verify the stored value against the current domain schema. 3. Run a data migration to correct invalid records. ## Retryable No. The underlying data must be corrected first. ## Response Shape ```json { "ok": false, "error": { "id": "DSAR-BE-1413", "code": "PERSISTENCE_INVALID_RECORD", "message": "Persisted record violates domain contract.", "status": 400, "trace": { "entity": "retention_policy", "field": "retentionClass", "type": "PersistenceInvalidRecordError" } } } ``` ## Minimal Trigger Example ```ts // Stored row has an unexpected enum value: // retentionClass = "legacy_hold" or status = "stale_state" const policy = await persistence.retentionPolicies.findById(policyId); // Reading this row triggers DSAR-BE-1413 (PERSISTENCE_INVALID_RECORD) // because `retentionClass` / `status` cannot be decoded to domain enums. ``` # DSAR-BE-1414: PERSISTENCE_SQL_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1414 A raw SQL query executed by the persistence layer failed. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A raw SQL query executed by the persistence layer failed. ## Probable Causes * Syntax error in a dynamically constructed query. * Database connection dropped or timed out mid-query. * Schema mismatch — a referenced table or column does not exist. * Constraint violation (unique, foreign key, check) at the database level. ## How to Fix 1. Inspect server logs for the full SQL error message and query context. 2. Verify database connectivity and credentials. 3. Ensure migrations have been applied so the schema matches the application's expectations. 4. Check for constraint violations in the input data. ## Retryable Depends on the cause. Connection timeouts are retriable; schema and constraint errors are not. ## Response Shape ```json { "ok": false, "error": { "id": "DSAR-BE-1414", "code": "PERSISTENCE_SQL_ERROR", "message": "SQL query execution failure", "status": 500, "trace": { "type": "SqlError" } } } ``` ## Minimal Trigger Example ```ts // Example 1: schema mismatch (column does not exist) await db.execute(sql`SELECT non_existent_column FROM retention_policies`); // -> DSAR-BE-1414 (PERSISTENCE_SQL_ERROR) // Example 2: NOT NULL constraint violation await db.execute( sql`INSERT INTO retention_policies (id, tenant_id, status) VALUES (${id}, NULL, 'active')` ); // -> DSAR-BE-1414 (PERSISTENCE_SQL_ERROR) ``` # DSAR-BE-1500: INTERNAL_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1500 An unhandled backend runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled backend runtime exception occurred. ## Probable Causes * Unexpected bug in route/service logic. * Dependency failure not mapped to a typed domain error. ## How to Fix 1. Inspect server logs for `handled_error`/`unhandled_error` payload and stack. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example Any uncaught exception thrown by backend runtime path. # DSAR-BE-1599: INTERNAL_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-be-1599 The runtime emitted an error code that is not present in the backend catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the backend catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to backend catalog. 2. Add matching per-code docs markdown file. 3. Update OpenAPI error code schema and tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in `error-catalog.ts`. # DSAR-CLI-1500: CLI_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-cli-1500 An unhandled CLI runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled CLI runtime exception occurred. ## Probable Causes * Unexpected bug in CLI command logic. * Dependency failure not mapped to a typed domain error. ## How to Fix 1. Inspect stderr output for stack trace and context. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example Any uncaught exception thrown during CLI command execution. # DSAR-CLI-1599: CLI_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-cli-1599 The runtime emitted an error code that is not present in the CLI catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the CLI catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to CLI catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in the CLI error catalog. # DSAR-CORE-1500: CORE_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-core-1500 An unhandled core runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled core runtime exception occurred. ## Probable Causes * Unexpected bug in core logic. * Dependency failure not mapped to a typed domain error. ## How to Fix 1. Inspect logs for stack trace and context. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example Any uncaught exception thrown by core runtime path. # DSAR-CORE-1599: CORE_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-core-1599 The runtime emitted an error code that is not present in the core catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the core catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to core catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in the core error catalog. # DSAR-FS-1001: STORAGE_FILESYSTEM_RETRY_EXHAUSTED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-fs-1001 A filesystem storage operation failed after exhausting all configured retry attempts. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A filesystem storage operation failed after exhausting all configured retry attempts. ## Probable Causes * Persistent I/O errors (permission denied, disk full, file locked) across all retries. * The target directory or mount point became unavailable during operation. * Retry budget (`retryMaxAttempts`) is too low for the current error rate. ## How to Fix 1. Inspect `error.details.lastError` for the message of the final failed attempt. 2. Verify the storage directory exists and has correct read/write permissions. 3. Check available disk space on the target volume. 4. Increase `retryMaxAttempts` in the storage adapter configuration if appropriate. ## Retryable No — retries are already exhausted. Address the root cause before retrying the outer operation. ## Minimal Trigger Example ```ts import { makeFilesystemStorageAdapter } from "@dsar/storage-filesystem"; const adapter = makeFilesystemStorageAdapter({ baseDir: "/unwritable-path", retryMaxAttempts: 2, }); try { await adapter.putObject({ bytes: new TextEncoder().encode("{}"), contentType: "application/json", key: "requests/req-1.json", }); } catch (error) { if (error && typeof error === "object" && "code" in error) { if (error.code === "DSAR-FS-1001") { console.error("Last filesystem error:", error.details?.lastError); } } } ``` # DSAR-FS-1500: STORAGE_FILESYSTEM_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-fs-1500 An unhandled filesystem storage runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled filesystem storage runtime exception occurred. ## Probable Causes * Unexpected bug in filesystem storage logic. * I/O or permission failure not mapped to a typed domain error. ## How to Fix 1. Inspect logs for stack trace and context. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example Any uncaught exception thrown during filesystem storage operations. # DSAR-FS-1599: STORAGE_FILESYSTEM_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-fs-1599 The runtime emitted an error code that is not present in the filesystem storage catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the filesystem storage catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to filesystem storage catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in the filesystem storage error catalog. # DSAR-GRD-1500: GUARDS_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-grd-1500 An unhandled guards runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled guards runtime exception occurred. ## Probable Causes * Unexpected bug in guard evaluation logic. * Dependency failure not mapped to a typed domain error. ## How to Fix 1. Inspect logs for stack trace and context. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example Any uncaught exception thrown during guard evaluation. # DSAR-GRD-1599: GUARDS_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-grd-1599 The runtime emitted an error code that is not present in the guards catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the guards catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to guards catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in the guards error catalog. # DSAR-IN-1001: INBOUND_RESEND_CONTENT_FETCH_FAILED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-in-1001 The inbound Resend adapter failed to retrieve the content of a received email from the Resend API. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The inbound Resend adapter failed to retrieve the content of a received email from the Resend API. ## Probable Causes * Resend API returned an error when fetching email content by ID. * Network connectivity issue between the backend and Resend servers. * Invalid or expired Resend API credentials. * The referenced email ID does not exist or has been purged. ## How to Fix 1. Inspect `error.details` for the upstream Resend error message and status. 2. Verify Resend API key is valid and has sufficient permissions. 3. Confirm the email ID exists in the Resend dashboard. 4. Retry if the failure is transient (network/timeout). ## Retryable Depends on the underlying cause. Network and timeout errors are retriable; auth and validation errors are not. ## Minimal Trigger Example An inbound webhook processes an email whose content cannot be fetched from the Resend API. # DSAR-IN-1500: INBOUND_RESEND_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-in-1500 An unhandled inbound Resend adapter runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled inbound Resend adapter runtime exception occurred. ## Probable Causes * Unexpected bug in inbound Resend logic. * Resend webhook or dependency failure not mapped to a typed domain error. ## How to Fix 1. Inspect logs for stack trace and context. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example Any uncaught exception thrown during inbound Resend operations. # DSAR-IN-1599: INBOUND_RESEND_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-in-1599 The runtime emitted an error code that is not present in the inbound Resend catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the inbound Resend catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to inbound Resend catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in the inbound Resend error catalog. # DSAR-OUT-1001: OUTBOUND_RESEND_CONFIG_INVALID URL: https://dsar-sdk.dev/docs/reference/errors/dsar-out-1001 The outbound Resend adapter configuration failed validation. The adapter cannot initialize with the provided settings. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The outbound Resend adapter configuration failed validation. The adapter cannot initialize with the provided settings. ## Probable Causes * Missing or empty `apiKey` in the Resend adapter configuration. * Invalid `from` email address format. * Unsupported or malformed configuration values passed during adapter setup. ## How to Fix 1. Inspect `error.details.parseError` for the specific validation failure. Example (`error.details.parseError`) for a validation failure: ```json { "parseError": { "path": ["from"], "message": "Invalid email address format" } } ``` This is a sample parse payload you may see when config schema validation fails. 2. Verify all required configuration fields are set (`apiKey`, `from`). 3. Ensure email addresses conform to RFC 5322 format. 4. Check environment variables that feed into the adapter configuration. ## Retryable No. The configuration must be corrected before the adapter can initialize. ## Minimal Trigger Example ```ts // Triggers DSAR-OUT-1001: missing API key createResendAdapter({ apiKey: "", from: "noreply@example.com" }); // Triggers DSAR-OUT-1001: invalid sender format createResendAdapter({ apiKey: "re_valid_key", from: "invalid-email" }); ``` # DSAR-OUT-1500: OUTBOUND_RESEND_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-out-1500 An unhandled outbound Resend adapter runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled outbound Resend adapter runtime exception occurred. ## Probable Causes * Resend API request failed at runtime (for example: transient 5xx, timeout, or connection reset). * Dependency/runtime fault (network client, serialization, environment config, or provider SDK issue). * Unexpected exception path in outbound send code. ## How to Fix 1. Inspect logs with correlation IDs, stack traces, and request context to identify the failing boundary. 2. Add runtime hardening (timeouts, retries with backoff, and defensive handling around provider calls). 3. Apply a hotfix for the root cause and add regression tests for the runtime failure mode. 4. If failures persist, investigate deeper code or dependency issues beyond transient conditions. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example ```ts import { resolveOutboundResendErrorCatalogEntry } from "@dsar/outbound-resend"; const entry = resolveOutboundResendErrorCatalogEntry("UNKNOWN_CODE_XYZ"); console.log(entry.code); // "OUTBOUND_RESEND_UNCATALOGED_ERROR" (DSAR-OUT-1599) ``` # DSAR-OUT-1599: OUTBOUND_RESEND_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-out-1599 The runtime emitted an error code that is not present in the outbound Resend catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the outbound Resend catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to outbound Resend catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in the outbound Resend error catalog. # DSAR-PE-1500: POLICY_ENGINE_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-pe-1500 An unhandled policy engine runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled policy engine runtime exception occurred. ## Probable Causes * Unexpected bug in policy evaluation logic. * Dependency failure not mapped to a typed domain error. ## How to Fix 1. Inspect logs for stack trace and context. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example Any uncaught exception thrown during policy evaluation. # DSAR-PE-1599: POLICY_ENGINE_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-pe-1599 The runtime emitted an error code that is not present in the policy engine catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the policy engine catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to policy engine catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in the policy engine error catalog. # DSAR-PG-1500: PERSISTENCE_PG_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-pg-1500 An unhandled PostgreSQL persistence runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled PostgreSQL persistence runtime exception occurred. ## Probable Causes * Unexpected bug in PostgreSQL persistence logic. * Database connection or query failure not mapped to a typed domain error. ## How to Fix 1. Inspect logs for stack trace and context. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example Any uncaught exception thrown during PostgreSQL persistence operations. # DSAR-PG-1599: PERSISTENCE_PG_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-pg-1599 The runtime emitted an error code that is not present in the PostgreSQL persistence catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the PostgreSQL persistence catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to PostgreSQL persistence catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in the PostgreSQL persistence error catalog. # DSAR-PP-1001: POLICY_PACKS_CHECKSUM_FAILED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-pp-1001 Computing a SHA-256 checksum for a policy pack failed. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning Computing a SHA-256 checksum for a policy pack failed. ## Probable Causes * The policy pack payload could not be serialized to a stable canonical form. * An unexpected runtime error in the hashing implementation. * Invalid or circular data structure in the policy pack definition. ## How to Fix 1. Inspect the `cause` field for the underlying error message. 2. Verify the policy pack JSON is well-formed and serializable. 3. Ensure the runtime environment supports the Web Crypto / Node.js crypto API. ## Retryable No. The policy pack content must be valid before a checksum can be computed. ## Minimal Trigger Example ```ts const policyPack: Record = { id: "pack-1", rules: [], }; policyPack.self = policyPack; // circular reference (non-serializable) await computePolicyPackChecksum(policyPack); // -> throws PolicyChecksumComputationError (DSAR-PP-1001) ``` # DSAR-PP-1500: POLICY_PACKS_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-pp-1500 An unhandled policy packs runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled policy packs runtime exception occurred. ## Probable Causes * Unexpected bug in policy pack loading or evaluation logic. * Dependency failure not mapped to a typed domain error. ## How to Fix 1. Inspect logs for stack trace and context. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example Any uncaught exception thrown during policy pack operations. # DSAR-PP-1599: POLICY_PACKS_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-pp-1599 The runtime emitted an error code that is not present in the policy packs catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the policy packs catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in error code from throw site. ## How to Fix 1. Add the missing code to policy packs catalog. 2. Add matching per-code docs markdown file. 3. Update policy-packs error-code contract tests to include `DSAR-PP-1599` (`dsar-pp-1599`). ## Retryable Unknown until cataloged. Do not assume retryability from `POLICY_PACKS_UNCATALOGED_ERROR` alone; determine transience from cataloged error types and instrumentation. ## Minimal Trigger Example ```ts import { resolvePolicyPacksErrorCatalogEntry } from "@dsar/policy-packs"; const entry = resolvePolicyPacksErrorCatalogEntry( "POLICY_PACKS_NOT_A_REAL_CODE" ); console.log(entry.code); // "POLICY_PACKS_UNCATALOGED_ERROR" ``` # DSAR-PS-1001: PERSISTENCE_TENANT_SCOPE_MISSING URL: https://dsar-sdk.dev/docs/reference/errors/dsar-ps-1001 A persistence operation was attempted without the required tenant scope context. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A persistence operation was attempted without the required tenant scope context. ## Probable Causes * The request pipeline did not set a tenant ID before invoking persistence queries. * Middleware that injects tenant scope was bypassed or misconfigured. * A background job or internal service call omitted the tenant context. ## How to Fix 1. Ensure all persistence calls are wrapped with `withTenant(tenantId)`. 2. Verify tenant resolution middleware is active in the request pipeline. 3. For background jobs, explicitly provide the tenant ID from the job payload. ## Retryable No. The tenant scope must be provided before retrying. ## Response Shape ```json { "ok": false, "error": { "id": "DSAR-PS-1001", "code": "PERSISTENCE_TENANT_SCOPE_MISSING", "message": "Persistence operation missing tenant scope", "status": 500, "trace": { "operation": "readPolicies", "type": "MissingTenantScopeError" } } } ``` ## Minimal Trigger Example ```ts // Bad: outside tenant scope, can trigger DSAR-PS-1001 await persistence.requests.findById(requestId); // Good: scoped call with tenant context await withTenant(tenantId, () => persistence.requests.findById(requestId)); ``` # DSAR-PS-1002: PERSISTENCE_ENTITY_NOT_FOUND URL: https://dsar-sdk.dev/docs/reference/errors/dsar-ps-1002 A persistence lookup for a specific entity returned no results. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A persistence lookup for a specific entity returned no results. ## Probable Causes * The entity ID does not exist in the database. * The entity was deleted or belongs to a different tenant. * A typo or stale reference in the request payload. ## How to Fix 1. Verify the entity ID is correct and exists for the current tenant. 2. Check whether the entity was recently deleted or archived. 3. Inspect `error.trace.entity` and `error.trace.id` for the lookup details. ## Retryable No. The entity must exist before the operation can succeed. ## Response Shape ```json { "ok": false, "error": { "id": "DSAR-PS-1002", "code": "PERSISTENCE_ENTITY_NOT_FOUND", "message": "Entity not found: request (req-123).", "status": 404, "trace": { "entity": "request", "id": "req-123", "type": "PersistenceEntityNotFoundError" } } } ``` ## Minimal Trigger Example Any persistence `getById` call with a non-existent entity ID. # DSAR-PS-1003: PERSISTENCE_OPERATION_UNSUPPORTED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-ps-1003 The persistence layer does not support the requested operation for the given entity or context. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The persistence layer does not support the requested operation for the given entity or context. ## Probable Causes * Attempted an operation that is not implemented by the current persistence adapter. * Called a write operation on a read-only entity or view. * Used a feature that requires a specific database backend not currently configured. ## How to Fix 1. Check `error.trace.operation` and `error.trace.reason` for specifics. 2. Verify the persistence adapter supports the intended operation. 3. Use an alternative approach or enable the required feature. ## Retryable No. The operation is structurally unsupported and requires a code or configuration change. ## Minimal Trigger Example Calling an unsupported persistence method on an entity that does not implement it. ## Response Shape ```json { "errorCode": "DSAR-PS-1003", "message": "Persistence operation is not supported for this entity.", "entity": "audit_events", "attemptedMethod": "bulkUpsert", "timestamp": "2026-03-03T12:00:00.000Z", "details": { "adapter": "sqlite", "operation": "bulkUpsert" }, "suggestion": "Use append or switch to an adapter that supports bulk writes." } ``` # DSAR-PS-1004: PERSISTENCE_INVALID_RECORD URL: https://dsar-sdk.dev/docs/reference/errors/dsar-ps-1004 A record retrieved from the database violates the expected domain contract (e.g. an enum field contains an unrecognised value). > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A record retrieved from the database violates the expected domain contract (e.g. an enum field contains an unrecognised value). ## Probable Causes * Database was modified directly, bypassing application-level validation. * A migration introduced or removed valid enum values without updating all records. * Data corruption or encoding issue in the storage layer. ## How to Fix 1. Inspect `error.trace.entity` and `error.trace.field` for the offending record. 2. Verify the stored value against the current domain schema. 3. Run a data migration to correct invalid records. 4. If `error.trace.entity` or `error.trace.field` is missing/redacted, identify affected rows using record identifiers (record ID, primary key, and query context), then generate a schema diff between stored values and the current domain schema. 5. Review migrations and change logs for the relevant deployment window to find when the schema/value divergence began, then run a targeted data migration to fix only invalid records. 6. Add diagnostic logging when trace metadata is absent: record ID, attempted field path, schema diff summary, and migration window. ## Retryable No. The underlying data must be corrected first. ## Minimal Trigger Example Reading a record whose `status` or `retentionClass` column contains an unrecognised value. # DSAR-PS-1500: PERSISTENCE_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-ps-1500 An unhandled persistence layer runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled persistence layer runtime exception occurred. ## Probable Causes * Unexpected bug in persistence logic. * Backend storage failure not mapped to a typed domain error. ## How to Fix 1. Inspect logs for stack trace and context. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example Any uncaught exception thrown during persistence operations. # DSAR-PS-1599: PERSISTENCE_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-ps-1599 The runtime emitted an error code that is not present in the persistence catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the persistence catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to persistence catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in the persistence error catalog. # DSAR-S3-1500: STORAGE_S3_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-s3-1500 An unhandled S3 storage runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled S3 storage runtime exception occurred. ## Probable Causes * Unexpected bug in S3 storage logic. * AWS API or credential failure not mapped to a typed domain error. ## How to Fix 1. Inspect logs for stack trace and context. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example Any uncaught exception thrown during S3 storage operations. # DSAR-S3-1599: STORAGE_S3_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-s3-1599 The runtime emitted an error code that is not present in the S3 storage catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the S3 storage catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to S3 storage catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example ```ts const mapError = () => ({ code: "S3_NOT_IN_CATALOG" }); const mapped = mapError(); // catalog lookup fails for this unregistered code ``` # DSAR-SCH-1500: SCHEMA_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-sch-1500 An unhandled schema runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled schema runtime exception occurred. ## Probable Causes * Unexpected bug in schema validation or serialization logic. * Dependency failure not mapped to a typed domain error. ## How to Fix 1. Inspect logs for stack trace and context. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example Any uncaught exception thrown during schema operations. # DSAR-SCH-1599: SCHEMA_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-sch-1599 The runtime emitted an error code that is not present in the schema catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the schema catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to schema catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable No. `SCHEMA_UNCATALOGED_ERROR` is a catalog/code defect (missing catalog entry or throw-site typo) and retrying the same request does not resolve it. If a transient downstream failure exists, handle that separately; the uncataloged error itself is a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in the schema error catalog. # DSAR-SDK-1101: SDK_NETWORK_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-sdk-1101 The SDK could not complete the HTTP request due to a network-level failure. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The SDK could not complete the HTTP request due to a network-level failure. ## Probable Causes * DNS resolution failure. * Connection refused or reset. * No internet connectivity. ## How to Fix 1. Verify network connectivity and DNS. 2. Ensure target host is reachable. 3. Check firewall/proxy settings. ## Retryable Yes. Network failures are often transient. ## Minimal Trigger Example ```ts // Request to unreachable host const client = createClient({ baseUrl: "http://nonexistent.invalid" }); await client.requests.capture({ ... }); ``` # DSAR-SDK-1102: SDK_TIMEOUT URL: https://dsar-sdk.dev/docs/reference/errors/dsar-sdk-1102 The SDK HTTP request exceeded the configured timeout before completing. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The SDK HTTP request exceeded the configured timeout before completing. ## Probable Causes * Server is slow or overloaded. * Network latency too high. * Timeout configured too low. ## How to Fix 1. Increase timeout in client configuration. 2. Investigate server performance. 3. Retry with exponential backoff. ## Retryable Yes. Timeouts are often transient. ## Minimal Trigger Example ```ts const client = createClient({ baseUrl: "...", timeout: 1 }); await client.requests.capture({ /* ... */ }); // Server responds after >1ms, so request will time out with timeout: 1 ``` # DSAR-SDK-1201: SDK_HTTP_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-sdk-1201 The server returned an HTTP error status (4xx or 5xx) that the SDK mapped to this code. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The server returned an HTTP error status (4xx or 5xx) that the SDK mapped to this code. ## Probable Causes * Server rejected the request (validation, auth, etc.). * Server internal error. ## How to Fix 1. Inspect `error.status` and `error.message`. 2. Fix request payload or auth headers per server requirements. 3. For 5xx, retry with backoff or contact service owner. ## Retryable Yes for 5xx. No for 4xx unless request is corrected. ## Minimal Trigger Example ```ts await client.requests.capture({ ... }); // Server returns 400 or 500 ``` # DSAR-SDK-1301: SDK_INVALID_ENVELOPE URL: https://dsar-sdk.dev/docs/reference/errors/dsar-sdk-1301 The SDK received an HTTP response that could not be parsed as a valid error envelope. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The SDK received an HTTP response that could not be parsed as a valid error envelope. ## Probable Causes * Server returned non-JSON or malformed JSON. * Response missing required envelope fields. * Proxy or middleware altered the response. ## How to Fix 1. Verify server returns valid JSON error envelope. 2. Check for proxies that modify responses. 3. Ensure SDK and server versions are compatible. ## Retryable No. Retry only after fixing response format. ## Minimal Trigger Example ```ts // Server returns HTML error page instead of JSON await client.requests.capture({ ... }); ``` # DSAR-SDK-1500: SDK_RETRY_FAILED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-sdk-1500 The SDK exhausted retries and the request still failed. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The SDK exhausted retries and the request still failed. ## Probable Causes * Persistent network or server failure. * Upstream dependency issues such as API rate limiting, auth failures, DNS/proxy misconfiguration, firewall/load-balancer blocking, backend crash, or database outage. * All retry attempts hit timeout or error. ## How to Fix 1. Inspect last error in the chain. 2. Verify service availability. 3. Adjust retry policy or resolve underlying issue. ## Retryable No. Retries have been exhausted. ## Minimal Trigger Example ```ts import { createClient } from "@dsar/node-sdk"; const client = createClient({ baseUrl: "http://down.example", retryMaxAttempts: 3, }); try { await client.requests.capture({ /* capture options */ }); } catch (err) { console.error(err.code, err.errorId, err.docsUrl); // SDK_RETRY_FAILED / DSAR-SDK-1500 } ``` # DSAR-SDK-1599: SDK_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-sdk-1599 The SDK emitted an error code that is not present in the SDK catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The SDK emitted an error code that is not present in the SDK catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to SDK catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in the SDK error catalog. # DSAR-SQL-1500: PERSISTENCE_SQLITE_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-sql-1500 An unhandled SQLite persistence runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled SQLite persistence runtime exception occurred. ## Probable Causes * Unexpected bug in SQLite persistence logic. * Database I/O or constraint failure not mapped to a typed domain error. ## How to Fix 1. Inspect logs for stack trace and context. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example ```ts db.prepare("INSERT INTO unknown_table VALUES (?)").run("value"); // throws and is mapped to PERSISTENCE_SQLITE_RUNTIME_ERROR ``` # DSAR-SQL-1599: PERSISTENCE_SQLITE_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-sql-1599 The runtime emitted an error code that is not present in the SQLite persistence catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the SQLite persistence catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to SQLite persistence catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in the SQLite persistence error catalog. # DSAR-VB-1001: STORAGE_VERCEL_BLOB_FETCH_FAILED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-vb-1001 Fetching the binary payload of a Vercel Blob object failed after a successful `HEAD` request. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning Fetching the binary payload of a Vercel Blob object failed after a successful `HEAD` request. ## Probable Causes * The blob URL returned by `HEAD` is no longer accessible. * Network interruption between the backend and Vercel Blob storage. * The blob was deleted or moved between the `HEAD` and `GET` requests. * Vercel Blob returned a non-2xx HTTP status code. ## How to Fix 1. Check `error.details.httpStatus` for the HTTP status code of the failed fetch. 2. Verify the blob exists in the Vercel Blob dashboard. 3. Confirm the `BLOB_READ_WRITE_TOKEN` is valid and has read permissions. 4. Retry if the failure is transient. ## Retryable Yes, when the cause is a transient network error. Persistent 4xx responses are not retryable. ## Minimal Trigger Example A `getObject` call where the blob URL returns a non-OK HTTP response. # DSAR-VB-1002: STORAGE_VERCEL_BLOB_RETRY_EXHAUSTED URL: https://dsar-sdk.dev/docs/reference/errors/dsar-vb-1002 A Vercel Blob storage operation failed after exhausting all configured retry attempts. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning A Vercel Blob storage operation failed after exhausting all configured retry attempts. ## Probable Causes * Persistent transient errors (timeouts, rate limits, network issues) across all retries. * Vercel Blob service experiencing an extended outage. * Retry budget (`retryMaxAttempts`) is too low for the current error rate. ## How to Fix 1. Inspect `error.details.lastError.message` and `error.details.lastError.code` to identify the underlying failure class. 2. Confirm retry metadata (`error.details.attempts` or `error.details.lastAttempt`) and `error.operation` / `error.type` so logs show exactly which operation exhausted retries. 3. Surface these fields in logs and alerts: `lastError.message`, `lastError.code`, retry attempt count, and failed operation/type. 4. Check Vercel status (`https://www.vercel-status.com`, or your org status page) for incidents during the failure window. 5. If needed, tune retry settings (for example `storageAdapter.retryMaxAttempts` and `storageAdapter.retryBackoffMs`) and document expected values per environment. 6. Verify blob endpoint reachability and validate storage adapter credentials/tokens. ## Retryable Not automatically retryable until the root cause is addressed. Retries are exhausted for the current operation, but a new attempt may succeed after fixing the underlying issue. ## Minimal Trigger Example A Vercel Blob `put` or `list` operation that fails with retriable errors on every attempt up to the configured maximum. # DSAR-VB-1500: STORAGE_VERCEL_BLOB_RUNTIME_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-vb-1500 An unhandled Vercel Blob storage runtime exception occurred. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning An unhandled Vercel Blob storage runtime exception occurred. ## Probable Causes * Unexpected bug in Vercel Blob storage logic. * Vercel Blob API or credential failure not mapped to a typed domain error. ## How to Fix 1. Inspect logs for stack trace and context. 2. Add explicit domain error mapping for the failing boundary. 3. Patch root cause and add regression tests. ## Retryable Yes, but only when failure is transient. Persistent failures require code fix. ## Minimal Trigger Example Any uncaught exception thrown during Vercel Blob storage operations. # DSAR-VB-1599: STORAGE_VERCEL_BLOB_UNCATALOGED_ERROR URL: https://dsar-sdk.dev/docs/reference/errors/dsar-vb-1599 The runtime emitted an error code that is not present in the Vercel Blob storage catalog and fell back to uncataloged handling. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. ## Meaning The runtime emitted an error code that is not present in the Vercel Blob storage catalog and fell back to uncataloged handling. ## Probable Causes * New error code emitted without catalog/docs entry. * Typo in reason code string from throw site. ## How to Fix 1. Add the missing code to Vercel Blob storage catalog. 2. Add matching per-code docs markdown file. 3. Update tests. ## Retryable Yes for transient failures, but treat as a release-quality defect. ## Minimal Trigger Example A mapper returns a code not defined in the Vercel Blob storage error catalog. # DSAR Docs URL: https://dsar-sdk.dev/docs DSAR ships generated OpenAPI at GET /spec.json and interactive HTTP docs at GET /docs, but the markdown docs in this folder explain how the runtime, integrations, and request lifecycle fit together. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves. DSAR ships generated OpenAPI at `GET /spec.json` and interactive HTTP docs at `GET /docs`, but the markdown docs in this folder explain how the runtime, integrations, and request lifecycle fit together. ## Top-Level Groups * [Guides](./guides) for onboarding, lifecycle walkthroughs, deployments, and build metrics. * [Reference](./reference) for API, developer, persistence, storage, testing, and error catalog documentation. * [Integrations](./integrations) for inbound channels plus auth, outbound, and adapter-specific setup. * [Architecture](./architecture) for runtime boundaries, contracts, versioning, and package layout. ## Recommended Paths * Self-hosted runtime: [Getting Started](./guides/getting-started.md) -> [Backend Runtime Core](./architecture/backend-runtime-core.md) -> [Integrations](./integrations/integrations) -> [API Reference](./reference/api) * Operator tooling: [SDK and Runtime Modes](./reference/developer/sdk-and-runtime.md) -> [Core Request API](./reference/api/requests.md) -> [Verification API](./reference/api/verification.md) -> [Delivery API](./reference/api/delivery.md) * Subject-facing experiences: [Auth Model](./architecture/auth-model.md) -> [Request Lifecycle](./guides/request-lifecycle.md) -> [Examples and Deployment](./guides/examples-and-deployment.md) ## Generated HTTP Contract * Contract source-of-truth: [API Contract Surface](./architecture/api-contract-surface.md) * Base-path-aware generated spec: `GET /spec.json` * Base-path-aware interactive docs: `GET /docs` If you need concrete runnable setups, start with [Examples and Deployment](./guides/examples-and-deployment.md). # Alpha Warning URL: https://dsar-sdk.dev/docs/_shared/alpha-warning Shared alpha-status warning included across DSAR documentation pages. > ⚠️ **Warning:** **Alpha** > DSAR is currently in alpha. APIs, package surfaces, configuration, and documentation may change as the project evolves.