0015: No runtime dependencies in core
Why permdock depends only on @standard-schema/spec, ships ESM-only, and keeps validators, serialisers and OpenTelemetry out of core.
Status
Accepted, September 2026. The size-budget bullet is superseded by 0020.
Context
PermDock core runs in browsers, React Native, edge runtimes, serverless functions, MCP servers and Node. Every dependency it carries is paid by all of them. The landscape has clear examples of the cost:
- Kilpi depends on
zodandsuperjsonin core, so a Kilpi client bundle carries a validator it never calls and a serialiser for dates and maps. @zap-studio/permitmakes@opentelemetry/apia required peer, so apps without tracing still install it.- permix stays at 2.64 kB gzip precisely because it has no dependencies; CASL core is around 6 kB with
@ucast.
Standard Schema exists so that a library can accept Zod, Valibot, ArkType or Effect schemas without depending on any of them. Its spec package is types-only, versioned, and part of PermDock's public API surface (resource definitions take a StandardSchemaV1), which is the documented case for installing it as a regular dependency rather than vendoring the types.
Decision
permdockhas exactly one runtime dependency:@standard-schema/spec. Everything else is an optional peer dependency of the adapter that needs it (react,next,hono,@modelcontextprotocol/server,ai,drizzle-orm, ...).- No validator, no serialiser, no telemetry in core. Conditions and snapshots are plain JSON with tagged ISO date strings; there is no
superjson. OpenTelemetry lives inpermdock/otelbehind a structural, type-onlyTracerinterface. - ESM-only. No CommonJS build, no dual package hazard,
"type": "module"with anexportsmap. - Size is measured, not capped in advance. Per-entry gzip is recorded in
tests/bundle; the regression baseline is the measured size after core ships, not a 3 kB guess (0020). - No
eval, nonew Function, no dynamicrequire; condition evaluation is a switch over the AST.
Consequences
- One install brings no transitive surprises; a React Native or edge bundle contains only what it imports.
- Heavy work belongs in
@permdock/cli(parsers) and@permdock/testing(test frameworks), never inpermdock(0002). - Features that need libraries (delegation-chain signature verification, quota stores, RLS parsing) are adapters or CLI commands, which shapes the roadmap.
- Contributors cannot reach for a utility package; small helpers are written in-tree and covered by tests.
- Keeping validators, serialisers and telemetry out of core also keeps the condition AST, the permission tree and snapshots small. A numeric gzip cap is not set until that core is measured (0020).
Alternatives considered
- Depend on Zod for schemas and validation (Kilpi). Rejected: locks out Valibot and ArkType users and adds tens of kilobytes to clients.
superjsonfor dates and sets in conditions. Rejected: tagged ISO strings cover the RLS-portable subset, and one JSON format must work in Postgres, snapshots and catalogs.- Required
@opentelemetry/apipeer (@zap-studio/permit). Rejected; a type-only logger and tracer interface plus an optionalpermdock/oteladapter gives the same spans without the install. - Dual CJS and ESM builds (CASL). Rejected: the target runtimes are ESM, Node 24 is the floor, and dual builds double the test matrix.
- Vendoring the Standard Schema types. Acceptable per the spec, rejected because the types are part of PermDock's public API and should version with the spec.
Related
0014: Target OpenAPI 3.2 with 3.1 fallbacks
Why PermDock emits OpenAPI 3.2 security objects and downgrades to 3.1 with x-oai-* extensions when a generator only speaks 3.1.
0016: Repository layout and toolchain
The packages, apps and tests layout, the pnpm, Turborepo, tsdown, Oxlint and Vitest toolchain, and the TypeScript 5.9/6/7 support matrix.