@prisma-next/framework-components
Advanced tools
| import { blindCast } from "@prisma-next/utils/casts"; | ||
| //#region src/shared/capabilities.ts | ||
| /** | ||
| * Capability matrix merge primitive shared by emit-time and runtime stack composition. | ||
| * | ||
| * The CLI's `enrichContract` and the SQL runtime's `createExecutionContext` both need | ||
| * to fold a stack of component descriptors' `capabilities` declarations into a single | ||
| * matrix keyed by namespace. Keeping the primitive here lets both call sites stay | ||
| * byte-for-byte consistent without one depending on the other. | ||
| */ | ||
| function isPlainObject(value) { | ||
| return typeof value === "object" && value !== null && !Array.isArray(value); | ||
| } | ||
| function sortDeep(value) { | ||
| if (Array.isArray(value)) return value.map(sortDeep); | ||
| if (!isPlainObject(value)) return value; | ||
| const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b)); | ||
| const next = {}; | ||
| for (const [key, child] of entries) next[key] = sortDeep(child); | ||
| return next; | ||
| } | ||
| function extractCapabilityMatrix(value) { | ||
| if (!isPlainObject(value)) return {}; | ||
| const out = {}; | ||
| for (const [namespace, maybeCaps] of Object.entries(value)) { | ||
| if (!isPlainObject(maybeCaps)) continue; | ||
| const caps = {}; | ||
| for (const [key, flag] of Object.entries(maybeCaps)) if (typeof flag === "boolean") caps[key] = flag; | ||
| if (Object.keys(caps).length > 0) out[namespace] = caps; | ||
| } | ||
| return out; | ||
| } | ||
| /** | ||
| * Merge an ordered list of contributor capability declarations into a base matrix. | ||
| * | ||
| * Behaviour: | ||
| * - `base` and each contributor's `capabilities` are filtered through the same | ||
| * structural extraction: non-plain-object namespace blocks are dropped, | ||
| * non-boolean leaves inside a namespace block are dropped, and a namespace | ||
| * block that ends up with zero boolean leaves is omitted entirely (so a | ||
| * later contributor with a malformed namespace cannot erase a namespace | ||
| * already present in `base`). | ||
| * - Non-plain-object `capabilities` on a contributor (including `undefined`, | ||
| * `null`, arrays, primitives) are skipped silently — the contributor | ||
| * contributes nothing. | ||
| * - Later contributors win on `(namespace, key)` collisions. | ||
| * - The returned object is fresh — neither `base` nor any contributor is mutated. | ||
| * - Output keys are sorted lexicographically at every plain-object level. | ||
| */ | ||
| function mergeCapabilityMatrices(base, contributors) { | ||
| const merged = extractCapabilityMatrix(base); | ||
| for (const contributor of contributors) { | ||
| const extracted = extractCapabilityMatrix(contributor.capabilities); | ||
| for (const [namespace, capabilities] of Object.entries(extracted)) merged[namespace] = { | ||
| ...merged[namespace] ?? {}, | ||
| ...capabilities | ||
| }; | ||
| } | ||
| return blindCast(sortDeep(merged)); | ||
| } | ||
| //#endregion | ||
| export { mergeCapabilityMatrices as t }; | ||
| //# sourceMappingURL=capabilities-BnRAFKP5.mjs.map |
| {"version":3,"file":"capabilities-BnRAFKP5.mjs","names":[],"sources":["../src/shared/capabilities.ts"],"sourcesContent":["/**\n * Capability matrix merge primitive shared by emit-time and runtime stack composition.\n *\n * The CLI's `enrichContract` and the SQL runtime's `createExecutionContext` both need\n * to fold a stack of component descriptors' `capabilities` declarations into a single\n * matrix keyed by namespace. Keeping the primitive here lets both call sites stay\n * byte-for-byte consistent without one depending on the other.\n */\n\nimport { blindCast } from '@prisma-next/utils/casts';\n\nexport type CapabilityMatrix = Record<string, Record<string, boolean>>;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction sortDeep(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortDeep);\n }\n if (!isPlainObject(value)) {\n return value;\n }\n const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));\n const next: Record<string, unknown> = {};\n for (const [key, child] of entries) {\n next[key] = sortDeep(child);\n }\n return next;\n}\n\nfunction extractCapabilityMatrix(value: unknown): CapabilityMatrix {\n if (!isPlainObject(value)) return {};\n\n const out: CapabilityMatrix = {};\n for (const [namespace, maybeCaps] of Object.entries(value)) {\n if (!isPlainObject(maybeCaps)) continue;\n const caps: Record<string, boolean> = {};\n for (const [key, flag] of Object.entries(maybeCaps)) {\n if (typeof flag === 'boolean') {\n caps[key] = flag;\n }\n }\n if (Object.keys(caps).length > 0) {\n out[namespace] = caps;\n }\n }\n\n return out;\n}\n\n/**\n * Merge an ordered list of contributor capability declarations into a base matrix.\n *\n * Behaviour:\n * - `base` and each contributor's `capabilities` are filtered through the same\n * structural extraction: non-plain-object namespace blocks are dropped,\n * non-boolean leaves inside a namespace block are dropped, and a namespace\n * block that ends up with zero boolean leaves is omitted entirely (so a\n * later contributor with a malformed namespace cannot erase a namespace\n * already present in `base`).\n * - Non-plain-object `capabilities` on a contributor (including `undefined`,\n * `null`, arrays, primitives) are skipped silently — the contributor\n * contributes nothing.\n * - Later contributors win on `(namespace, key)` collisions.\n * - The returned object is fresh — neither `base` nor any contributor is mutated.\n * - Output keys are sorted lexicographically at every plain-object level.\n */\nexport function mergeCapabilityMatrices(\n base: Record<string, Record<string, boolean>>,\n contributors: ReadonlyArray<{ readonly capabilities?: unknown }>,\n): Record<string, Record<string, boolean>> {\n const merged: CapabilityMatrix = extractCapabilityMatrix(base);\n\n for (const contributor of contributors) {\n const extracted = extractCapabilityMatrix(contributor.capabilities);\n for (const [namespace, capabilities] of Object.entries(extracted)) {\n merged[namespace] = {\n ...(merged[namespace] ?? {}),\n ...capabilities,\n };\n }\n }\n\n return blindCast<\n CapabilityMatrix,\n \"sortDeep preserves the matrix shape but the recursive generic relationship can't be expressed to TS\"\n >(sortDeep(merged));\n}\n"],"mappings":";;;;;;;;;;AAaA,SAAS,cAAc,OAAkD;CACvE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,SAAS,OAAyB;CACzC,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,MAAM,IAAI,QAAQ;CAE3B,IAAI,CAAC,cAAc,KAAK,GACtB,OAAO;CAET,MAAM,UAAU,OAAO,QAAQ,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;CAC3E,MAAM,OAAgC,CAAC;CACvC,KAAK,MAAM,CAAC,KAAK,UAAU,SACzB,KAAK,OAAO,SAAS,KAAK;CAE5B,OAAO;AACT;AAEA,SAAS,wBAAwB,OAAkC;CACjE,IAAI,CAAC,cAAc,KAAK,GAAG,OAAO,CAAC;CAEnC,MAAM,MAAwB,CAAC;CAC/B,KAAK,MAAM,CAAC,WAAW,cAAc,OAAO,QAAQ,KAAK,GAAG;EAC1D,IAAI,CAAC,cAAc,SAAS,GAAG;EAC/B,MAAM,OAAgC,CAAC;EACvC,KAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,SAAS,GAChD,IAAI,OAAO,SAAS,WAClB,KAAK,OAAO;EAGhB,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,GAC7B,IAAI,aAAa;CAErB;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,wBACd,MACA,cACyC;CACzC,MAAM,SAA2B,wBAAwB,IAAI;CAE7D,KAAK,MAAM,eAAe,cAAc;EACtC,MAAM,YAAY,wBAAwB,YAAY,YAAY;EAClE,KAAK,MAAM,CAAC,WAAW,iBAAiB,OAAO,QAAQ,SAAS,GAC9D,OAAO,aAAa;GAClB,GAAI,OAAO,cAAc,CAAC;GAC1B,GAAG;EACL;CAEJ;CAEA,OAAO,UAGL,SAAS,MAAM,CAAC;AACpB"} |
| //#region src/shared/capabilities.d.ts | ||
| /** | ||
| * Capability matrix merge primitive shared by emit-time and runtime stack composition. | ||
| * | ||
| * The CLI's `enrichContract` and the SQL runtime's `createExecutionContext` both need | ||
| * to fold a stack of component descriptors' `capabilities` declarations into a single | ||
| * matrix keyed by namespace. Keeping the primitive here lets both call sites stay | ||
| * byte-for-byte consistent without one depending on the other. | ||
| */ | ||
| type CapabilityMatrix = Record<string, Record<string, boolean>>; | ||
| /** | ||
| * Merge an ordered list of contributor capability declarations into a base matrix. | ||
| * | ||
| * Behaviour: | ||
| * - `base` and each contributor's `capabilities` are filtered through the same | ||
| * structural extraction: non-plain-object namespace blocks are dropped, | ||
| * non-boolean leaves inside a namespace block are dropped, and a namespace | ||
| * block that ends up with zero boolean leaves is omitted entirely (so a | ||
| * later contributor with a malformed namespace cannot erase a namespace | ||
| * already present in `base`). | ||
| * - Non-plain-object `capabilities` on a contributor (including `undefined`, | ||
| * `null`, arrays, primitives) are skipped silently — the contributor | ||
| * contributes nothing. | ||
| * - Later contributors win on `(namespace, key)` collisions. | ||
| * - The returned object is fresh — neither `base` nor any contributor is mutated. | ||
| * - Output keys are sorted lexicographically at every plain-object level. | ||
| */ | ||
| declare function mergeCapabilityMatrices(base: Record<string, Record<string, boolean>>, contributors: ReadonlyArray<{ | ||
| readonly capabilities?: unknown; | ||
| }>): Record<string, Record<string, boolean>>; | ||
| //#endregion | ||
| export { mergeCapabilityMatrices as n, CapabilityMatrix as t }; | ||
| //# sourceMappingURL=capabilities-Cupq4-1-.d.mts.map |
| {"version":3,"file":"capabilities-Cupq4-1-.d.mts","names":[],"sources":["../src/shared/capabilities.ts"],"mappings":";;AAWA;;;;AAAoD;AA0DpD;;KA1DY,gBAAA,GAAmB,MAAM,SAAS,MAAA;;;;;;;;;;;;;;;;;AA6DtB;iBAHR,uBAAA,CACd,IAAA,EAAM,MAAA,SAAe,MAAA,oBACrB,YAAA,EAAc,aAAA;EAAA,SAAyB,YAAA;AAAA,KACtC,MAAA,SAAe,MAAA"} |
| import { JsonValue } from "@prisma-next/contract/types"; | ||
| import { StandardSchemaV1 } from "@standard-schema/spec"; | ||
| //#region src/shared/codec-descriptor.d.ts | ||
| /** | ||
| * Unified codec descriptor. Every codec in the framework registers through this shape — non-parameterized codecs use `P = void` and a constant factory that returns the same shared codec instance for every column; parameterized codecs use a non-empty `P` and a curried higher-order factory that returns a per-instance codec. | ||
| * | ||
| * The descriptor is the codec-id-keyed source of truth for static metadata (`traits`, `targetTypes`, `meta`) and registration concerns (`paramsSchema` for JSON-boundary validation; optional `renderOutputType` for the `contract.d.ts` emit path). The runtime `Codec` instance returned by `factory(params)(ctx)` carries only the conversion behavior. | ||
| * | ||
| * Whether a codec id "is parameterized" stops being a registration-time distinction — it's a property of `P` on the descriptor. The descriptor map indexes every descriptor by `codecId`; both `descriptorFor(codecId)` and `forColumn(table, column)` resolve through the same map without branching on parameterization. | ||
| * | ||
| * @template P - The shape of the params accepted by the factory (`void` for non-parameterized codecs; a record like `{ length: number }` for parameterized codecs). | ||
| * | ||
| * Codec-registry-unification project § Decision. | ||
| */ | ||
| interface CodecDescriptor<P = void> { | ||
| /** The codec ID this descriptor applies to (e.g. `pg/vector@1`, `pg/text@1`). */ | ||
| readonly codecId: string; | ||
| /** Semantic traits for operator gating (e.g. equality, order, numeric). */ | ||
| readonly traits: readonly CodecTrait[]; | ||
| /** Database-native type names this codec handles (e.g. `['timestamptz']`). */ | ||
| readonly targetTypes: readonly string[]; | ||
| /** Optional family-specific metadata (e.g. SQL-side `db.sql.postgres.nativeType`). */ | ||
| readonly meta?: CodecMeta; | ||
| /** Standard Schema validator for the factory's params. Validates JSON-sourced params at the contract boundary (PSL → IR; `contract.json` → runtime). For non-parameterized codecs (`P = void`), the schema validates `void`/`undefined` — the framework supplies no params at the call boundary. */ | ||
| readonly paramsSchema: StandardSchemaV1<P>; | ||
| /** Whether this descriptor is parameterized — i.e. its `paramsSchema` is something other than the singleton `voidParamsSchema`. Consumers that need to gate column-aware dispatch read this directly rather than threading a free-floating `(codecId) => boolean` callback. */ | ||
| readonly isParameterized: boolean; | ||
| /** Optional params-aware metadata renderer. Computes this codec instance's `CodecMeta` from its `typeParams` (e.g. a per-instance identifier derived from an enum's declared member set). Optional; absent renderers cause `CodecLookup.metaFor` to fall back to the codec's static `meta`. Non-parameterized codecs typically omit it. */ | ||
| readonly metaFor?: (params: P) => CodecMeta | undefined; | ||
| /** Emit-path string renderer for `contract.d.ts`. Returns the TypeScript output type expression for given params (e.g. `Vector<1536>`). Optional; absent renderers cause the emitter to fall back to the codec's base output type. Non-parameterized codecs typically omit it. */ | ||
| readonly renderOutputType?: (params: P) => string | undefined; | ||
| /** Emit-path string renderer for the `contract.d.ts` *input* position (create/update values). Returns the TypeScript input type expression for given params. Optional; absent renderers fall back to the codec's base input type. A codec supplies this when its write type is narrower than the generic codec input — e.g. an enum whose input should be the literal member union, not `string`. */ | ||
| readonly renderInputType?: (params: P) => string | undefined; | ||
| /** | ||
| * Given one stored (codec-encoded) value, return the TypeScript literal type to print for it | ||
| * (e.g. `'low'`, `1`), or `undefined` if this codec's output isn't literal-expressible (e.g. a | ||
| * Date-output codec). | ||
| * | ||
| * `value` is the `encodeJson` form stored in the value set. `side` selects which type to print: | ||
| * `output` = the read/SELECT type; `input` = the create/update type. Most codecs render the same | ||
| * literal for both, but a codec whose read and write types differ can render per side. Called once | ||
| * per permitted value; the caller joins the results with `|`. | ||
| */ | ||
| readonly renderValueLiteral?: (value: JsonValue, side: 'output' | 'input') => string | undefined; | ||
| /** The curried higher-order codec. For non-parameterized codecs, the factory is constant — every call returns the same shared codec instance. For parameterized codecs, the factory is called once per `storage.types` instance (or once per inline-`typeParams` column), with `ctx` carrying the column set the resulting codec serves. */ | ||
| readonly factory: (params: P) => (ctx: CodecInstanceContext) => Codec; | ||
| } | ||
| /** | ||
| * Variance-erased {@link CodecDescriptor} alias. `CodecDescriptor<P>` is invariant in `P` (the `factory` and `renderOutputType` slots use `P` contravariantly), so `CodecDescriptor<P>` does not extend `CodecDescriptor<unknown>` for specific `P`. Heterogeneous descriptor collections — e.g. `SqlStaticContributions.codecs:` returning a list that mixes parameterized and non-parameterized descriptors — type against this alias and narrow per codec id at the consumer. | ||
| * | ||
| * Codec-registry-unification spec § Decision: every codec resolves through one descriptor map; reads are non-branching. | ||
| */ | ||
| type AnyCodecDescriptor = CodecDescriptor<any>; | ||
| /** | ||
| * Abstract base class for concrete codec descriptors. | ||
| * | ||
| * Codec authors extend this class with their typed `TParams` and declare `codecId`, `traits`, `targetTypes`, `paramsSchema`, the curried `factory(params)`, and (optionally) `renderOutputType`. | ||
| * | ||
| * Implements the {@link CodecDescriptor} interface so a concrete subclass instance is directly usable wherever the framework expects a `CodecDescriptor<P>`. | ||
| */ | ||
| declare abstract class CodecDescriptorImpl<TParams = void> implements CodecDescriptor<TParams> { | ||
| abstract readonly codecId: string; | ||
| abstract readonly traits: readonly CodecTrait[]; | ||
| abstract readonly targetTypes: readonly string[]; | ||
| readonly meta?: CodecMeta; | ||
| abstract readonly paramsSchema: StandardSchemaV1<TParams>; | ||
| /** Boolean derived from `paramsSchema`: `true` whenever the schema is not the singleton `voidParamsSchema`. */ | ||
| get isParameterized(): boolean; | ||
| /** Optional params-aware metadata renderer. Computes this codec instance's `CodecMeta` from its `typeParams` (e.g. a per-instance identifier derived from an enum's declared member set). Non-parameterized codecs typically omit it. */ | ||
| metaFor?(params: TParams): CodecMeta | undefined; | ||
| /** Optional emit-path string renderer for `contract.d.ts`. Returns the TypeScript output type expression for the given params (e.g. `Vector<1536>`). Non-parameterized codecs typically omit it. */ | ||
| renderOutputType?(params: TParams): string | undefined; | ||
| /** Optional emit-path string renderer for the `contract.d.ts` input position. Returns the TypeScript input type expression for the given params; supplied when the write type is narrower than the generic codec input (e.g. an enum's literal member union). */ | ||
| renderInputType?(params: TParams): string | undefined; | ||
| /** Optional emit-path renderer for a single stored value. See {@link CodecDescriptor.renderValueLiteral}. */ | ||
| renderValueLiteral?(value: JsonValue, side: 'output' | 'input'): string | undefined; | ||
| /** | ||
| * Materialize a curried codec factory for the given params. Concrete subclasses override with a typed return type (e.g. `factory<N>(params: { length: N }): (ctx) => VectorCodec<N>`); per-codec helpers read the typed return at the *direct* call site, which is what preserves method-level generics. Type extraction (e.g. `ReturnType<D['factory']>`) widens method generics to their constraint — that's why the column-helper surface is per-codec, not polymorphic. | ||
| */ | ||
| abstract factory(params: TParams): (ctx: CodecInstanceContext) => Codec<string, readonly CodecTrait[], unknown, unknown>; | ||
| } | ||
| //#endregion | ||
| //#region src/shared/codec.d.ts | ||
| /** | ||
| * A codec is the contract between an application value and its driver-wire and JSON representations. | ||
| * | ||
| * The author's mental model is two JS-side types — `TInput` (the application JS type) and `TWire` (the database driver wire format) — plus a target-defined `JsonValue`. The codec translates `TInput` to `TWire` on writes and back on ordinary reads, and to/from the target's JSON representation for contract artifacts and database-produced JSON values. | ||
| * | ||
| * Three representations participate: | ||
| * - **Input** (`TInput`): the JS type at the application boundary. | ||
| * - **Wire** (`TWire`): the format exchanged with the database driver. | ||
| * - **JSON** (`JsonValue`): the target-defined JSON-safe form used in contract artifacts. It uses the exact scalar shape the target produces inside JSON values, which can differ from the ordinary wire format. | ||
| * | ||
| * The runtime instance carries only its `id` (the descriptor's `codecId`, set by the factory) and the four conversion methods. Static metadata (`traits`, `targetTypes`, `meta`) and the build-time `renderOutputType` renderer live on the {@link CodecDescriptor} keyed by `codecId` — the read-surface single source of truth. Consumers that need them resolve through `descriptorFor(codecId)`. | ||
| * | ||
| * Codec methods split into two groups: | ||
| * | ||
| * - **Query-time** methods (`encode`, `decode`) run per row/parameter at the IO boundary; they are required and Promise-returning. The per-family codec factory accepts sync or async author functions and lifts sync ones to Promise-shaped methods automatically. | ||
| * - **JSON** methods (`encodeJson`, `decodeJson`) run when the contract is serialized or loaded. Runtimes may also use `decodeJson` for values embedded in database-produced JSON results. They stay synchronous so contract validation and client construction are synchronous. | ||
| * | ||
| * Target-family codec interfaces extend this base; family-specific concerns (e.g. the SQL `column?` per-call context) layer on through the `CodecCallContext` extension pattern. | ||
| */ | ||
| interface Codec<Id extends string = string, TTraits extends readonly CodecTrait[] = readonly CodecTrait[], TWire = unknown, TInput = unknown> { | ||
| /** Unique codec identifier in `namespace/name@version` format (e.g. `pg/timestamptz@1`). The factory sets this to the descriptor's `codecId`; consumers use it as a back-reference for descriptor lookups and for decode-error diagnostics. */ | ||
| readonly id: Id; | ||
| /** Phantom carrier for the `TTraits` generic; type-only, undefined at runtime. Runtime traits live on {@link CodecDescriptor.traits}. Implemented as a string-key phantom (`__codecTraits`) rather than `unique symbol` so bundlers that split `.d.ts` chunks do not strand symbol identity on chunk-private paths (the same `TS2742` family that the public re-export of `CodecTypes` works around). */ | ||
| readonly __codecTraits?: TTraits; | ||
| /** Converts a JS value to the wire format expected by the database driver. Always Promise-returning at the boundary. The {@link CodecCallContext} is supplied by the runtime on every call (allocated once per `runtime.execute()`); family layers may narrow the ctx to extend it (e.g. SQL adds `column`). Author-side single-arg `(value) => …` functions remain legal via TypeScript's bivariance for trailing parameters. */ | ||
| encode(value: TInput, ctx: CodecCallContext): Promise<TWire>; | ||
| /** Converts a wire value from the database driver into the JS application type. Always Promise-returning at the boundary. The {@link CodecCallContext} is supplied by the runtime on every call (allocated once per `runtime.execute()`); family layers may narrow the ctx to extend it (e.g. SQL adds `column`). Author-side single-arg `(wire) => …` functions remain legal via TypeScript's bivariance for trailing parameters. */ | ||
| decode(wire: TWire, ctx: CodecCallContext): Promise<TInput>; | ||
| /** Converts a JS value to the target-defined JSON representation used for contract serialization. This must match the scalar shape produced by the target inside JSON values. Synchronous; called during contract emission. */ | ||
| encodeJson(value: TInput): JsonValue; | ||
| /** Converts the target-defined JSON representation back to the JS input type. Synchronous; called during contract loading via `family.deserializeContract` and may be called by runtimes for embedded JSON values. */ | ||
| decodeJson(json: JsonValue): TInput; | ||
| } | ||
| /** | ||
| * Abstract base class for concrete codec implementations. | ||
| * | ||
| * Codec authors extend this class with their typed `Id`, `TTraits`, `TWire`, `TInput` and override all four abstract conversion methods: `encode`, `decode`, `encodeJson`, and `decodeJson`. The runtime instance carries only its `id` (proxied through the descriptor so alias subclasses inherit the descriptor's id automatically) and the conversion methods — static metadata lives on the {@link CodecDescriptor}. | ||
| */ | ||
| declare abstract class CodecImpl<Id extends string = string, TTraits extends readonly CodecTrait[] = readonly CodecTrait[], TWire = unknown, TInput = unknown> implements Codec<Id, TTraits, TWire, TInput> { | ||
| readonly descriptor: CodecDescriptor<any>; | ||
| /** | ||
| * Variance-erased descriptor reference. Concrete codec subclasses receive the typed descriptor in their own constructors and forward it via `super(descriptor)`; the variance erasure lives at this base because the abstract surface can't carry the concrete `TParams`. | ||
| */ | ||
| constructor(descriptor: CodecDescriptor<any>); | ||
| get id(): Id; | ||
| abstract encode(value: TInput, ctx: CodecCallContext): Promise<TWire>; | ||
| abstract decode(wire: TWire, ctx: CodecCallContext): Promise<TInput>; | ||
| abstract encodeJson(value: TInput): JsonValue; | ||
| abstract decodeJson(json: JsonValue): TInput; | ||
| } | ||
| //#endregion | ||
| //#region src/shared/codec-types.d.ts | ||
| type CodecTrait = 'equality' | 'order' | 'boolean' | 'numeric' | 'textual'; | ||
| /** | ||
| * Serializable codec identity carried by every codec-bearing AST node. | ||
| * | ||
| * `(codecId, typeParams?)` is the single fact the runtime needs to materialize a codec via `descriptorFor(codecId).factory(typeParams)(ctx)`. The pair is content-keyed: two refs with the same `codecId` and structurally equal `typeParams` (regardless of object key ordering) resolve to the same memoized {@link Codec} instance. | ||
| * | ||
| * `typeParams` is `JsonValue`-constrained so the ref survives JSON serialization (relevant for AST-embedded migration ops). Non-parameterized codecs leave `typeParams` undefined; the descriptor's `paramsSchema` validates the value at the JSON boundary. | ||
| * | ||
| * `many` marks a scalar-array (list-typed) column. When `true`, the encode/decode paths map the element codec over the JS array rather than applying the codec to the whole value. The element codec id is `codecId`; the driver owns the array wire framing (`{…}`) in both directions. Absent for scalar columns. | ||
| * | ||
| * Family-agnostic by design — both SQL and Mongo AST nodes carry `codec: CodecRef | undefined`, and the resolver is the only dispatch path that survives serialization. | ||
| */ | ||
| interface CodecRef { | ||
| readonly codecId: string; | ||
| readonly typeParams?: JsonValue; | ||
| readonly many?: boolean; | ||
| } | ||
| /** | ||
| * Per-call context the runtime threads to every `codec.encode` / `codec.decode` invocation for a single `runtime.execute()` call. | ||
| * | ||
| * The framework-level shape is family-agnostic and carries one field: | ||
| * | ||
| * - `signal?: AbortSignal` — per-query cancellation. The runtime returns a `RUNTIME.ABORTED` envelope when the signal aborts; codec authors who forward `signal` to their underlying SDK get true cancellation of in-flight network calls. | ||
| * | ||
| * Family layers extend this base with their own shape-of-call metadata: the SQL family adds `column?: SqlColumnRef` via `SqlCodecCallContext` (see `@prisma-next/sql-relational-core`). Mongo currently uses this framework type unchanged. Column metadata is intentionally **not** on the framework type — it is a SQL-family concept rooted in SQL's `(table, column)` addressing model and would not generalise to other families. | ||
| * | ||
| * The interface is named explicitly (not inlined) so future framework fields and family extensions can land additively without breaking codec author signatures. | ||
| */ | ||
| interface CodecCallContext { | ||
| readonly signal?: AbortSignal; | ||
| } | ||
| /** | ||
| * Codec-id-keyed read surface threaded into emit and authoring paths. | ||
| * | ||
| * - `get(id)` returns a representative {@link Codec} instance for the codec id (used by `family.deserializeContract` for `decodeJson` of literal column defaults). For parameterized codecs whose factory requires concrete params, this may return `undefined` — use `CodecRegistry.forCodecRef` instead. | ||
| * - `targetTypesFor(id)` exposes the codec-id-keyed `targetTypes` metadata the runtime instance no longer carries (TML-2357). Returns the same array `CodecDescriptor.targetTypes` would; for Mongo (whose registration doesn't yet resolve through the unified descriptor map — TML-2324) the family-side assembly populates this directly from the contributor's codec metadata. | ||
| * - `metaFor(id, typeParams)` exposes the codec-id-keyed `meta` (e.g. SQL-side `db.sql.postgres.nativeType`) the runtime instance no longer carries. `typeParams` is optional: when given and the codec descriptor implements a params-aware `metaFor`, the descriptor computes its meta from those params (e.g. a native enum's per-instance Postgres type name); otherwise (or when `typeParams` is omitted) the codec's static `meta` is returned. | ||
| * - `renderOutputTypeFor(id, params)` exposes the codec-id-keyed `renderOutputType` renderer the runtime instance no longer carries. Returns `undefined` when the codec doesn't render a custom type or when the codec id is unknown. | ||
| */ | ||
| interface CodecLookup { | ||
| get(id: string): Codec | undefined; | ||
| targetTypesFor(id: string): readonly string[] | undefined; | ||
| metaFor(id: string, typeParams?: Record<string, unknown> | JsonValue): CodecMeta | undefined; | ||
| renderOutputTypeFor(id: string, params: Record<string, unknown>): string | undefined; | ||
| /** Codec-id-keyed `renderInputType` renderer for the `contract.d.ts` input position. Optional so existing lookups need not provide it; returns `undefined` when the codec renders no custom input type or the id is unknown. */ | ||
| renderInputTypeFor?(id: string, params: Record<string, unknown>): string | undefined; | ||
| /** Codec-id-keyed `renderValueLiteral` renderer for the emit path (`side`: `output` = read type, `input` = create/update type). Optional so existing lookups need not provide it; returns `undefined` when the codec's output isn't literal-expressible or the id is unknown. */ | ||
| renderValueLiteralFor?(id: string, value: JsonValue, side: 'output' | 'input'): string | undefined; | ||
| /** | ||
| * Codec-id-keyed descriptor accessor. Returns the full registered | ||
| * {@link AnyCodecDescriptor} for `id`, or `undefined` if no descriptor is | ||
| * registered. Optional so existing lookups need not provide it; a consumer | ||
| * that needs more than the derived per-id readers above — e.g. an | ||
| * authoring-time hook a target-specific descriptor exposes but this | ||
| * framework interface does not model generically — fetches the descriptor | ||
| * itself and narrows it with its own structural predicate. | ||
| */ | ||
| descriptorFor?(id: string): AnyCodecDescriptor | undefined; | ||
| } | ||
| /** | ||
| * Full codec registry — the read surface of {@link CodecLookup} plus codec resolution by ref or | ||
| * column coordinate. Built once by `extractCodecLookup` and passed by reference to adapters and | ||
| * other consumers that need to materialise codecs at runtime. | ||
| * | ||
| * - `forCodecRef(ref)` materialises a codec from a {@link CodecRef}. Throws | ||
| * `RUNTIME.CODEC_DESCRIPTOR_MISSING` for unknown ids and `RUNTIME.TYPE_PARAMS_INVALID` on param | ||
| * schema rejection. | ||
| * - `forColumn(namespaceId, table, column)` returns the codec for a specific column coordinate, or | ||
| * `undefined` when no column-to-codec mapping is present. This registry is contract-free so it | ||
| * always returns `undefined` — the method exists so the object structurally satisfies the SQL | ||
| * `ContractCodecRegistry` interface. | ||
| */ | ||
| interface CodecRegistry extends CodecLookup { | ||
| forCodecRef(ref: CodecRef): Codec; | ||
| forColumn(namespaceId: string, table: string, column: string): Codec | undefined; | ||
| } | ||
| declare const emptyCodecLookup: CodecLookup; | ||
| /** | ||
| * Family-agnostic per-instance context supplied by the framework when applying a higher-order codec factory. Allows stateful codecs (e.g. column-scoped encryption) to derive per-instance state from the materialization site. | ||
| * | ||
| * - `name` — the family-agnostic instance identity. For SQL, the runtime populates this as the `storage.types` instance name (e.g. `Embedding1536`) for typeRef-shaped columns, an inline-column sentinel (`<col:Document.embedding>`) for inline-`typeParams` columns, a shared codec-id sentinel (`<codec:pg/text@1>`) for non-parameterized codec ids, or the canonical cache key (`<codecId>:<canonicalizeJson(typeParams)>`) for ad-hoc refs the contract walk did not pre-populate. Other families pick the analogous identity for their materialization sites. | ||
| * | ||
| * Family-specific extensions (e.g. {@link import('@prisma-next/sql-relational-core/ast').SqlCodecInstanceContext} in the SQL layer) augment this base with domain-shaped column-set metadata. Codec authors target the base when they don't read family-specific metadata; they target the family extension when they do. | ||
| */ | ||
| interface CodecInstanceContext { | ||
| readonly name: string; | ||
| } | ||
| /** | ||
| * Family-agnostic codec metadata. Family-specific extensions augment the base `db.<family>.<target>` block with native-type information; the base shape is an empty object so non-relational codecs can carry no metadata. | ||
| */ | ||
| interface CodecMeta { | ||
| readonly db?: Record<string, unknown>; | ||
| } | ||
| /** | ||
| * Standard Schema validator for `void` params. Accepts only `undefined` (or absent input); rejects any other value so a contract that tries to thread `typeParams` through a non-parameterized codec id fails fast at the JSON boundary instead of silently coercing the value away. Used by the framework-supplied non-parameterized descriptor synthesizer. | ||
| */ | ||
| declare const voidParamsSchema: StandardSchemaV1<void>; | ||
| //#endregion | ||
| export { CodecRef as a, emptyCodecLookup as c, CodecImpl as d, AnyCodecDescriptor as f, CodecMeta as i, voidParamsSchema as l, CodecDescriptorImpl as m, CodecInstanceContext as n, CodecRegistry as o, CodecDescriptor as p, CodecLookup as r, CodecTrait as s, CodecCallContext as t, Codec as u }; | ||
| //# sourceMappingURL=codec-types-e32YHT3D.d.mts.map |
| {"version":3,"file":"codec-types-e32YHT3D.d.mts","names":[],"sources":["../src/shared/codec-descriptor.ts","../src/shared/codec.ts","../src/shared/codec-types.ts"],"mappings":"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"} |
| import { r as CodecLookup } from "./codec-types-e32YHT3D.mjs"; | ||
| import { t as TypesImportSpec } from "./types-import-spec-DRKzrJ20.mjs"; | ||
| import { Contract, ContractModelBase, JsonValue } from "@prisma-next/contract/types"; | ||
| //#region src/control/emission-types.d.ts | ||
| interface GenerateContractTypesOptions { | ||
| readonly queryOperationTypeImports?: ReadonlyArray<TypesImportSpec>; | ||
| } | ||
| interface ValidationContext { | ||
| readonly codecTypeImports?: ReadonlyArray<TypesImportSpec>; | ||
| readonly extensionIds?: ReadonlyArray<string>; | ||
| } | ||
| interface EmissionSpi { | ||
| readonly id: string; | ||
| generateStorageType(contract: Contract, storageHashTypeName: string): string; | ||
| generateModelStorageType(modelName: string, model: ContractModelBase): string; | ||
| getFamilyImports(): string[]; | ||
| getFamilyTypeAliases(options?: GenerateContractTypesOptions): string; | ||
| getTypeMapsExpression(): string; | ||
| getContractWrapper(contractBaseName: string, typeMapsName: string): string; | ||
| resolveFieldTypeParams?(modelName: string, fieldName: string, model: ContractModelBase, contract: Contract): Record<string, unknown> | undefined; | ||
| /** | ||
| * Resolves a field's permitted values (codec-encoded) plus the codec that types them, or | ||
| * `undefined` for a field with no restricted value set. The framework renders the values into a TS | ||
| * literal union through the codec seam. Each family decides where the values live — a value set in | ||
| * its own storage plane, or another family-owned source. | ||
| */ | ||
| resolveFieldValueSet?(modelName: string, fieldName: string, model: ContractModelBase, contract: Contract): { | ||
| readonly encodedValues: readonly JsonValue[]; | ||
| readonly codecId: string; | ||
| } | undefined; | ||
| getStorageTypeExports?(contract: Contract, codecLookup?: CodecLookup): string | undefined; | ||
| } | ||
| //#endregion | ||
| export { GenerateContractTypesOptions as n, ValidationContext as r, EmissionSpi as t }; | ||
| //# sourceMappingURL=emission-types-BQMFUNQO.d.mts.map |
| {"version":3,"file":"emission-types-BQMFUNQO.d.mts","names":[],"sources":["../src/control/emission-types.ts"],"mappings":";;;;;UAIiB,4BAAA;EAAA,SACN,yBAAA,GAA4B,aAAa,CAAC,eAAA;AAAA;AAAA,UAGpC,iBAAA;EAAA,SACN,gBAAA,GAAmB,aAAA,CAAc,eAAA;EAAA,SACjC,YAAA,GAAe,aAAA;AAAA;AAAA,UAGT,WAAA;EAAA,SACN,EAAA;EAET,mBAAA,CAAoB,QAAA,EAAU,QAAA,EAAU,mBAAA;EAExC,wBAAA,CAAyB,SAAA,UAAmB,KAAA,EAAO,iBAAA;EAEnD,gBAAA;EAEA,oBAAA,CAAqB,OAAA,GAAU,4BAAA;EAE/B,qBAAA;EAEA,kBAAA,CAAmB,gBAAA,UAA0B,YAAA;EAE7C,sBAAA,EACE,SAAA,UACA,SAAA,UACA,KAAA,EAAO,iBAAA,EACP,QAAA,EAAU,QAAA,GACT,MAAA;EAvBqB;;;;;;EA+BxB,oBAAA,EACE,SAAA,UACA,SAAA,UACA,KAAA,EAAO,iBAAA,EACP,QAAA,EAAU,QAAA;IAAA,SACE,aAAA,WAAwB,SAAA;IAAA,SAAsB,OAAA;EAAA;EAE5D,qBAAA,EAAuB,QAAA,EAAU,QAAA,EAAU,WAAA,GAAc,WAAA;AAAA"} |
| import { n as runtimeError } from "./runtime-error-B2gWOtgH.mjs"; | ||
| import { blindCast } from "@prisma-next/utils/casts"; | ||
| import { isColumnDefaultLiteralInputValue, isExecutionMutationDefaultValue } from "@prisma-next/contract/types"; | ||
| import { ifDefined } from "@prisma-next/utils/defined"; | ||
| //#region src/shared/framework-authoring.ts | ||
| /** | ||
| * Classifies an `enum` block's members (before codec decoding, which needs | ||
| * the codec chosen first) into which default codec an omitted `@@type` | ||
| * should resolve to: | ||
| * | ||
| * - every member is `bare`, or a `value` whose raw JSON is a string → `'text'` | ||
| * - every member is a `value` whose raw JSON is an integer → `'int'` | ||
| * - anything else (float, bigint, boolean, mixed, or a `ref`/`option`/`list` | ||
| * parameter) → `null`, meaning the caller must require an explicit `@@type`. | ||
| */ | ||
| function classifyEnumMemberType(block) { | ||
| let sawText = false; | ||
| let sawInt = false; | ||
| for (const paramValue of Object.values(block.parameters)) { | ||
| if (paramValue.kind === "bare") { | ||
| sawText = true; | ||
| continue; | ||
| } | ||
| if (paramValue.kind !== "value") return null; | ||
| let jsonValue; | ||
| try { | ||
| jsonValue = JSON.parse(paramValue.raw); | ||
| } catch { | ||
| return null; | ||
| } | ||
| if (typeof jsonValue === "string") sawText = true; | ||
| else if (typeof jsonValue === "number" && Number.isInteger(jsonValue)) sawInt = true; | ||
| else return null; | ||
| } | ||
| if (sawText && sawInt) return null; | ||
| if (sawText) return "text"; | ||
| if (sawInt) return "int"; | ||
| return null; | ||
| } | ||
| /** | ||
| * Resolves the codec id for an `enum` block. When `@@type` is absent, the codec | ||
| * is inferred from the members via {@link classifyEnumMemberType}; otherwise the | ||
| * explicit `@@type("codec")` argument is parsed. Pushes the appropriate | ||
| * diagnostic and returns `undefined` when neither yields a codec. `codecSpan` is | ||
| * the span downstream codec-validation diagnostics should anchor to. Shared by | ||
| * every family's enum factory so inference and the explicit path stay identical. | ||
| */ | ||
| function resolveEnumCodecId(block, ctx) { | ||
| const sourceId = ctx.sourceId ?? "unknown"; | ||
| const typeAttr = block.blockAttributes.find((a) => a.name === "type"); | ||
| if (typeAttr === void 0) { | ||
| const inferredKind = classifyEnumMemberType(block); | ||
| if (inferredKind === null || ctx.enumInferenceCodecs === void 0) { | ||
| ctx.diagnostics?.push({ | ||
| code: "PSL_ENUM_CANNOT_INFER_TYPE", | ||
| message: `cannot infer @@type for enum "${block.name}"; add an explicit @@type(...)`, | ||
| sourceId, | ||
| span: block.span | ||
| }); | ||
| return; | ||
| } | ||
| return { | ||
| codecId: ctx.enumInferenceCodecs[inferredKind], | ||
| codecSpan: block.span | ||
| }; | ||
| } | ||
| const rawCodecArg = typeAttr.args[0]?.value; | ||
| const codecId = rawCodecArg?.startsWith("\"") && rawCodecArg.endsWith("\"") && rawCodecArg.length >= 2 ? rawCodecArg.slice(1, -1) : void 0; | ||
| if (codecId === void 0) { | ||
| ctx.diagnostics?.push({ | ||
| code: "PSL_ENUM_MISSING_TYPE", | ||
| message: `enum "${block.name}" @@type attribute must have a quoted codec id argument`, | ||
| sourceId, | ||
| span: typeAttr.span | ||
| }); | ||
| return; | ||
| } | ||
| return { | ||
| codecId, | ||
| codecSpan: typeAttr.args[0]?.span ?? typeAttr.span | ||
| }; | ||
| } | ||
| function isAuthoringArgRef(value) { | ||
| if (typeof value !== "object" || value === null || value.kind !== "arg") return false; | ||
| const { index, path } = value; | ||
| if (typeof index !== "number" || !Number.isInteger(index) || index < 0) return false; | ||
| if (path !== void 0 && (!Array.isArray(path) || path.some((s) => typeof s !== "string"))) return false; | ||
| return true; | ||
| } | ||
| function isAuthoringTemplateRecord(value) { | ||
| return typeof value === "object" && value !== null && !Array.isArray(value); | ||
| } | ||
| function isAuthoringTypeConstructorDescriptor(value) { | ||
| return "kind" in value && value.kind === "typeConstructor"; | ||
| } | ||
| function isAuthoringFieldPresetDescriptor(value) { | ||
| return "kind" in value && value.kind === "fieldPreset"; | ||
| } | ||
| function isAuthoringEntityTypeDescriptor(value) { | ||
| return "kind" in value && value.kind === "entity"; | ||
| } | ||
| function isAuthoringPslBlockDescriptor(value) { | ||
| return "kind" in value && value.kind === "pslBlock"; | ||
| } | ||
| function isAuthoringModelAttributeDescriptor(value) { | ||
| return "kind" in value && value.kind === "modelAttribute"; | ||
| } | ||
| /** | ||
| * Returns true when `namespace` is a non-leaf key in `contributions.field`. | ||
| * | ||
| * `AuthoringFieldNamespace` permits a leaf descriptor at any depth — including | ||
| * the root — so a top-level `field: { Foo: { kind: 'fieldPreset', ... } }` | ||
| * registration must NOT be treated as a "namespace" with sub-paths. Callers | ||
| * use this predicate to gate dot-namespaced lookups (e.g. PSL `@Foo.bar`). | ||
| */ | ||
| function hasRegisteredFieldNamespace(contributions, namespace) { | ||
| if (contributions?.field === void 0 || !Object.hasOwn(contributions.field, namespace)) return false; | ||
| const value = contributions.field[namespace]; | ||
| return value !== void 0 && !isAuthoringFieldPresetDescriptor(value); | ||
| } | ||
| function isCopyableNamespaceObject(value) { | ||
| if (typeof value !== "object" || value === null || Array.isArray(value)) return false; | ||
| const proto = Object.getPrototypeOf(value); | ||
| return proto === Object.prototype || proto === null; | ||
| } | ||
| /** | ||
| * Deep structural check run only at the composition boundary (the merge and | ||
| * collect walkers) to classify a raw namespace-tree node as a leaf descriptor. | ||
| * A node counts as a leaf iff its `kind` matches `descriptorKind` AND it | ||
| * carries that kind's required fields. | ||
| * | ||
| * This is boundary validation over `unknown`, NOT a type-predicate: the four | ||
| * exported `isAuthoring*Descriptor` predicates deliberately narrow on `kind` | ||
| * alone and trust the static types. The walkers, by contrast, also receive | ||
| * type-bypassing packs (`as unknown as never` in tests, untyped JS at runtime) | ||
| * whose descriptor-shaped-but-incomplete nodes must be rejected rather than | ||
| * silently treated as sub-namespaces — so the well-formedness check lives here. | ||
| */ | ||
| function isWellFormedDescriptor(value, descriptorKind) { | ||
| if (typeof value !== "object" || value === null) return false; | ||
| if (!("kind" in value) || value.kind !== descriptorKind) return false; | ||
| switch (descriptorKind) { | ||
| case "typeConstructor": | ||
| case "fieldPreset": { | ||
| if (!("output" in value)) return false; | ||
| const output = value.output; | ||
| return typeof output === "object" && output !== null; | ||
| } | ||
| case "entity": { | ||
| if (!("discriminator" in value) || typeof value.discriminator !== "string") return false; | ||
| if (value.discriminator.length === 0) return false; | ||
| if (!("output" in value)) return false; | ||
| const output = value.output; | ||
| if (typeof output !== "object" || output === null) return false; | ||
| const factory = "factory" in output ? output.factory : void 0; | ||
| const template = "template" in output ? output.template : void 0; | ||
| return typeof factory === "function" || template !== void 0; | ||
| } | ||
| case "pslBlock": { | ||
| if (!("keyword" in value) || typeof value.keyword !== "string" || value.keyword.length === 0) return false; | ||
| if (!("discriminator" in value) || typeof value.discriminator !== "string" || value.discriminator.length === 0) return false; | ||
| if (!("name" in value)) return false; | ||
| const name = value.name; | ||
| if (typeof name !== "object" || name === null) return false; | ||
| if (!("required" in name) || typeof name.required !== "boolean") return false; | ||
| if (!("parameters" in value)) return false; | ||
| const parameters = value.parameters; | ||
| return typeof parameters === "object" && parameters !== null && !Array.isArray(parameters); | ||
| } | ||
| case "modelAttribute": | ||
| if (!("attribute" in value) || typeof value.attribute !== "string" || value.attribute.length === 0) return false; | ||
| if (!("spec" in value)) return false; | ||
| return "lower" in value && typeof value.lower === "function"; | ||
| default: return false; | ||
| } | ||
| } | ||
| function deepCopyNamespace(source, descriptorKind) { | ||
| const copy = {}; | ||
| for (const [key, value] of Object.entries(source)) copy[key] = isCopyableNamespaceObject(value) && !isWellFormedDescriptor(value, descriptorKind) ? deepCopyNamespace(value, descriptorKind) : value; | ||
| return copy; | ||
| } | ||
| /** | ||
| * Merges `source` into `target` recursively at the descriptor-namespace | ||
| * level. `descriptorKind` is the `kind` value ('typeConstructor', | ||
| * 'fieldPreset', 'entity', or 'pslBlock') that identifies a descriptor | ||
| * (terminal merge point; same-path registrations across components are | ||
| * reported as duplicates) as opposed to a sub-namespace (recursion target). | ||
| * | ||
| * Path segments are validated against prototype-pollution names | ||
| * (`__proto__`, `constructor`, `prototype`). A value that is neither a | ||
| * recognized leaf nor a plain object — e.g. a malformed descriptor | ||
| * where the canonical leaf guard rejected it for missing `output` — | ||
| * is reported as an invalid contribution rather than recursed into, | ||
| * which would either silently mangle state or infinite-loop on | ||
| * primitive properties. | ||
| * | ||
| * Within-registry duplicate detection is this walker's job; | ||
| * cross-registry detection runs separately via | ||
| * `assertNoCrossRegistryCollisions` after merging completes. | ||
| */ | ||
| function mergeAuthoringNamespaces(target, source, path, descriptorKind, label) { | ||
| const assertSafePath = (currentPath) => { | ||
| const blockedSegment = currentPath.find((segment) => segment === "__proto__" || segment === "constructor" || segment === "prototype"); | ||
| if (blockedSegment) throw new Error(`Invalid authoring ${label} helper "${currentPath.join(".")}". Helper path segments must not use "${blockedSegment}".`); | ||
| }; | ||
| for (const [key, sourceValue] of Object.entries(source)) { | ||
| const currentPath = [...path, key]; | ||
| assertSafePath(currentPath); | ||
| const hasExistingValue = Object.hasOwn(target, key); | ||
| const existingValue = hasExistingValue ? target[key] : void 0; | ||
| if (!hasExistingValue) { | ||
| target[key] = isCopyableNamespaceObject(sourceValue) && !isWellFormedDescriptor(sourceValue, descriptorKind) ? deepCopyNamespace(sourceValue, descriptorKind) : sourceValue; | ||
| continue; | ||
| } | ||
| const existingIsLeaf = isWellFormedDescriptor(existingValue, descriptorKind); | ||
| const sourceIsLeaf = isWellFormedDescriptor(sourceValue, descriptorKind); | ||
| if (existingIsLeaf || sourceIsLeaf) throw new Error(`Duplicate authoring ${label} helper "${currentPath.join(".")}". Helper names must be unique across composed packs.`); | ||
| if (!isCopyableNamespaceObject(existingValue) || !isCopyableNamespaceObject(sourceValue)) throw new Error(`Invalid authoring ${label} helper "${currentPath.join(".")}". Expected a sub-namespace object or a recognized descriptor; received a malformed value.`); | ||
| mergeAuthoringNamespaces(existingValue, sourceValue, currentPath, descriptorKind, label); | ||
| } | ||
| } | ||
| function collectDescriptorPaths(namespace, isLeaf, path = []) { | ||
| const paths = []; | ||
| for (const [key, value] of Object.entries(namespace)) { | ||
| const currentPath = [...path, key]; | ||
| if (isLeaf(value)) { | ||
| paths.push(currentPath.join(".")); | ||
| continue; | ||
| } | ||
| if (typeof value === "object" && value !== null && !Array.isArray(value)) paths.push(...collectDescriptorPaths(value, isLeaf, currentPath)); | ||
| } | ||
| return paths; | ||
| } | ||
| function collectDescriptorEntries(namespace, isLeaf, descriptorKind, label, path = []) { | ||
| const entries = []; | ||
| for (const [key, value] of Object.entries(namespace)) { | ||
| const currentPath = [...path, key]; | ||
| if (isLeaf(value)) { | ||
| if (!isWellFormedDescriptor(value, descriptorKind)) throw new Error(`Malformed authoring ${label} contribution at "${currentPath.join(".")}". The value carries descriptor keys (kind/keyword/discriminator) but does not satisfy the ${label} descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`); | ||
| if (value.discriminator.length > 0) entries.push({ | ||
| path: currentPath.join("."), | ||
| discriminator: value.discriminator | ||
| }); | ||
| continue; | ||
| } | ||
| if (typeof value === "object" && value !== null && !Array.isArray(value)) { | ||
| const record = blindCast(value); | ||
| if ((record["kind"] !== void 0 || record["keyword"] !== void 0 || record["discriminator"] !== void 0) && !isLeaf(value)) { | ||
| const hasKind = record["kind"] === "pslBlock"; | ||
| const hasKeyword = typeof record["keyword"] === "string"; | ||
| const hasDiscriminator = typeof record["discriminator"] === "string"; | ||
| if (hasKind || hasKeyword && hasDiscriminator) throw new Error(`Malformed authoring ${label} contribution at "${currentPath.join(".")}". The value carries descriptor keys (kind/keyword/discriminator) but does not satisfy the ${label} descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`); | ||
| } | ||
| entries.push(...collectDescriptorEntries(value, isLeaf, descriptorKind, label, currentPath)); | ||
| } | ||
| } | ||
| return entries; | ||
| } | ||
| /** | ||
| * Throws when two or more entries in the same namespace share a key. A | ||
| * duplicate key makes dispatch ambiguous — the caller's lookup dispatches by | ||
| * this key, so one entry would silently shadow the other. Catch duplicates | ||
| * before building any dispatch map. | ||
| * | ||
| * `label` (e.g. `'pslBlock'`, `'entityType'`) names which namespace the | ||
| * duplicate was found in and is carried in the structured error metadata; | ||
| * the key itself is always called `key` in both the message and the | ||
| * metadata, since what it semantically represents (a discriminator for | ||
| * `entityType`, the parser's dispatch keyword for `pslBlock`) is the | ||
| * caller's concern, not this function's. | ||
| */ | ||
| function assertUniqueDiscriminators(entries, label) { | ||
| const seen = /* @__PURE__ */ new Map(); | ||
| for (const { path, discriminator: key } of entries) { | ||
| const existing = seen.get(key); | ||
| if (existing !== void 0) throw runtimeError("RUNTIME.DUPLICATE_AUTHORING_DISCRIMINATOR", `Duplicate ${label} key "${key}" registered at both "${existing}" and "${path}". Each ${label} contribution must use a unique key.`, { | ||
| label, | ||
| key, | ||
| existingPath: existing, | ||
| path | ||
| }); | ||
| seen.set(key, path); | ||
| } | ||
| } | ||
| function collectPslBlockDescriptorEntries(namespace, path = []) { | ||
| const entries = []; | ||
| for (const [key, value] of Object.entries(namespace)) { | ||
| const currentPath = [...path, key]; | ||
| if (isAuthoringPslBlockDescriptor(value)) { | ||
| if (!isWellFormedDescriptor(value, "pslBlock")) throw new Error(`Malformed authoring pslBlock contribution at "${currentPath.join(".")}". The value carries descriptor keys (kind/keyword/discriminator) but does not satisfy the pslBlock descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`); | ||
| entries.push({ | ||
| path: currentPath.join("."), | ||
| discriminator: value.discriminator, | ||
| keyword: value.keyword | ||
| }); | ||
| continue; | ||
| } | ||
| if (typeof value === "object" && value !== null && !Array.isArray(value)) { | ||
| const record = blindCast(value); | ||
| const hasKind = record["kind"] === "pslBlock"; | ||
| const hasKeyword = typeof record["keyword"] === "string"; | ||
| const hasDiscriminator = typeof record["discriminator"] === "string"; | ||
| if (hasKind || hasKeyword && hasDiscriminator) throw new Error(`Malformed authoring pslBlock contribution at "${currentPath.join(".")}". The value carries descriptor keys (kind/keyword/discriminator) but does not satisfy the pslBlock descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`); | ||
| entries.push(...collectPslBlockDescriptorEntries(value, currentPath)); | ||
| } | ||
| } | ||
| return entries; | ||
| } | ||
| /** | ||
| * Every `pslBlockDescriptors` entry requires a matching `entityTypes` factory | ||
| * with the same discriminator. An `entityTypes` factory may stand alone (e.g. | ||
| * `enum`, reachable from the TypeScript builder without any PSL block). | ||
| * | ||
| * Uniqueness for pslBlock entries is keyed on **keyword**, not discriminator: | ||
| * several keywords (e.g. `policy_select`/`policy_insert`) may legitimately | ||
| * share one discriminator, routing to the same `entityTypes` factory and the | ||
| * same `entries[discriminator]` slot — that N:1 shape is exactly what lets | ||
| * one entity kind be authored through several PSL keywords. What must stay | ||
| * unique is the keyword itself, since that's what the parser dispatches on. | ||
| */ | ||
| function assertPslBlocksHaveFactories(entityTypeNamespace, pslBlockNamespace) { | ||
| const blockEntries = collectPslBlockDescriptorEntries(pslBlockNamespace); | ||
| const entityEntries = collectDescriptorEntries(entityTypeNamespace, isAuthoringEntityTypeDescriptor, "entity", "entityType"); | ||
| assertUniqueDiscriminators(blockEntries.map((entry) => ({ | ||
| path: entry.path, | ||
| discriminator: entry.keyword | ||
| })), "pslBlock"); | ||
| assertUniqueDiscriminators(entityEntries, "entityType"); | ||
| const entityDiscriminators = new Set(entityEntries.map((entry) => entry.discriminator)); | ||
| for (const block of blockEntries) if (!entityDiscriminators.has(block.discriminator)) throw new Error(`Incomplete extension contribution: pslBlock helper "${block.path}" registers discriminator "${block.discriminator}" but no entityType contribution shares that discriminator. An extension-contributed PSL block requires a matching entityType factory so the parsed AST node can lower to an IR class instance; add an entityType helper with discriminator "${block.discriminator}".`); | ||
| } | ||
| function collectModelAttributeEntries(namespace, path = []) { | ||
| const entries = []; | ||
| for (const [key, value] of Object.entries(namespace)) { | ||
| const currentPath = [...path, key]; | ||
| if (isAuthoringModelAttributeDescriptor(value)) { | ||
| if (!isWellFormedDescriptor(value, "modelAttribute")) throw new Error(`Malformed authoring modelAttribute contribution at "${currentPath.join(".")}". The value carries descriptor keys (kind/attribute) but does not satisfy the modelAttribute descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`); | ||
| entries.push({ | ||
| path: currentPath.join("."), | ||
| discriminator: value.attribute | ||
| }); | ||
| continue; | ||
| } | ||
| if (typeof value === "object" && value !== null && !Array.isArray(value)) { | ||
| const record = blindCast(value); | ||
| if (typeof record["attribute"] === "string" && "spec" in record) throw new Error(`Malformed authoring modelAttribute contribution at "${currentPath.join(".")}". The value carries descriptor keys (kind/attribute) but does not satisfy the modelAttribute descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`); | ||
| entries.push(...collectModelAttributeEntries(value, currentPath)); | ||
| } | ||
| } | ||
| return entries; | ||
| } | ||
| /** | ||
| * Throws when two modelAttribute contributions — at any paths, even | ||
| * different ones — claim the same bare `@@` attribute name. The family | ||
| * interpreter dispatches by attribute name, not by registration path, so | ||
| * two descriptors claiming the same name would have one silently shadow | ||
| * the other. | ||
| */ | ||
| function assertUniqueModelAttributeNames(entries) { | ||
| const seen = /* @__PURE__ */ new Map(); | ||
| for (const { path, discriminator: attribute } of entries) { | ||
| const existing = seen.get(attribute); | ||
| if (existing !== void 0) throw new Error(`Duplicate modelAttribute "${attribute}" registered at both "${existing}" and "${path}". Each modelAttribute contribution must claim a unique attribute name.`); | ||
| seen.set(attribute, path); | ||
| } | ||
| } | ||
| function assertNoCrossRegistryCollisions(typeNamespace, fieldNamespace, entityTypeNamespace = {}, pslBlockNamespace = {}, modelAttributeNamespace = {}) { | ||
| const typePaths = new Set(collectDescriptorPaths(typeNamespace, isAuthoringTypeConstructorDescriptor)); | ||
| const fieldPaths = new Set(collectDescriptorPaths(fieldNamespace, isAuthoringFieldPresetDescriptor)); | ||
| const entityPaths = new Set(collectDescriptorPaths(entityTypeNamespace, isAuthoringEntityTypeDescriptor)); | ||
| const ambiguityHint = "Register each path in only one of authoringContributions.field / authoringContributions.type / authoringContributions.entityTypes."; | ||
| for (const fieldPath of fieldPaths) if (typePaths.has(fieldPath)) throw new Error(`Ambiguous authoring registry path "${fieldPath}". The same path is registered as both a type constructor and a field preset; PSL resolution would be ambiguous. ${ambiguityHint}`); | ||
| for (const entityPath of entityPaths) if (typePaths.has(entityPath) || fieldPaths.has(entityPath)) throw new Error(`Ambiguous authoring registry path "${entityPath}". The same path is registered as an entity contribution AND as a type constructor or field preset; PSL resolution would be ambiguous. ${ambiguityHint}`); | ||
| assertPslBlocksHaveFactories(entityTypeNamespace, pslBlockNamespace); | ||
| assertUniqueModelAttributeNames(collectModelAttributeEntries(modelAttributeNamespace)); | ||
| } | ||
| function resolveAuthoringTemplateValue(template, args) { | ||
| if (template === void 0) return; | ||
| if (isAuthoringArgRef(template)) { | ||
| let value = args[template.index]; | ||
| for (const segment of template.path ?? []) { | ||
| if (!isAuthoringTemplateRecord(value) || !Object.hasOwn(value, segment)) { | ||
| value = void 0; | ||
| break; | ||
| } | ||
| value = value[segment]; | ||
| } | ||
| if (value === void 0 && template.default !== void 0) return resolveAuthoringTemplateValue(template.default, args); | ||
| return value; | ||
| } | ||
| if (Array.isArray(template)) return template.map((value) => resolveAuthoringTemplateValue(value, args)); | ||
| if (typeof template === "object" && template !== null) { | ||
| const resolved = {}; | ||
| for (const [key, value] of Object.entries(template)) { | ||
| const resolvedValue = resolveAuthoringTemplateValue(value, args); | ||
| if (resolvedValue !== void 0) resolved[key] = resolvedValue; | ||
| } | ||
| return resolved; | ||
| } | ||
| return template; | ||
| } | ||
| function validateAuthoringArgument(descriptor, value, path) { | ||
| if (value === void 0) { | ||
| if (descriptor.optional) return; | ||
| throw new Error(`Missing required authoring helper argument at ${path}`); | ||
| } | ||
| if (descriptor.kind === "string") { | ||
| if (typeof value !== "string") throw new Error(`Authoring helper argument at ${path} must be a string`); | ||
| return; | ||
| } | ||
| if (descriptor.kind === "boolean") { | ||
| if (typeof value !== "boolean") throw new Error(`Authoring helper argument at ${path} must be a boolean`); | ||
| return; | ||
| } | ||
| if (descriptor.kind === "stringArray") { | ||
| if (!Array.isArray(value)) throw new Error(`Authoring helper argument at ${path} must be an array of strings`); | ||
| for (const entry of value) if (typeof entry !== "string") throw new Error(`Authoring helper argument at ${path} must be an array of strings`); | ||
| return; | ||
| } | ||
| if (descriptor.kind === "object") { | ||
| if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`Authoring helper argument at ${path} must be an object`); | ||
| const input = value; | ||
| const expectedKeys = new Set(Object.keys(descriptor.properties)); | ||
| for (const key of Object.keys(input)) if (!expectedKeys.has(key)) throw new Error(`Authoring helper argument at ${path} contains unknown property "${key}"`); | ||
| for (const [key, propertyDescriptor] of Object.entries(descriptor.properties)) validateAuthoringArgument(propertyDescriptor, input[key], `${path}.${key}`); | ||
| return; | ||
| } | ||
| if (typeof value !== "number" || Number.isNaN(value)) throw new Error(`Authoring helper argument at ${path} must be a number`); | ||
| if (descriptor.integer && !Number.isInteger(value)) throw new Error(`Authoring helper argument at ${path} must be an integer`); | ||
| if (descriptor.minimum !== void 0 && value < descriptor.minimum) throw new Error(`Authoring helper argument at ${path} must be >= ${descriptor.minimum}, received ${value}`); | ||
| if (descriptor.maximum !== void 0 && value > descriptor.maximum) throw new Error(`Authoring helper argument at ${path} must be <= ${descriptor.maximum}, received ${value}`); | ||
| } | ||
| function validateAuthoringHelperArguments(helperPath, descriptors, args) { | ||
| const expected = descriptors ?? []; | ||
| const minimumArgs = expected.reduce((count, descriptor, index) => descriptor.optional ? count : index + 1, 0); | ||
| if (args.length < minimumArgs || args.length > expected.length) throw new Error(`${helperPath} expects ${minimumArgs === expected.length ? expected.length : `${minimumArgs}-${expected.length}`} argument(s), received ${args.length}`); | ||
| expected.forEach((descriptor, index) => { | ||
| validateAuthoringArgument(descriptor, args[index], `${helperPath}[${index}]`); | ||
| }); | ||
| } | ||
| function resolveAuthoringStorageTypeTemplate(template, args) { | ||
| const nativeType = resolveAuthoringTemplateValue(template.nativeType, args); | ||
| if (typeof nativeType !== "string") throw new Error(`Resolved authoring nativeType must be a string for codec "${template.codecId}", received ${String(nativeType)}`); | ||
| const typeParams = template.typeParams === void 0 ? void 0 : resolveAuthoringTemplateValue(template.typeParams, args); | ||
| if (typeParams !== void 0 && !isAuthoringTemplateRecord(typeParams)) throw new Error(`Resolved authoring typeParams must be an object for codec "${template.codecId}", received ${String(typeParams)}`); | ||
| return { | ||
| codecId: template.codecId, | ||
| nativeType, | ||
| ...ifDefined("typeParams", typeParams) | ||
| }; | ||
| } | ||
| function resolveAuthoringColumnDefaultTemplate(template, args) { | ||
| if (template.kind === "literal") { | ||
| const value = resolveAuthoringTemplateValue(template.value, args); | ||
| if (value === void 0) throw new Error("Resolved authoring literal default must not be undefined"); | ||
| if (!isColumnDefaultLiteralInputValue(value)) throw new Error(`Resolved authoring literal default must be a JSON-serializable value or Date, received ${String(value)}`); | ||
| return { | ||
| kind: "literal", | ||
| value | ||
| }; | ||
| } | ||
| const expression = resolveAuthoringTemplateValue(template.expression, args); | ||
| if (expression === void 0 || typeof expression === "object" && expression !== null) throw new Error(`Resolved authoring function default expression must resolve to a primitive, received ${String(expression)}`); | ||
| return { | ||
| kind: "function", | ||
| expression: String(expression) | ||
| }; | ||
| } | ||
| function resolveExecutionMutationDefaultPhase(phase, template, args) { | ||
| const value = resolveAuthoringTemplateValue(template, args); | ||
| if (!isExecutionMutationDefaultValue(value)) throw new Error(`Authoring preset executionDefaults.${phase} did not resolve to a valid generator descriptor (kind: 'generator', id: string).`); | ||
| return value; | ||
| } | ||
| function resolveAuthoringExecutionDefaultsTemplate(template, args) { | ||
| return { | ||
| ...ifDefined("onCreate", template.onCreate !== void 0 ? resolveExecutionMutationDefaultPhase("onCreate", template.onCreate, args) : void 0), | ||
| ...ifDefined("onUpdate", template.onUpdate !== void 0 ? resolveExecutionMutationDefaultPhase("onUpdate", template.onUpdate, args) : void 0) | ||
| }; | ||
| } | ||
| function instantiateAuthoringTypeConstructor(descriptor, args) { | ||
| return resolveAuthoringStorageTypeTemplate(descriptor.output, args); | ||
| } | ||
| function instantiateAuthoringEntityType(helperPath, descriptor, args, ctx) { | ||
| if ("factory" in descriptor.output) { | ||
| const input = args[0]; | ||
| return blindCast(descriptor.output.factory)(input, ctx); | ||
| } | ||
| validateAuthoringHelperArguments(helperPath, descriptor.args, args); | ||
| return blindCast(resolveAuthoringTemplateValue(descriptor.output.template, args)); | ||
| } | ||
| function instantiateAuthoringFieldPreset(descriptor, args) { | ||
| return { | ||
| descriptor: resolveAuthoringStorageTypeTemplate(descriptor.output, args), | ||
| nullable: descriptor.output.nullable ?? false, | ||
| ...ifDefined("default", descriptor.output.default !== void 0 ? resolveAuthoringColumnDefaultTemplate(descriptor.output.default, args) : void 0), | ||
| ...ifDefined("executionDefaults", descriptor.output.executionDefaults !== void 0 ? resolveAuthoringExecutionDefaultsTemplate(descriptor.output.executionDefaults, args) : void 0), | ||
| id: descriptor.output.id ?? false, | ||
| unique: descriptor.output.unique ?? false | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { instantiateAuthoringFieldPreset as a, isAuthoringEntityTypeDescriptor as c, isAuthoringPslBlockDescriptor as d, isAuthoringTypeConstructorDescriptor as f, validateAuthoringHelperArguments as g, resolveEnumCodecId as h, instantiateAuthoringEntityType as i, isAuthoringFieldPresetDescriptor as l, resolveAuthoringTemplateValue as m, classifyEnumMemberType as n, instantiateAuthoringTypeConstructor as o, mergeAuthoringNamespaces as p, hasRegisteredFieldNamespace as r, isAuthoringArgRef as s, assertNoCrossRegistryCollisions as t, isAuthoringModelAttributeDescriptor as u }; | ||
| //# sourceMappingURL=framework-authoring-Bz_vaNZw.mjs.map |
Sorry, the diff of this file is too big to display
| import { r as CodecLookup } from "./codec-types-e32YHT3D.mjs"; | ||
| import { ColumnDefault, ExecutionMutationDefaultPhases } from "@prisma-next/contract/types"; | ||
| import { Type } from "arktype"; | ||
| //#region src/shared/psl-extension-block.d.ts | ||
| /** | ||
| * Shape-only types for the PSL source-position primitives, diagnostic | ||
| * codes, extension-block descriptor vocabulary, and the uniform | ||
| * extension-block AST node base. | ||
| * | ||
| * These live in the shared plane so an extension's authoring descriptor | ||
| * (`AuthoringPslBlockDescriptor` in `framework-authoring`) can reference | ||
| * them without crossing the shared → migration-plane boundary. The | ||
| * migration-plane `psl-ast.ts` re-exports everything here for consumers | ||
| * that import PSL AST types from the control entrypoint. | ||
| */ | ||
| interface PslPosition { | ||
| readonly offset: number; | ||
| readonly line: number; | ||
| readonly column: number; | ||
| } | ||
| interface PslSpan { | ||
| readonly start: PslPosition; | ||
| readonly end: PslPosition; | ||
| } | ||
| type PslDiagnosticCode = 'PSL_UNTERMINATED_BLOCK' | 'PSL_UNSUPPORTED_TOP_LEVEL_BLOCK' | 'PSL_INVALID_NAMESPACE_BLOCK' | 'PSL_INVALID_ATTRIBUTE_SYNTAX' | 'PSL_INVALID_MODEL_MEMBER' | 'PSL_UNSUPPORTED_MODEL_ATTRIBUTE' | 'PSL_UNSUPPORTED_FIELD_ATTRIBUTE' | 'PSL_INVALID_RELATION_ATTRIBUTE' | 'PSL_INVALID_REFERENTIAL_ACTION' | 'PSL_INVALID_DEFAULT_VALUE' | 'PSL_INVALID_ENUM_MEMBER' | 'PSL_INVALID_TYPES_MEMBER' | 'PSL_INVALID_QUALIFIED_TYPE' | ||
| /** | ||
| * A qualified name (e.g. a dotted type or attribute reference) is structurally | ||
| * invalid, such as an over-qualified or trailing-separator name. | ||
| */ | ||
| | 'PSL_INVALID_QUALIFIED_NAME' | ||
| /** | ||
| * A reserved declaration keyword (`model`/`enum`/`namespace`/`type`) that | ||
| * committed the declaration kind on the keyword alone but is missing its name | ||
| * and/or opening brace. The recursive-descent parser produces a best-effort | ||
| * typed node for the malformed header and reports this code rather than | ||
| * `PSL_UNSUPPORTED_TOP_LEVEL_BLOCK`, which is reserved for a genuinely unknown | ||
| * top-level keyword. | ||
| */ | ||
| | 'PSL_INVALID_DECLARATION' | ||
| /** | ||
| * A malformed line inside an extension-contributed top-level block body, or | ||
| * a structurally invalid element inside a `list` parameter value. | ||
| * | ||
| * Replaces the overloaded `PSL_UNSUPPORTED_TOP_LEVEL_BLOCK` code that the | ||
| * generic framework parser previously used for these two parse-error sites | ||
| * inside extension blocks — keeping `PSL_UNSUPPORTED_TOP_LEVEL_BLOCK` for | ||
| * its original meaning (an unknown keyword at the top level) and giving | ||
| * extension-block parse errors their own code. | ||
| */ | ||
| | 'PSL_INVALID_EXTENSION_BLOCK_MEMBER' | ||
| /** | ||
| * A malformed JS-like object literal `{ key: value, … }` in value/argument | ||
| * position — a field missing its `:`, a field missing its value, or an | ||
| * unterminated `{`. The recursive-descent parser still produces a best-effort | ||
| * `ObjectLiteralExpr` node (preserving the lossless round-trip) and reports | ||
| * this code anchored on the offending token. | ||
| */ | ||
| | 'PSL_INVALID_OBJECT_LITERAL' | ||
| /** | ||
| * A string literal with no closing quote — the tokenizer stops the literal at | ||
| * a newline or at EOF when no terminating `"` is found, and the | ||
| * recursive-descent parser still consumes the token (preserving the lossless | ||
| * round-trip) but reports this code anchored on the string token's span. | ||
| */ | ||
| | 'PSL_UNTERMINATED_STRING' | ||
| /** | ||
| * An unknown parameter key in an extension-contributed block — a key present | ||
| * in the source block but absent from the descriptor's `parameters` map. | ||
| */ | ||
| | 'PSL_EXTENSION_UNKNOWN_PARAMETER' | ||
| /** | ||
| * A required parameter declared in the descriptor is absent from the parsed block. | ||
| */ | ||
| | 'PSL_EXTENSION_MISSING_REQUIRED_PARAMETER' | ||
| /** | ||
| * An `option`-kind parameter value is not one of the allowed tokens listed | ||
| * in the descriptor's `values` array. | ||
| */ | ||
| | 'PSL_EXTENSION_OPTION_OUT_OF_SET' | ||
| /** | ||
| * A `value`-kind parameter's raw text is not a valid JSON literal, or the | ||
| * parsed JSON value was rejected by the codec's `decodeJson` method, or the | ||
| * codec id is not registered in the lookup. | ||
| */ | ||
| | 'PSL_EXTENSION_INVALID_VALUE' | ||
| /** | ||
| * A `ref`-kind parameter identifier does not resolve to a declared entity of | ||
| * the required `refKind` within the declared scope. | ||
| */ | ||
| | 'PSL_EXTENSION_UNRESOLVED_REF' | ||
| /** | ||
| * A parameter key appears more than once in an extension block body. | ||
| * The first occurrence is kept; subsequent occurrences emit this diagnostic. | ||
| */ | ||
| | 'PSL_EXTENSION_DUPLICATE_PARAMETER' | ||
| /** | ||
| * A `@@`-prefixed block-attribute line inside an extension block has invalid syntax. | ||
| */ | ||
| | 'PSL_INVALID_EXTENSION_BLOCK_ATTRIBUTE' | ||
| /** | ||
| * Duplicate scopes are top level, namespace body, or block fields; diagnostics | ||
| * are first-wins and anchored on later name spans. | ||
| */ | ||
| | 'PSL_DUPLICATE_DECLARATION'; | ||
| /** | ||
| * Descriptor vocabulary for a single parameter on a declared block. | ||
| * | ||
| * Four kinds: | ||
| * - `ref` — the parameter value is an identifier that must resolve to a | ||
| * declared entity of `refKind` within the declared `scope`. | ||
| * - `value` — the parameter value is a PSL literal parsed and printed | ||
| * through the codec identified by `codecId`. | ||
| * - `option` — the parameter value is one of the literal tokens in `values`. | ||
| * Not a codec; not persisted data. A closed authoring-time constraint only. | ||
| * - `list` — a bracketed list whose elements each match the `of` descriptor. | ||
| */ | ||
| type PslBlockParam = PslBlockParamRef | PslBlockParamValue | PslBlockParamOption | PslBlockParamList; | ||
| interface PslBlockParamRef { | ||
| readonly kind: 'ref'; | ||
| readonly refKind: string; | ||
| readonly scope: 'same-namespace' | 'same-space' | 'cross-space'; | ||
| readonly required?: boolean; | ||
| } | ||
| interface PslBlockParamValue { | ||
| readonly kind: 'value'; | ||
| readonly codecId: string; | ||
| readonly required?: boolean; | ||
| } | ||
| interface PslBlockParamOption { | ||
| readonly kind: 'option'; | ||
| readonly values: readonly string[]; | ||
| readonly required?: boolean; | ||
| } | ||
| interface PslBlockParamList { | ||
| readonly kind: 'list'; | ||
| readonly of: PslBlockParam; | ||
| readonly required?: boolean; | ||
| } | ||
| /** | ||
| * The parsed representation of a single parameter value on a uniform | ||
| * extension-block AST node. Mirrors the `PslBlockParam` descriptor | ||
| * vocabulary, plus `bare` for keyonly entries: | ||
| * | ||
| * - `ref` → `PslExtensionBlockParamRef` — a raw identifier string | ||
| * (resolution runs in the validator, not the parser). | ||
| * - `value` → `PslExtensionBlockParamScalarValue` — a raw PSL literal string | ||
| * (codec validation runs in the validator). | ||
| * - `option` → `PslExtensionBlockParamOption` — the chosen token. | ||
| * - `list` → `PslExtensionBlockParamList` — ordered list of the above. | ||
| * - `bare` → `PslExtensionBlockParamBare` — a bare identifier line with no | ||
| * `= value` (e.g. `Low` in an enum block). The name is the key in | ||
| * `parameters`; the interpreting consumer decides the default value. | ||
| * | ||
| * These shapes are intentionally minimal. The validator and lowering refine | ||
| * and consume them; the generic framework parser produces them. | ||
| */ | ||
| type PslExtensionBlockParamValue = PslExtensionBlockParamRef | PslExtensionBlockParamScalarValue | PslExtensionBlockParamOption | PslExtensionBlockParamList | PslExtensionBlockParamBare; | ||
| interface PslExtensionBlockParamRef { | ||
| readonly kind: 'ref'; | ||
| readonly identifier: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslExtensionBlockParamScalarValue { | ||
| readonly kind: 'value'; | ||
| readonly raw: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslExtensionBlockParamOption { | ||
| readonly kind: 'option'; | ||
| readonly token: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslExtensionBlockParamList { | ||
| readonly kind: 'list'; | ||
| readonly items: readonly PslExtensionBlockParamValue[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** | ||
| * A bare identifier line inside an extension block — a key with no `= value`. | ||
| * Emitted when a line matches `/^[A-Za-z_]\w*$/` with no assignment. The | ||
| * consumer decides what default value (if any) to apply. | ||
| */ | ||
| interface PslExtensionBlockParamBare { | ||
| readonly kind: 'bare'; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** | ||
| * A positional argument on a block attribute, e.g. the `"pg/text@1"` in | ||
| * `@@type("pg/text@1")`. | ||
| */ | ||
| interface PslExtensionBlockAttributeArg { | ||
| readonly kind: 'positional'; | ||
| readonly value: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** | ||
| * A `@@`-prefixed block-level attribute parsed inside an extension block, | ||
| * e.g. `@@type("pg/text@1")`. Block attributes are captured generically | ||
| * — the parser does not validate attribute names or argument shapes; that | ||
| * is a concern of the block's interpreter. | ||
| */ | ||
| interface PslExtensionBlockAttribute { | ||
| readonly name: string; | ||
| readonly args: readonly PslExtensionBlockAttributeArg[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** | ||
| * Base shape for a uniform extension-contributed top-level PSL block | ||
| * node, as produced by the generic framework parser and consumed by the | ||
| * validator, printer, and lowering factory. | ||
| * | ||
| * - `kind` is the routing discriminant, equal to the descriptor's | ||
| * `discriminator`. The framework parser sets this to | ||
| * `descriptor.discriminator` for every block it parses. Several keywords | ||
| * may share one discriminator (e.g. `policy_select`/`policy_insert` both | ||
| * route to `kind: 'policy'`) — `kind` identifies the entity/storage kind, | ||
| * not the source syntax. | ||
| * - `keyword` is the source PSL keyword the block was declared with | ||
| * (`policy_select`, `policy_insert`, …) — the parse-dispatch identity. | ||
| * Distinct from `kind` precisely when a discriminator is shared by more | ||
| * than one keyword; a lowering factory that contributes several keywords | ||
| * under one discriminator reads `keyword` to tell its blocks apart, and | ||
| * the printer re-emits each block under its own `keyword` regardless of | ||
| * how many other keywords share its `kind`. | ||
| * - `name` is the block's declared name (the identifier after the keyword). | ||
| * - `parameters` is the descriptor-driven parameter map. Keys are | ||
| * parameter names from the descriptor; values are the parsed parameter | ||
| * representations. Only parameters present in the source are included | ||
| * — absence of a required parameter is a validator concern, not a | ||
| * parser concern. Insertion order is preserved; the first occurrence of a | ||
| * duplicate key is retained and subsequent occurrences emit | ||
| * `PSL_EXTENSION_DUPLICATE_PARAMETER`. | ||
| * - `blockAttributes` are `@@`-prefixed attribute lines inside the block, in | ||
| * declaration order. Captured generically — names and args are not validated | ||
| * by the parser. | ||
| * - `span` covers the full block from keyword to closing brace. | ||
| */ | ||
| interface PslExtensionBlock { | ||
| readonly kind: string; | ||
| /** | ||
| * The block's parse identity — the source PSL keyword it was declared | ||
| * with. `kind`/`discriminator` is its storage identity; several keywords | ||
| * can share one. E.g. the five `policy_*` keywords all lower to the | ||
| * `policy` entity kind. | ||
| */ | ||
| readonly keyword: string; | ||
| readonly name: string; | ||
| readonly parameters: Record<string, PslExtensionBlockParamValue>; | ||
| readonly blockAttributes: readonly PslExtensionBlockAttribute[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| //#endregion | ||
| //#region src/shared/framework-authoring.d.ts | ||
| type AuthoringArgRef = { | ||
| readonly kind: 'arg'; | ||
| readonly index: number; | ||
| readonly path?: readonly string[]; | ||
| readonly default?: AuthoringTemplateValue; | ||
| }; | ||
| type AuthoringTemplateValue = string | number | boolean | null | AuthoringArgRef | readonly AuthoringTemplateValue[] | { | ||
| readonly [key: string]: AuthoringTemplateValue; | ||
| }; | ||
| interface AuthoringArgumentDescriptorCommon { | ||
| readonly name?: string; | ||
| readonly optional?: boolean; | ||
| } | ||
| type AuthoringArgumentDescriptor = AuthoringArgumentDescriptorCommon & ({ | ||
| readonly kind: 'string'; | ||
| } | { | ||
| readonly kind: 'boolean'; | ||
| } | { | ||
| readonly kind: 'number'; | ||
| readonly integer?: boolean; | ||
| readonly minimum?: number; | ||
| readonly maximum?: number; | ||
| } | { | ||
| readonly kind: 'stringArray'; | ||
| } | { | ||
| readonly kind: 'object'; | ||
| readonly properties: Record<string, AuthoringArgumentDescriptor>; | ||
| }); | ||
| interface AuthoringStorageTypeTemplate { | ||
| readonly codecId: string; | ||
| /** | ||
| * Optional so a type constructor whose {@link AuthoringTypeConstructorDescriptor.entityRefArg} | ||
| * names another entity can omit this template entirely — its output for | ||
| * that case is derived by the codec at `codecId`, not by resolving a | ||
| * literal here. Every other consumer of this shape (field presets, plain | ||
| * type constructors) always supplies it. | ||
| */ | ||
| readonly nativeType?: AuthoringTemplateValue; | ||
| readonly typeParams?: Record<string, AuthoringTemplateValue>; | ||
| } | ||
| /** | ||
| * Declares that one positional argument of a | ||
| * {@link AuthoringTypeConstructorDescriptor} call names another entity | ||
| * parsed from the same document, rather than carrying a literal value (e.g. | ||
| * `pg.enum(AalLevel)` naming a `native_enum` entity). `index` is the | ||
| * argument's position in the call; `entityKind` is the entries-slot | ||
| * discriminator the interpreter looks the named entity up under (the same | ||
| * shape {@link AuthoringEntityTypeFactoryOutput.factory} output is collected | ||
| * into, keyed by discriminator then block name). | ||
| * | ||
| * The interpreter resolves the named argument to the entity instance | ||
| * generically, driven only by this declaration — it has no target-specific | ||
| * knowledge of which type constructors carry one. Converting the resolved | ||
| * entity into the constructor's params is a separate, codec-owned concern: | ||
| * the codec descriptor registered for `output.codecId` supplies that | ||
| * conversion, not this framework type. | ||
| */ | ||
| interface AuthoringTypeConstructorEntityRef { | ||
| readonly index: number; | ||
| readonly entityKind: string; | ||
| } | ||
| interface AuthoringTypeConstructorDescriptor { | ||
| readonly kind: 'typeConstructor'; | ||
| readonly args?: readonly AuthoringArgumentDescriptor[]; | ||
| readonly output: AuthoringStorageTypeTemplate; | ||
| /** Present when one of this constructor's positional arguments names another document-local entity instead of carrying a literal value. Absent for ordinary literal-argument constructors. */ | ||
| readonly entityRefArg?: AuthoringTypeConstructorEntityRef; | ||
| } | ||
| interface AuthoringColumnDefaultTemplateLiteral { | ||
| readonly kind: 'literal'; | ||
| readonly value: AuthoringTemplateValue; | ||
| } | ||
| interface AuthoringColumnDefaultTemplateFunction { | ||
| readonly kind: 'function'; | ||
| readonly expression: AuthoringTemplateValue; | ||
| } | ||
| type AuthoringColumnDefaultTemplate = AuthoringColumnDefaultTemplateLiteral | AuthoringColumnDefaultTemplateFunction; | ||
| interface AuthoringExecutionDefaultsTemplate { | ||
| readonly onCreate?: AuthoringTemplateValue; | ||
| readonly onUpdate?: AuthoringTemplateValue; | ||
| } | ||
| interface AuthoringFieldPresetOutput extends AuthoringStorageTypeTemplate { | ||
| readonly nullable?: boolean; | ||
| readonly default?: AuthoringColumnDefaultTemplate; | ||
| readonly executionDefaults?: AuthoringExecutionDefaultsTemplate; | ||
| readonly id?: boolean; | ||
| readonly unique?: boolean; | ||
| } | ||
| interface AuthoringFieldPresetDescriptor { | ||
| readonly kind: 'fieldPreset'; | ||
| readonly args?: readonly AuthoringArgumentDescriptor[]; | ||
| readonly output: AuthoringFieldPresetOutput; | ||
| } | ||
| type AuthoringTypeNamespace = { | ||
| readonly [name: string]: AuthoringTypeConstructorDescriptor | AuthoringTypeNamespace; | ||
| }; | ||
| type AuthoringFieldNamespace = { | ||
| readonly [name: string]: AuthoringFieldPresetDescriptor | AuthoringFieldNamespace; | ||
| }; | ||
| /** | ||
| * Context surfaced to entity-type factories at call time. Currently a | ||
| * placeholder — sharpened as concrete consumers (enum, namespace, …) | ||
| * discover what the factory actually needs to read (codec lookup, | ||
| * namespace registry, …). | ||
| */ | ||
| /** | ||
| * A write-only sink that a factory may push authoring-time diagnostics into. | ||
| * The concrete type pushed must be structurally compatible with whatever the | ||
| * consumer accumulates (typically `ContractSourceDiagnostic[]`); the framework | ||
| * layer deliberately does not depend on that concrete type. | ||
| */ | ||
| interface AuthoringDiagnosticSink { | ||
| push(d: { | ||
| readonly code: string; | ||
| readonly message: string; | ||
| readonly sourceId: string; | ||
| readonly span?: unknown; | ||
| }): void; | ||
| } | ||
| interface AuthoringEntityContext { | ||
| readonly family: string; | ||
| readonly target: string; | ||
| /** Codec registry available to factories that need to validate or decode values. */ | ||
| readonly codecLookup?: CodecLookup; | ||
| /** Source file identifier threaded into diagnostics emitted by the factory. */ | ||
| readonly sourceId?: string; | ||
| /** Push channel for authoring-time diagnostics emitted by the factory. */ | ||
| readonly diagnostics?: AuthoringDiagnosticSink; | ||
| /** | ||
| * The target's default codec ids for an `enum` block that omits `@@type`. | ||
| * `text` is used when every member is a bare name or a string value; | ||
| * `int` is used when every member is an integer value. Every target pack | ||
| * populates this so `@@type` omission can be inferred consistently. | ||
| */ | ||
| readonly enumInferenceCodecs?: { | ||
| readonly text: string; | ||
| readonly int: string; | ||
| }; | ||
| } | ||
| /** | ||
| * Classifies an `enum` block's members (before codec decoding, which needs | ||
| * the codec chosen first) into which default codec an omitted `@@type` | ||
| * should resolve to: | ||
| * | ||
| * - every member is `bare`, or a `value` whose raw JSON is a string → `'text'` | ||
| * - every member is a `value` whose raw JSON is an integer → `'int'` | ||
| * - anything else (float, bigint, boolean, mixed, or a `ref`/`option`/`list` | ||
| * parameter) → `null`, meaning the caller must require an explicit `@@type`. | ||
| */ | ||
| declare function classifyEnumMemberType(block: PslExtensionBlock): 'text' | 'int' | null; | ||
| /** | ||
| * Resolves the codec id for an `enum` block. When `@@type` is absent, the codec | ||
| * is inferred from the members via {@link classifyEnumMemberType}; otherwise the | ||
| * explicit `@@type("codec")` argument is parsed. Pushes the appropriate | ||
| * diagnostic and returns `undefined` when neither yields a codec. `codecSpan` is | ||
| * the span downstream codec-validation diagnostics should anchor to. Shared by | ||
| * every family's enum factory so inference and the explicit path stay identical. | ||
| */ | ||
| declare function resolveEnumCodecId(block: PslExtensionBlock, ctx: AuthoringEntityContext): { | ||
| readonly codecId: string; | ||
| readonly codecSpan: PslSpan; | ||
| } | undefined; | ||
| interface AuthoringEntityTypeTemplateOutput { | ||
| readonly template: AuthoringTemplateValue; | ||
| } | ||
| /** | ||
| * Default `Input = never` is load-bearing for pack-bag-driven type | ||
| * narrowing. Factory parameter positions are contravariant, so a pack | ||
| * literal declaring `factory: (input: DemoEntityInput) => DemoEntity` | ||
| * is only assignable to the base descriptor's factory shape if the | ||
| * base's input is `never` (the bottom of the contravariant position). | ||
| * The concrete input/output types are recovered at the helper-derivation | ||
| * site via `EntityHelperFunction<Descriptor>`'s conditional inference, | ||
| * which reads them from the pack's `as const` literal factory signature | ||
| * — the base widening does not erase the literal because `satisfies` | ||
| * does not widen the declared type. | ||
| */ | ||
| interface AuthoringEntityTypeFactoryOutput<Input = never, Output = unknown> { | ||
| readonly factory: (input: Input, ctx: AuthoringEntityContext) => Output; | ||
| } | ||
| interface AuthoringEntityTypeDescriptor<Input = never, Output = unknown> { | ||
| readonly kind: 'entity'; | ||
| readonly discriminator: string; | ||
| readonly args?: readonly AuthoringArgumentDescriptor[]; | ||
| readonly output: AuthoringEntityTypeTemplateOutput | AuthoringEntityTypeFactoryOutput<Input, Output>; | ||
| /** | ||
| * arktype schema fragment for one entry whose envelope `kind` matches | ||
| * this descriptor's {@link discriminator}. The family validator composes | ||
| * contributed fragments into the per-namespace entry schema at | ||
| * validator construction time so the structural check covers | ||
| * pack-introduced kinds without the family core hard-coding the schema. | ||
| * | ||
| * Hydration uses {@link AuthoringEntityTypeFactoryOutput.factory} | ||
| * directly — the wire shape conforms structurally to the factory's | ||
| * `Input` after `validatorSchema` validates it. | ||
| */ | ||
| readonly validatorSchema?: Type<unknown>; | ||
| } | ||
| type AuthoringEntityTypeNamespace = { | ||
| readonly [name: string]: AuthoringEntityTypeDescriptor | AuthoringEntityTypeNamespace; | ||
| }; | ||
| /** | ||
| * Declarative descriptor for an extension-contributed top-level PSL block. | ||
| * | ||
| * An extension registers one of these per keyword it contributes. The | ||
| * framework owns the generic parser, validator, and printer — no | ||
| * parsing or printing code runs from the extension. | ||
| * | ||
| * - `keyword` is the PSL top-level identifier this descriptor claims | ||
| * (`policy_select`, `role`, …). | ||
| * - `discriminator` is the routing key used by the printer dispatch and | ||
| * the `entityTypes` lowering factory lookup. Convention: | ||
| * `<target-or-family>-<kind>` (`postgres-policy-select`). | ||
| * - `name.required` declares whether the block must have a name token | ||
| * after the keyword. Currently always `true` — anonymous blocks are | ||
| * not part of the closed-grammar premise — but the field is explicit | ||
| * so the type can evolve without a breaking change. | ||
| * - `parameters` maps parameter names to their value-kind descriptors | ||
| * (`ref` / `value` / `option` / `list`). The generic parser and | ||
| * validator interpret these; the extension supplies no parser or | ||
| * printer function. | ||
| */ | ||
| interface AuthoringPslBlockDescriptor { | ||
| readonly kind: 'pslBlock'; | ||
| readonly keyword: string; | ||
| readonly discriminator: string; | ||
| readonly name: { | ||
| readonly required: boolean; | ||
| }; | ||
| readonly parameters: Record<string, PslBlockParam>; | ||
| /** | ||
| * When `true`, the block body accepts a variadic tail of parameters beyond | ||
| * the declared set. The block body may contain: fields (model-style), | ||
| * `key = value` parameters, and `@@` attributes. With `variadicParameters`, | ||
| * bare identifiers (keys without a `= value`) and undeclared `key = value` | ||
| * pairs flow into the variadic tail — their semantics belong to the | ||
| * lowering, not the parser. | ||
| * | ||
| * A key that IS declared in `parameters` must still be supplied as | ||
| * `key = value`; a bare occurrence of a declared key is a diagnostic. | ||
| * | ||
| * When `false` (default), the validator emits `PSL_EXTENSION_UNKNOWN_PARAMETER` | ||
| * for keys absent from `parameters`. | ||
| */ | ||
| readonly variadicParameters?: boolean; | ||
| /** | ||
| * Declares that the model named by the block's ref parameter `parameter` | ||
| * must carry the bare `@@` model attribute `attribute`. The family | ||
| * interpreter enforces this generically over the whole parsed document — | ||
| * declaration order of the block and the model does not matter — and | ||
| * emits `PSL_EXTENSION_TARGET_MODEL_MISSING_ATTRIBUTE` naming the block | ||
| * and the model when the attribute is absent. A parameter that is | ||
| * missing or does not resolve to a model is not this rule's concern | ||
| * (missing-parameter and unresolved-ref diagnostics own those cases). | ||
| */ | ||
| readonly requiresModelAttribute?: { | ||
| readonly parameter: string; | ||
| readonly attribute: string; | ||
| }; | ||
| } | ||
| type AuthoringPslBlockDescriptorNamespace = { | ||
| readonly [name: string]: AuthoringPslBlockDescriptor | AuthoringPslBlockDescriptorNamespace; | ||
| }; | ||
| /** | ||
| * Context surfaced to a model-attribute lowering at call time: the entity | ||
| * context shared with entity-type factories, plus the declaring model's | ||
| * name, its mapped storage name (the name of the storage object the model | ||
| * maps to; which kind of object that is belongs to the family, not the | ||
| * framework), and the namespace id the lowered entity should be filed | ||
| * under. | ||
| */ | ||
| interface AuthoringModelAttributeContext extends AuthoringEntityContext { | ||
| readonly modelName: string; | ||
| readonly storageName: string; | ||
| readonly namespaceId: string; | ||
| } | ||
| /** | ||
| * What a model-attribute lowering returns when it produces an entity: `key` | ||
| * is the identity the entity is stored under within its `entries` slot | ||
| * (`entries[attribute][key]`); `entity` is the value stored there. A | ||
| * lowering that instead pushed a diagnostic through | ||
| * {@link AuthoringModelAttributeContext.diagnostics} returns `undefined` — | ||
| * the same convention {@link AuthoringEntityTypeFactoryOutput} uses. | ||
| */ | ||
| interface AuthoringModelAttributeLoweringOutput { | ||
| readonly key: string; | ||
| readonly entity: unknown; | ||
| } | ||
| /** | ||
| * Declarative descriptor for an extension-contributed `@@` model attribute. | ||
| * | ||
| * An extension registers one of these per bare attribute name it | ||
| * contributes. The framework owns the generic consult in the interpreter's | ||
| * model-attribute loop; the contribution supplies only `spec` and `lower`. | ||
| * | ||
| * - `attribute` is the bare `@@` attribute name this descriptor claims and, | ||
| * by the one-string rule, the `entries` slot its lowered entities are | ||
| * grouped under (`entries[attribute][key]`). | ||
| * - `spec` is opaque to the framework core: an ADR-231 attribute-spec kit | ||
| * `AttributeSpec<Out>` value (`modelAttribute(name, {...})` from | ||
| * `@prisma-next/psl-parser`). Framework core does not depend on | ||
| * psl-parser and never inspects this field; the family interpreter, | ||
| * which does depend on psl-parser, parses the attribute's arguments | ||
| * against it. | ||
| * - `lower` receives the parsed arguments and the declaring model's | ||
| * context, and returns the entity to file into `entries`, or `undefined` | ||
| * after pushing a diagnostic via `ctx.diagnostics`. | ||
| * | ||
| * `Out` defaults to `never` — not `unknown` — for the same contravariance | ||
| * reason documented on {@link AuthoringEntityTypeFactoryOutput}: a concrete | ||
| * pack literal's narrower `lower(parsed: ConcreteOut, ctx)` is only | ||
| * assignable to this base shape when the base parameter is the bottom type. | ||
| */ | ||
| interface AuthoringModelAttributeDescriptor<Out = never> { | ||
| readonly kind: 'modelAttribute'; | ||
| readonly attribute: string; | ||
| readonly spec: unknown; | ||
| readonly lower: (parsed: Out, ctx: AuthoringModelAttributeContext) => AuthoringModelAttributeLoweringOutput | undefined; | ||
| } | ||
| type AuthoringModelAttributeDescriptorNamespace = { | ||
| readonly [name: string]: AuthoringModelAttributeDescriptor | AuthoringModelAttributeDescriptorNamespace; | ||
| }; | ||
| interface AuthoringContributions { | ||
| readonly type?: AuthoringTypeNamespace; | ||
| readonly field?: AuthoringFieldNamespace; | ||
| readonly entityTypes?: AuthoringEntityTypeNamespace; | ||
| /** | ||
| * Registry of declarative block descriptors this contribution registers, | ||
| * keyed by arbitrary path segments. Each leaf is an | ||
| * {@link AuthoringPslBlockDescriptor} that claims a PSL top-level keyword. | ||
| * The framework owns the generic parser, validator, and printer; the | ||
| * contribution supplies only these declarative descriptors. | ||
| * | ||
| * Contrast with the parsed block nodes themselves, which live in a | ||
| * namespace's `entries` under their discriminator key; this field holds the | ||
| * registry of descriptors that teach the parser how to read those blocks. | ||
| */ | ||
| readonly pslBlockDescriptors?: AuthoringPslBlockDescriptorNamespace; | ||
| /** | ||
| * Registry of declarative `@@` model attribute descriptors this | ||
| * contribution registers, keyed by arbitrary path segments. Each leaf is | ||
| * an {@link AuthoringModelAttributeDescriptor} that claims a bare model | ||
| * attribute name. The framework owns the generic consult in the family | ||
| * interpreter's model-attribute loop; the contribution supplies only the | ||
| * declarative spec and the lowering. | ||
| */ | ||
| readonly modelAttributes?: AuthoringModelAttributeDescriptorNamespace; | ||
| } | ||
| declare function isAuthoringArgRef(value: unknown): value is AuthoringArgRef; | ||
| declare function isAuthoringTypeConstructorDescriptor(value: AuthoringTypeConstructorDescriptor | AuthoringTypeNamespace): value is AuthoringTypeConstructorDescriptor; | ||
| declare function isAuthoringFieldPresetDescriptor(value: AuthoringFieldPresetDescriptor | AuthoringFieldNamespace): value is AuthoringFieldPresetDescriptor; | ||
| declare function isAuthoringEntityTypeDescriptor(value: AuthoringEntityTypeDescriptor | AuthoringEntityTypeNamespace): value is AuthoringEntityTypeDescriptor; | ||
| declare function isAuthoringPslBlockDescriptor(value: AuthoringPslBlockDescriptor | AuthoringPslBlockDescriptorNamespace): value is AuthoringPslBlockDescriptor; | ||
| declare function isAuthoringModelAttributeDescriptor(value: AuthoringModelAttributeDescriptor | AuthoringModelAttributeDescriptorNamespace): value is AuthoringModelAttributeDescriptor; | ||
| /** | ||
| * Returns true when `namespace` is a non-leaf key in `contributions.field`. | ||
| * | ||
| * `AuthoringFieldNamespace` permits a leaf descriptor at any depth — including | ||
| * the root — so a top-level `field: { Foo: { kind: 'fieldPreset', ... } }` | ||
| * registration must NOT be treated as a "namespace" with sub-paths. Callers | ||
| * use this predicate to gate dot-namespaced lookups (e.g. PSL `@Foo.bar`). | ||
| */ | ||
| declare function hasRegisteredFieldNamespace(contributions: AuthoringContributions | undefined, namespace: string): boolean; | ||
| /** | ||
| * Merges `source` into `target` recursively at the descriptor-namespace | ||
| * level. `descriptorKind` is the `kind` value ('typeConstructor', | ||
| * 'fieldPreset', 'entity', or 'pslBlock') that identifies a descriptor | ||
| * (terminal merge point; same-path registrations across components are | ||
| * reported as duplicates) as opposed to a sub-namespace (recursion target). | ||
| * | ||
| * Path segments are validated against prototype-pollution names | ||
| * (`__proto__`, `constructor`, `prototype`). A value that is neither a | ||
| * recognized leaf nor a plain object — e.g. a malformed descriptor | ||
| * where the canonical leaf guard rejected it for missing `output` — | ||
| * is reported as an invalid contribution rather than recursed into, | ||
| * which would either silently mangle state or infinite-loop on | ||
| * primitive properties. | ||
| * | ||
| * Within-registry duplicate detection is this walker's job; | ||
| * cross-registry detection runs separately via | ||
| * `assertNoCrossRegistryCollisions` after merging completes. | ||
| */ | ||
| declare function mergeAuthoringNamespaces(target: Record<string, unknown>, source: Record<string, unknown>, path: readonly string[], descriptorKind: string, label: string): void; | ||
| declare function assertNoCrossRegistryCollisions(typeNamespace: AuthoringTypeNamespace, fieldNamespace: AuthoringFieldNamespace, entityTypeNamespace?: AuthoringEntityTypeNamespace, pslBlockNamespace?: AuthoringPslBlockDescriptorNamespace, modelAttributeNamespace?: AuthoringModelAttributeDescriptorNamespace): void; | ||
| declare function resolveAuthoringTemplateValue(template: AuthoringTemplateValue | undefined, args: readonly unknown[]): unknown; | ||
| declare function validateAuthoringHelperArguments(helperPath: string, descriptors: readonly AuthoringArgumentDescriptor[] | undefined, args: readonly unknown[]): void; | ||
| declare function instantiateAuthoringTypeConstructor(descriptor: AuthoringTypeConstructorDescriptor, args: readonly unknown[]): { | ||
| readonly codecId: string; | ||
| readonly nativeType: string; | ||
| readonly typeParams?: Record<string, unknown>; | ||
| }; | ||
| declare function instantiateAuthoringEntityType<TOutput = unknown>(helperPath: string, descriptor: AuthoringEntityTypeDescriptor, args: readonly unknown[], ctx: AuthoringEntityContext): TOutput; | ||
| declare function instantiateAuthoringFieldPreset(descriptor: AuthoringFieldPresetDescriptor, args: readonly unknown[]): { | ||
| readonly descriptor: { | ||
| readonly codecId: string; | ||
| readonly nativeType: string; | ||
| readonly typeParams?: Record<string, unknown>; | ||
| }; | ||
| readonly nullable: boolean; | ||
| readonly default?: ColumnDefault; | ||
| readonly executionDefaults?: ExecutionMutationDefaultPhases; | ||
| readonly id: boolean; | ||
| readonly unique: boolean; | ||
| }; | ||
| //#endregion | ||
| export { PslExtensionBlockParamRef as $, instantiateAuthoringTypeConstructor as A, validateAuthoringHelperArguments as B, AuthoringTypeConstructorEntityRef as C, hasRegisteredFieldNamespace as D, classifyEnumMemberType as E, isAuthoringPslBlockDescriptor as F, PslBlockParamValue as G, PslBlockParamList as H, isAuthoringTypeConstructorDescriptor as I, PslExtensionBlockAttribute as J, PslDiagnosticCode as K, mergeAuthoringNamespaces as L, isAuthoringEntityTypeDescriptor as M, isAuthoringFieldPresetDescriptor as N, instantiateAuthoringEntityType as O, isAuthoringModelAttributeDescriptor as P, PslExtensionBlockParamOption as Q, resolveAuthoringTemplateValue as R, AuthoringTypeConstructorDescriptor as S, assertNoCrossRegistryCollisions as T, PslBlockParamOption as U, PslBlockParam as V, PslBlockParamRef as W, PslExtensionBlockParamBare as X, PslExtensionBlockAttributeArg as Y, PslExtensionBlockParamList as Z, AuthoringModelAttributeLoweringOutput as _, AuthoringDiagnosticSink as a, AuthoringStorageTypeTemplate as b, AuthoringEntityTypeFactoryOutput as c, AuthoringFieldNamespace as d, PslExtensionBlockParamScalarValue as et, AuthoringFieldPresetDescriptor as f, AuthoringModelAttributeDescriptorNamespace as g, AuthoringModelAttributeDescriptor as h, AuthoringContributions as i, isAuthoringArgRef as j, instantiateAuthoringFieldPreset as k, AuthoringEntityTypeNamespace as l, AuthoringModelAttributeContext as m, AuthoringArgumentDescriptor as n, PslPosition as nt, AuthoringEntityContext as o, AuthoringFieldPresetOutput as p, PslExtensionBlock as q, AuthoringColumnDefaultTemplate as r, PslSpan as rt, AuthoringEntityTypeDescriptor as s, AuthoringArgRef as t, PslExtensionBlockParamValue as tt, AuthoringEntityTypeTemplateOutput as u, AuthoringPslBlockDescriptor as v, AuthoringTypeNamespace as w, AuthoringTemplateValue as x, AuthoringPslBlockDescriptorNamespace as y, resolveEnumCodecId as z }; | ||
| //# sourceMappingURL=framework-authoring-DEadmUb3.d.mts.map |
| {"version":3,"file":"framework-authoring-DEadmUb3.d.mts","names":[],"sources":["../src/shared/psl-extension-block.ts","../src/shared/framework-authoring.ts"],"mappings":"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"} |
| import { f as AnyCodecDescriptor } from "./codec-types-e32YHT3D.mjs"; | ||
| import { i as AuthoringContributions } from "./framework-authoring-DEadmUb3.mjs"; | ||
| import { t as TypesImportSpec } from "./types-import-spec-DRKzrJ20.mjs"; | ||
| import { ColumnDefault, ExecutionMutationDefaultPhases, ExecutionMutationDefaultValue } from "@prisma-next/contract/types"; | ||
| //#region src/shared/mutation-default-types.d.ts | ||
| interface SourcePosition { | ||
| readonly offset: number; | ||
| readonly line: number; | ||
| readonly column: number; | ||
| } | ||
| interface SourceSpan { | ||
| readonly start: SourcePosition; | ||
| readonly end: SourcePosition; | ||
| } | ||
| interface SourceDiagnostic { | ||
| readonly code: string; | ||
| readonly message: string; | ||
| readonly sourceId?: string; | ||
| readonly span?: SourceSpan; | ||
| readonly data?: Readonly<Record<string, unknown>>; | ||
| } | ||
| interface DefaultFunctionLoweringContext { | ||
| readonly sourceId: string; | ||
| readonly modelName: string; | ||
| readonly fieldName: string; | ||
| readonly columnCodecId?: string; | ||
| } | ||
| type LoweredDefaultValue = { | ||
| readonly kind: 'storage'; | ||
| readonly defaultValue: ColumnDefault; | ||
| } | { | ||
| readonly kind: 'execution'; | ||
| readonly generated: ExecutionMutationDefaultValue; | ||
| }; | ||
| type LoweredDefaultResult = { | ||
| readonly ok: true; | ||
| readonly value: LoweredDefaultValue; | ||
| } | { | ||
| readonly ok: false; | ||
| readonly diagnostic: SourceDiagnostic; | ||
| }; | ||
| interface MutationDefaultGeneratorDescriptor { | ||
| readonly id: string; | ||
| /** | ||
| * Codec ids the generator is compatible with when the codec choice | ||
| * and the generator choice are made independently by the contract | ||
| * author. Set when the registry-coherence check is meaningful | ||
| * (the codec and the generator can be paired arbitrarily by the | ||
| * caller); omitted when the generator is only reachable through a | ||
| * descriptor that co-registers a fixed codec, so coherence is | ||
| * structural and the list would be tautological. | ||
| */ | ||
| readonly applicableCodecIds?: readonly string[]; | ||
| readonly resolveGeneratedColumnDescriptor?: (input: { | ||
| readonly generated: ExecutionMutationDefaultValue; | ||
| }) => { | ||
| readonly codecId: string; | ||
| readonly nativeType: string; | ||
| readonly typeRef?: string; | ||
| readonly typeParams?: Record<string, unknown>; | ||
| } | undefined; | ||
| /** | ||
| * Construct the `onCreate`/`onUpdate` phases value owned by this | ||
| * generator. Authoring layers (PSL `temporal.updatedAt()`, TS field presets) call | ||
| * this instead of building the literal inline so PSL/TS-authored | ||
| * contracts stay byte-equivalent for any future params-bearing generator. | ||
| */ | ||
| readonly buildPhases?: (args?: Record<string, unknown>) => ExecutionMutationDefaultPhases; | ||
| } | ||
| interface TypedDefaultFunctionCall { | ||
| readonly fn: string; | ||
| readonly span: SourceSpan; | ||
| readonly args: Readonly<Record<string, unknown>>; | ||
| } | ||
| interface ControlMutationDefaultEntry { | ||
| readonly signature?: unknown; | ||
| readonly lower: (input: { | ||
| readonly call: TypedDefaultFunctionCall; | ||
| readonly context: DefaultFunctionLoweringContext; | ||
| }) => LoweredDefaultResult; | ||
| readonly usageSignatures?: readonly string[]; | ||
| } | ||
| type ControlMutationDefaultRegistry = ReadonlyMap<string, ControlMutationDefaultEntry>; | ||
| interface ControlMutationDefaults { | ||
| readonly defaultFunctionRegistry: ControlMutationDefaultRegistry; | ||
| readonly generatorDescriptors: readonly MutationDefaultGeneratorDescriptor[]; | ||
| } | ||
| //#endregion | ||
| //#region src/shared/framework-components.d.ts | ||
| /** | ||
| * Declarative fields that describe component metadata. | ||
| */ | ||
| interface ComponentMetadata { | ||
| /** Component version (semver) */ | ||
| readonly version: string; | ||
| /** | ||
| * Capabilities this component provides. | ||
| * | ||
| * For adapters, capabilities must be declared on the adapter descriptor (so they are emitted into the contract) and also exposed in runtime adapter code (e.g. `adapter.profile.capabilities`); keep these declarations in sync. Targets are identifiers/descriptors and typically do not declare capabilities. | ||
| */ | ||
| readonly capabilities?: Record<string, unknown>; | ||
| /** Type imports for contract.d.ts generation */ | ||
| readonly types?: { | ||
| readonly codecTypes?: { | ||
| /** | ||
| * Base codec types import spec. Optional: adapters typically provide this, extensions usually don't. | ||
| */ | ||
| readonly import?: TypesImportSpec; | ||
| /** | ||
| * Additional type-only imports for parameterized codec branded types. | ||
| * | ||
| * These imports are included in generated `contract.d.ts` but are NOT treated as codec type maps (i.e., they should not be intersected into `export type CodecTypes = ...`). | ||
| * | ||
| * Example: `Vector<N>` for pgvector codecs that emit `Vector<1536>` | ||
| */ | ||
| readonly typeImports?: ReadonlyArray<TypesImportSpec>; | ||
| /** | ||
| * Optional control-plane hooks keyed by codecId. Used by family-specific planners/verifiers to handle storage types. | ||
| */ | ||
| readonly controlPlaneHooks?: Record<string, unknown>; | ||
| /** | ||
| * Codec descriptors contributed by this component. Source of truth for codec-id-keyed metadata (`traits`, `targetTypes`, `meta`, `renderOutputType`) consumed by `extractCodecLookup`, and used to materialize representative `Codec` instances for codec-dispatched type rendering during emission. | ||
| */ | ||
| readonly codecDescriptors?: ReadonlyArray<AnyCodecDescriptor>; | ||
| }; | ||
| readonly queryOperationTypes?: { | ||
| readonly import: TypesImportSpec; | ||
| }; | ||
| readonly storage?: ReadonlyArray<{ | ||
| readonly typeId: string; | ||
| readonly familyId: string; | ||
| readonly targetId: string; | ||
| readonly nativeType?: string; | ||
| }>; | ||
| }; | ||
| /** | ||
| * Optional pure-data authoring contributions exposed by this component. | ||
| * | ||
| * These contributions are safe to include on pack refs and descriptors because they contain only declarative metadata. Higher-level authoring packages may project them into concrete helper functions for TS-first workflows. | ||
| */ | ||
| readonly authoring?: AuthoringContributions; | ||
| /** | ||
| * Scalar type name to codec ID mapping contributed by this component. Assembled by `createControlStack` with duplicate detection. | ||
| */ | ||
| readonly scalarTypeDescriptors?: ReadonlyMap<string, string>; | ||
| /** | ||
| * Mutation default function handlers and generator descriptors contributed by this component. Assembled by `createControlStack` with duplicate detection. | ||
| */ | ||
| readonly controlMutationDefaults?: ControlMutationDefaults; | ||
| } | ||
| /** | ||
| * Base descriptor for any framework component. | ||
| * | ||
| * All component descriptors share these fundamental properties that identify the component and provide its metadata. This interface is extended by specific descriptor types (FamilyDescriptor, TargetDescriptor, etc.). | ||
| * | ||
| * @template Kind - Discriminator literal identifying the component type. Built-in kinds are 'family', 'target', 'adapter', 'driver', 'extension', but the type accepts any string to allow ecosystem extensions. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * // All descriptors have these properties | ||
| * descriptor.kind // The Kind type parameter (e.g., 'family', 'target', or custom kinds) | ||
| * descriptor.id // Unique string identifier (e.g., 'sql', 'postgres') | ||
| * descriptor.version // Component version (semver) | ||
| * ``` | ||
| */ | ||
| interface ComponentDescriptor<Kind extends string> extends ComponentMetadata { | ||
| /** Discriminator identifying the component type */ | ||
| readonly kind: Kind; | ||
| /** Unique identifier for this component (e.g., 'sql', 'postgres', 'pgvector') */ | ||
| readonly id: string; | ||
| } | ||
| interface ContractComponentRequirementsCheckInput { | ||
| readonly contract: { | ||
| readonly target: string; | ||
| readonly targetFamily?: string | undefined; | ||
| readonly extensionPacks?: Record<string, unknown> | undefined; | ||
| }; | ||
| readonly expectedTargetFamily?: string | undefined; | ||
| readonly expectedTargetId?: string | undefined; | ||
| readonly providedComponentIds: Iterable<string>; | ||
| } | ||
| interface ContractComponentRequirementsCheckResult { | ||
| readonly familyMismatch?: { | ||
| readonly expected: string; | ||
| readonly actual: string; | ||
| } | undefined; | ||
| readonly targetMismatch?: { | ||
| readonly expected: string; | ||
| readonly actual: string; | ||
| } | undefined; | ||
| readonly missingExtensionPackIds: readonly string[]; | ||
| } | ||
| declare function checkContractComponentRequirements(input: ContractComponentRequirementsCheckInput): ContractComponentRequirementsCheckResult; | ||
| /** | ||
| * Descriptor for a family component. | ||
| * | ||
| * A "family" represents a category of data sources with shared semantics (e.g., SQL databases, document stores). Families define: | ||
| * - Query semantics and operations (SELECT, INSERT, find, aggregate, etc.) | ||
| * - Contract structure (tables vs collections, columns vs fields) | ||
| * - Type system and codecs | ||
| * | ||
| * Families are the top-level grouping. Each family contains multiple targets (e.g., SQL family contains Postgres, MySQL, SQLite targets). | ||
| * | ||
| * Extended by plane-specific descriptors: | ||
| * - `ControlFamilyDescriptor` - adds `emission` for CLI/tooling operations | ||
| * - `RuntimeFamilyDescriptor` - adds runtime-specific factory methods | ||
| * | ||
| * @template TFamilyId - Literal type for the family identifier (e.g., 'sql', 'document') | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import sql from '@prisma-next/family-sql/control'; | ||
| * | ||
| * sql.kind // 'family' | ||
| * sql.familyId // 'sql' | ||
| * sql.id // 'sql' | ||
| * ``` | ||
| */ | ||
| interface FamilyDescriptor<TFamilyId extends string> extends ComponentDescriptor<'family'> { | ||
| /** The family identifier (e.g., 'sql', 'document') */ | ||
| readonly familyId: TFamilyId; | ||
| } | ||
| /** | ||
| * Descriptor for a target component. | ||
| * | ||
| * A "target" represents a specific database or data store within a family (e.g., Postgres, MySQL, MongoDB). Targets define: | ||
| * - Native type mappings (e.g., Postgres int4 → TypeScript number) | ||
| * - Target-specific capabilities (e.g., RETURNING, LATERAL joins) | ||
| * | ||
| * Targets are bound to a family and provide the target-specific implementation details that adapters and drivers use. | ||
| * | ||
| * Extended by plane-specific descriptors: | ||
| * - `ControlTargetDescriptor` - adds optional `migrations` capability | ||
| * - `RuntimeTargetDescriptor` - adds runtime factory method | ||
| * | ||
| * @template TFamilyId - Literal type for the family identifier | ||
| * @template TTargetId - Literal type for the target identifier (e.g., 'postgres', 'mysql') | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import postgres from '@prisma-next/target-postgres/control'; | ||
| * | ||
| * postgres.kind // 'target' | ||
| * postgres.familyId // 'sql' | ||
| * postgres.targetId // 'postgres' | ||
| * ``` | ||
| */ | ||
| interface TargetDescriptor<TFamilyId extends string, TTargetId extends string> extends ComponentDescriptor<'target'> { | ||
| /** The family this target belongs to */ | ||
| readonly familyId: TFamilyId; | ||
| /** The target identifier (e.g., 'postgres', 'mysql', 'mongodb') */ | ||
| readonly targetId: TTargetId; | ||
| } | ||
| /** | ||
| * Base shape for any pack reference. Pack refs are pure JSON-friendly objects safe to import in authoring flows. | ||
| */ | ||
| interface PackRefBase<Kind extends string, TFamilyId extends string> extends ComponentMetadata { | ||
| readonly kind: Kind; | ||
| readonly id: string; | ||
| readonly familyId: TFamilyId; | ||
| readonly targetId?: string; | ||
| readonly authoring?: AuthoringContributions; | ||
| } | ||
| type FamilyPackRef<TFamilyId extends string = string> = PackRefBase<'family', TFamilyId>; | ||
| type TargetPackRef<TFamilyId extends string = string, TTargetId extends string = string> = PackRefBase<'target', TFamilyId> & { | ||
| readonly targetId: TTargetId; /** The namespace a bare (un-namespaced) entity name resolves to for this target (e.g. Postgres `'public'`). */ | ||
| readonly defaultNamespaceId: string; | ||
| }; | ||
| type AdapterPackRef<TFamilyId extends string = string, TTargetId extends string = string> = PackRefBase<'adapter', TFamilyId> & { | ||
| readonly targetId: TTargetId; | ||
| }; | ||
| type ExtensionPackRef<TFamilyId extends string = string, TTargetId extends string = string> = PackRefBase<'extension', TFamilyId> & { | ||
| readonly targetId: TTargetId; | ||
| }; | ||
| type DriverPackRef<TFamilyId extends string = string, TTargetId extends string = string> = PackRefBase<'driver', TFamilyId> & { | ||
| readonly targetId: TTargetId; | ||
| }; | ||
| /** | ||
| * Descriptor for an adapter component. | ||
| * | ||
| * An "adapter" provides the protocol and dialect implementation for a target. Adapters handle: | ||
| * - SQL/query generation (lowering AST to target-specific syntax) | ||
| * - Codec registration (encoding/decoding between JS and wire types) | ||
| * - Type mappings and coercions | ||
| * | ||
| * Adapters are bound to a specific family+target combination and work with any compatible driver for that target. | ||
| * | ||
| * Extended by plane-specific descriptors: | ||
| * - `ControlAdapterDescriptor` - control-plane factory | ||
| * - `RuntimeAdapterDescriptor` - runtime factory | ||
| * | ||
| * @template TFamilyId - Literal type for the family identifier | ||
| * @template TTargetId - Literal type for the target identifier | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import postgresAdapter from '@prisma-next/adapter-postgres/control'; | ||
| * | ||
| * postgresAdapter.kind // 'adapter' | ||
| * postgresAdapter.familyId // 'sql' | ||
| * postgresAdapter.targetId // 'postgres' | ||
| * ``` | ||
| */ | ||
| interface AdapterDescriptor<TFamilyId extends string, TTargetId extends string> extends ComponentDescriptor<'adapter'> { | ||
| /** The family this adapter belongs to */ | ||
| readonly familyId: TFamilyId; | ||
| /** The target this adapter is designed for */ | ||
| readonly targetId: TTargetId; | ||
| } | ||
| /** | ||
| * Descriptor for a driver component. | ||
| * | ||
| * A "driver" provides the connection and execution layer for a target. Drivers handle: | ||
| * - Connection management (pooling, timeouts, retries) | ||
| * - Query execution (sending SQL/commands, receiving results) | ||
| * - Transaction management | ||
| * - Wire protocol communication | ||
| * | ||
| * Drivers are bound to a specific family+target and work with any compatible adapter. Multiple drivers can exist for the same target (e.g., node-postgres vs postgres.js for Postgres). | ||
| * | ||
| * Extended by plane-specific descriptors: | ||
| * - `ControlDriverDescriptor` - creates driver from connection URL | ||
| * - `RuntimeDriverDescriptor` - creates driver with runtime options | ||
| * | ||
| * @template TFamilyId - Literal type for the family identifier | ||
| * @template TTargetId - Literal type for the target identifier | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import postgresDriver from '@prisma-next/driver-postgres/control'; | ||
| * | ||
| * postgresDriver.kind // 'driver' | ||
| * postgresDriver.familyId // 'sql' | ||
| * postgresDriver.targetId // 'postgres' | ||
| * ``` | ||
| */ | ||
| interface DriverDescriptor<TFamilyId extends string, TTargetId extends string> extends ComponentDescriptor<'driver'> { | ||
| /** The family this driver belongs to */ | ||
| readonly familyId: TFamilyId; | ||
| /** The target this driver connects to */ | ||
| readonly targetId: TTargetId; | ||
| } | ||
| /** | ||
| * Descriptor for an extension component. | ||
| * | ||
| * An "extension" adds optional capabilities to a target. Extensions can provide: | ||
| * - Additional operations (e.g., vector similarity search with pgvector) | ||
| * - Custom types and codecs (e.g., vector type) | ||
| * - Extended query capabilities | ||
| * | ||
| * Extensions are bound to a specific family+target and are registered in the config alongside the core components. Multiple extensions can be used together. | ||
| * | ||
| * Extended by plane-specific descriptors: | ||
| * - `ControlExtensionDescriptor` - control-plane extension factory | ||
| * - `RuntimeExtensionDescriptor` - runtime extension factory | ||
| * | ||
| * @template TFamilyId - Literal type for the family identifier | ||
| * @template TTargetId - Literal type for the target identifier | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import pgvector from '@prisma-next/extension-pgvector/control'; | ||
| * | ||
| * pgvector.kind // 'extension' | ||
| * pgvector.familyId // 'sql' | ||
| * pgvector.targetId // 'postgres' | ||
| * ``` | ||
| */ | ||
| interface ExtensionDescriptor<TFamilyId extends string, TTargetId extends string> extends ComponentDescriptor<'extension'> { | ||
| /** The family this extension belongs to */ | ||
| readonly familyId: TFamilyId; | ||
| /** The target this extension is designed for */ | ||
| readonly targetId: TTargetId; | ||
| } | ||
| /** Components bound to a specific family+target combination. */ | ||
| type TargetBoundComponentDescriptor<TFamilyId extends string, TTargetId extends string> = TargetDescriptor<TFamilyId, TTargetId> | AdapterDescriptor<TFamilyId, TTargetId> | DriverDescriptor<TFamilyId, TTargetId> | ExtensionDescriptor<TFamilyId, TTargetId>; | ||
| interface FamilyInstance<TFamilyId extends string> { | ||
| readonly familyId: TFamilyId; | ||
| } | ||
| interface TargetInstance<TFamilyId extends string, TTargetId extends string> { | ||
| readonly familyId: TFamilyId; | ||
| readonly targetId: TTargetId; | ||
| } | ||
| interface AdapterInstance<TFamilyId extends string, TTargetId extends string> { | ||
| readonly familyId: TFamilyId; | ||
| readonly targetId: TTargetId; | ||
| } | ||
| interface DriverInstance<TFamilyId extends string, TTargetId extends string> { | ||
| readonly familyId: TFamilyId; | ||
| readonly targetId: TTargetId; | ||
| } | ||
| interface ExtensionInstance<TFamilyId extends string, TTargetId extends string> { | ||
| readonly familyId: TFamilyId; | ||
| readonly targetId: TTargetId; | ||
| } | ||
| //#endregion | ||
| export { SourceDiagnostic as A, ControlMutationDefaultEntry as C, LoweredDefaultResult as D, DefaultFunctionLoweringContext as E, TypedDefaultFunctionCall as M, LoweredDefaultValue as O, checkContractComponentRequirements as S, ControlMutationDefaults as T, PackRefBase as _, ComponentMetadata as a, TargetInstance as b, DriverDescriptor as c, ExtensionDescriptor as d, ExtensionInstance as f, FamilyPackRef as g, FamilyInstance as h, ComponentDescriptor as i, SourceSpan as j, MutationDefaultGeneratorDescriptor as k, DriverInstance as l, FamilyDescriptor as m, AdapterInstance as n, ContractComponentRequirementsCheckInput as o, ExtensionPackRef as p, AdapterPackRef as r, ContractComponentRequirementsCheckResult as s, AdapterDescriptor as t, DriverPackRef as u, TargetBoundComponentDescriptor as v, ControlMutationDefaultRegistry as w, TargetPackRef as x, TargetDescriptor as y }; | ||
| //# sourceMappingURL=framework-components-D1rRo9Oa.d.mts.map |
| {"version":3,"file":"framework-components-D1rRo9Oa.d.mts","names":[],"sources":["../src/shared/mutation-default-types.ts","../src/shared/framework-components.ts"],"mappings":"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"} |
| import { r as CodecLookup } from "./codec-types-e32YHT3D.mjs"; | ||
| import { K as PslDiagnosticCode, q as PslExtensionBlock, rt as PslSpan, y as AuthoringPslBlockDescriptorNamespace } from "./framework-authoring-DEadmUb3.mjs"; | ||
| //#region src/control/psl-ast.d.ts | ||
| interface PslDiagnostic { | ||
| readonly code: PslDiagnosticCode; | ||
| readonly message: string; | ||
| readonly sourceId: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslDefaultFunctionValue { | ||
| readonly kind: 'function'; | ||
| readonly name: 'autoincrement' | 'now'; | ||
| } | ||
| interface PslDefaultLiteralValue { | ||
| readonly kind: 'literal'; | ||
| readonly value: string | number | boolean; | ||
| } | ||
| type PslDefaultValue = PslDefaultFunctionValue | PslDefaultLiteralValue; | ||
| type PslAttributeTarget = 'field' | 'model' | 'enum' | 'namedType'; | ||
| interface PslAttributePositionalArgument { | ||
| readonly kind: 'positional'; | ||
| readonly value: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslAttributeNamedArgument { | ||
| readonly kind: 'named'; | ||
| readonly name: string; | ||
| readonly value: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| type PslAttributeArgument = PslAttributePositionalArgument | PslAttributeNamedArgument; | ||
| interface PslTypeConstructorCall { | ||
| readonly kind: 'typeConstructor'; | ||
| readonly path: readonly string[]; | ||
| readonly args: readonly PslAttributeArgument[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslAttribute { | ||
| readonly kind: 'attribute'; | ||
| readonly target: PslAttributeTarget; | ||
| readonly name: string; | ||
| readonly args: readonly PslAttributeArgument[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| type PslReferentialAction = string; | ||
| type PslFieldAttribute = PslAttribute; | ||
| interface PslField { | ||
| readonly kind: 'field'; | ||
| readonly name: string; | ||
| /** Unqualified type name, e.g. `"User"` for both `User`, `auth.User`, and `supabase:auth.User`. */ | ||
| readonly typeName: string; | ||
| /** Namespace qualifier from a dot-qualified type reference, e.g. `"auth"` for `auth.User` or `supabase:auth.User`. Absent for unqualified types. */ | ||
| readonly typeNamespaceId?: string; | ||
| /** | ||
| * Contract-space qualifier from a colon-prefix type reference, e.g. `"supabase"` for | ||
| * `supabase:auth.User` or `supabase:User`. Absent for local (same-space) type references. | ||
| * | ||
| * When present, the field references a model from a different contract space. The namespace | ||
| * (`typeNamespaceId`) and model name (`typeName`) identify the target within that space. | ||
| * Physical table resolution against the extension contract is deferred to the aggregate stage (M3). | ||
| */ | ||
| readonly typeContractSpaceId?: string; | ||
| readonly typeConstructor?: PslTypeConstructorCall; | ||
| readonly optional: boolean; | ||
| readonly list: boolean; | ||
| readonly typeRef?: string; | ||
| readonly attributes: readonly PslFieldAttribute[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslUniqueConstraint { | ||
| readonly kind: 'unique'; | ||
| readonly fields: readonly string[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslIndexConstraint { | ||
| readonly kind: 'index'; | ||
| readonly fields: readonly string[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| type PslModelAttribute = PslAttribute; | ||
| interface PslModel { | ||
| readonly kind: 'model'; | ||
| readonly name: string; | ||
| readonly fields: readonly PslField[]; | ||
| readonly attributes: readonly PslModelAttribute[]; | ||
| readonly span: PslSpan; | ||
| /** | ||
| * Optional leading comment line emitted above the `model` keyword by the | ||
| * printer. Producers (e.g. `sqlSchemaIrToPslAst`) attach introspection | ||
| * advisories such as "// WARNING: This table has no primary key in the | ||
| * database" here. The parser leaves this field unset; round-tripping a | ||
| * parsed schema does not re-attach comments. | ||
| */ | ||
| readonly comment?: string; | ||
| } | ||
| /** | ||
| * A reusable group of fields embedded in a model (a `type Name { … }` block) — | ||
| * e.g. a MongoDB embedded document or a Postgres composite type. Unlike | ||
| * {@link PslModel} it has no storage or identity of its own. | ||
| */ | ||
| interface PslCompositeType { | ||
| readonly kind: 'compositeType'; | ||
| readonly name: string; | ||
| readonly fields: readonly PslField[]; | ||
| readonly attributes: readonly PslAttribute[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslNamedTypeDeclaration { | ||
| readonly kind: 'namedType'; | ||
| readonly name: string; | ||
| /** | ||
| * Parser invariant: exactly one of `baseType` and `typeConstructor` is set. | ||
| * Expressing this as a discriminated union trips TypeScript narrowing when | ||
| * the declaration flows through helpers that accept the full union. | ||
| */ | ||
| readonly baseType?: string; | ||
| readonly typeConstructor?: PslTypeConstructorCall; | ||
| readonly attributes: readonly PslAttribute[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslTypesBlock { | ||
| readonly kind: 'types'; | ||
| readonly declarations: readonly PslNamedTypeDeclaration[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** | ||
| * Name of the synthesised namespace bucket the framework parser uses for | ||
| * top-level declarations that appear outside any `namespace { … }` block. | ||
| * The double-underscore decoration signals that the identifier is parser- | ||
| * synthesised and never appears in user-authored PSL source — writing | ||
| * `namespace __unspecified__ { … }` is a parse error. | ||
| * | ||
| * Distinct from the IR sentinel `__unbound__`: the PSL bucket describes | ||
| * syntactic absence at the parser layer; the IR sentinel describes a late- | ||
| * bound storage slot at the IR layer. Per-target interpreters decide how | ||
| * (or whether) to map the PSL bucket to the IR sentinel. | ||
| */ | ||
| declare const UNSPECIFIED_PSL_NAMESPACE_ID = "__unspecified__"; | ||
| /** A value in {@link PslNamespace.entries}: a built-in entity node or an extension-contributed {@link PslExtensionBlock}. */ | ||
| type PslNamespaceEntry = PslModel | PslCompositeType | PslExtensionBlock; | ||
| /** | ||
| * A namespace block, or the parser's synthesised `__unspecified__` bucket for | ||
| * declarations outside any `namespace { … }`. Same-name blocks reopen-merge; | ||
| * `span` points at the first opening. | ||
| * | ||
| * Entities are stored canonically (ADR 224) in `entries[kind][name]`, where | ||
| * `kind` is the PSL keyword for built-ins or the block discriminator for | ||
| * extension kinds, e.g. `entries['policy']['ReadPosts']` (the discriminator, | ||
| * not the PSL keyword — a `policy_select` block lands under `'policy'` per | ||
| * ADR 225). | ||
| */ | ||
| interface PslNamespace { | ||
| readonly kind: 'namespace'; | ||
| readonly name: string; | ||
| /** Canonical store: a frozen container of frozen per-kind maps. The accessors below derive from it. */ | ||
| readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>; | ||
| /** Built-in models, from `entries['model']`. Extension kinds: {@link namespacePslExtensionBlocks}. */ | ||
| readonly models: readonly PslModel[]; | ||
| /** Built-in composite types, from `entries['compositeType']`. */ | ||
| readonly compositeTypes: readonly PslCompositeType[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** Constructs a {@link PslNamespace}. Use this, never a namespace literal — the accessors must derive from `entries`. */ | ||
| declare function makePslNamespace(init: { | ||
| readonly kind: 'namespace'; | ||
| readonly name: string; | ||
| readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>; | ||
| readonly span: PslSpan; | ||
| }): PslNamespace; | ||
| /** | ||
| * Builds the frozen `entries[kind][name]` container from per-kind arrays. | ||
| * Built-ins key on their PSL keyword; extension blocks key on their `kind` | ||
| * discriminator. Call this rather than hand-building the literal. | ||
| */ | ||
| declare function makePslNamespaceEntries(models: readonly PslModel[], compositeTypes: readonly PslCompositeType[], extensionBlocks: readonly PslExtensionBlock[]): Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>; | ||
| interface PslDocumentAst { | ||
| readonly kind: 'document'; | ||
| readonly sourceId: string; | ||
| readonly namespaces: readonly PslNamespace[]; | ||
| readonly types?: PslTypesBlock; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** | ||
| * Returns all models from every namespace in document order. Convenience | ||
| * for consumers that don't (yet) need namespace-awareness. | ||
| */ | ||
| declare function flatPslModels(ast: PslDocumentAst): readonly PslModel[]; | ||
| /** | ||
| * Returns all composite types from every namespace in document order. | ||
| */ | ||
| declare function flatPslCompositeTypes(ast: PslDocumentAst): readonly PslCompositeType[]; | ||
| /** | ||
| * The set of `entries` kind keys that the framework parser reserves for | ||
| * built-in PSL entity kinds. Any own-enumerable key on `PslNamespace.entries` | ||
| * that is **not** in this set was contributed by an extension-block descriptor. | ||
| * | ||
| * Built-in keys match the PSL keyword used on each block type: | ||
| * `'model'`, `'compositeType'`. The `'enum'` keyword is claimed by the | ||
| * extension-block grammar via a registered descriptor, so `entries['enum']` | ||
| * holds `PslExtensionBlock` nodes and is returned by `namespacePslExtensionBlocks`. | ||
| */ | ||
| declare const BUILTIN_PSL_KIND_KEYS: ReadonlySet<string>; | ||
| /** | ||
| * Returns all extension-contributed blocks in the given namespace, in | ||
| * insertion order (the order the parser encountered them in the source). | ||
| * | ||
| * Reads from `namespace.entries`, skipping the built-in kind keys | ||
| * (`'model'`, `'compositeType'`). All remaining kind maps contain | ||
| * only `PslExtensionBlock` nodes by construction (see `makePslNamespaceEntries`). | ||
| */ | ||
| declare function namespacePslExtensionBlocks(ns: PslNamespace): readonly PslExtensionBlock[]; | ||
| interface ParsePslDocumentInput { | ||
| readonly schema: string; | ||
| readonly sourceId: string; | ||
| /** | ||
| * Registry of declarative block descriptors, keyed by arbitrary path | ||
| * segments with {@link AuthoringPslBlockDescriptor} leaves. The registry | ||
| * teaches the parser which top-level keywords belong to extension | ||
| * contributions: when the parser encounters an unknown keyword, it looks | ||
| * it up here and, when found, reads the block generically into a | ||
| * {@link PslExtensionBlock} node. Absent or undefined means no extension | ||
| * blocks are registered and any unknown keyword yields | ||
| * `PSL_UNSUPPORTED_TOP_LEVEL_BLOCK`. | ||
| * | ||
| * Contrast with the parsed block nodes themselves, which live in | ||
| * {@link PslNamespace.entries} under their discriminator key (read them with | ||
| * {@link namespacePslExtensionBlocks}); this field holds the registry of | ||
| * descriptors that teach the parser how to read those blocks. | ||
| */ | ||
| readonly pslBlockDescriptors?: AuthoringPslBlockDescriptorNamespace; | ||
| /** | ||
| * Codec lookup for validating `value`-kind extension block parameters. | ||
| * When provided alongside `pslBlockDescriptors`, the generic validator runs | ||
| * over every parsed extension block after the full AST is assembled, | ||
| * appending any diagnostics to the parse result. Absent or undefined means | ||
| * no codec validation runs; `ref` resolution still runs when namespace | ||
| * context is available (built from the assembled namespaces). | ||
| */ | ||
| readonly codecLookup?: CodecLookup; | ||
| } | ||
| interface ParsePslDocumentResult { | ||
| readonly ast: PslDocumentAst; | ||
| readonly diagnostics: readonly PslDiagnostic[]; | ||
| readonly ok: boolean; | ||
| } | ||
| //#endregion | ||
| export { makePslNamespace as A, PslReferentialAction as C, UNSPECIFIED_PSL_NAMESPACE_ID as D, PslUniqueConstraint as E, namespacePslExtensionBlocks as M, flatPslCompositeTypes as O, PslNamespaceEntry as S, PslTypesBlock as T, PslIndexConstraint as _, PslAttributeArgument as a, PslNamedTypeDeclaration as b, PslAttributeTarget as c, PslDefaultLiteralValue as d, PslDefaultValue as f, PslFieldAttribute as g, PslField as h, PslAttribute as i, makePslNamespaceEntries as j, flatPslModels as k, PslCompositeType as l, PslDocumentAst as m, ParsePslDocumentInput as n, PslAttributeNamedArgument as o, PslDiagnostic as p, ParsePslDocumentResult as r, PslAttributePositionalArgument as s, BUILTIN_PSL_KIND_KEYS as t, PslDefaultFunctionValue as u, PslModel as v, PslTypeConstructorCall as w, PslNamespace as x, PslModelAttribute as y }; | ||
| //# sourceMappingURL=psl-ast-jgAyMeUx.d.mts.map |
| {"version":3,"file":"psl-ast-jgAyMeUx.d.mts","names":[],"sources":["../src/control/psl-ast.ts"],"mappings":"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"} |
| import type { SchemaDiffIssue } from './schema-diff'; | ||
| export const VERIFY_CODE_MARKER_MISSING = 'PN-RUN-3001'; | ||
| export const VERIFY_CODE_HASH_MISMATCH = 'PN-RUN-3002'; | ||
| export const VERIFY_CODE_TARGET_MISMATCH = 'PN-RUN-3003'; | ||
| export const VERIFY_CODE_SCHEMA_FAILURE = 'PN-RUN-3010'; | ||
| export interface OperationContext { | ||
| readonly contractPath?: string; | ||
| readonly configPath?: string; | ||
| readonly meta?: Readonly<Record<string, unknown>>; | ||
| } | ||
| export interface VerifyDatabaseResult { | ||
| readonly ok: boolean; | ||
| readonly code?: string; | ||
| readonly summary: string; | ||
| readonly contract: { | ||
| readonly storageHash: string; | ||
| readonly profileHash?: string; | ||
| }; | ||
| readonly marker?: { | ||
| readonly storageHash?: string; | ||
| readonly profileHash?: string; | ||
| }; | ||
| readonly target: { | ||
| readonly expected: string; | ||
| readonly actual?: string; | ||
| }; | ||
| readonly missingCodecs?: readonly string[]; | ||
| readonly codecCoverageSkipped?: boolean; | ||
| readonly meta?: { | ||
| readonly configPath?: string; | ||
| readonly contractPath: string; | ||
| }; | ||
| readonly timings: { | ||
| readonly total: number; | ||
| }; | ||
| } | ||
| /** | ||
| * The three ways an actual state can fail an expectation: it contains a node | ||
| * that was not expected, lacks a node that was expected, or holds a node that | ||
| * is not equal to the expected one. Expected is the desired side and actual the | ||
| * current side of whatever comparison produced the issue — contract-vs-database, | ||
| * or contract-vs-contract in an offline plan — so the vocabulary is | ||
| * comparison-relative and never ambiguous about a base. | ||
| * | ||
| * The failure reason is a structural characteristic carried as a declared | ||
| * field: consumers filter on `reason`, never by enumerating kind strings or | ||
| * family-invented node codes. | ||
| */ | ||
| export type ExpectationFailureReason = 'not-expected' | 'not-found' | 'not-equal'; | ||
| /** | ||
| * The issue-based schema-verify result. `ok` derives from the FAILURE list | ||
| * only: a verify passes exactly when `schema.issues` is empty, post | ||
| * strict-gating and control-policy disposition. | ||
| * | ||
| * `schema.warnings` carries warn-graded issues (an `observed`-policy | ||
| * subject's drift, and any other `warn` disposition) in the same shape. | ||
| * Warnings are informational — they never affect `ok` — but they MUST be | ||
| * surfaced: an `observed` table that drifted yields `ok: true` with a | ||
| * non-empty warnings channel, which is what distinguishes "watch without | ||
| * failing" from full suppression. | ||
| */ | ||
| export interface VerifyDatabaseSchemaResult { | ||
| readonly ok: boolean; | ||
| readonly code?: string; | ||
| readonly summary: string; | ||
| readonly contract: { | ||
| readonly storageHash: string; | ||
| readonly profileHash?: string; | ||
| }; | ||
| readonly target: { | ||
| readonly expected: string; | ||
| readonly actual?: string; | ||
| }; | ||
| readonly schema: { | ||
| readonly issues: readonly SchemaDiffIssue[]; | ||
| readonly warnings?: { | ||
| readonly issues: readonly SchemaDiffIssue[]; | ||
| }; | ||
| }; | ||
| readonly meta?: { | ||
| readonly configPath?: string; | ||
| readonly contractPath?: string; | ||
| readonly strict: boolean; | ||
| }; | ||
| readonly timings: { | ||
| readonly total: number; | ||
| }; | ||
| } | ||
| export interface EmitContractResult { | ||
| readonly contractJson: string; | ||
| readonly contractDts: string; | ||
| readonly storageHash: string; | ||
| readonly executionHash?: string; | ||
| readonly profileHash: string; | ||
| } | ||
| export interface IntrospectSchemaResult<TSchemaIR> { | ||
| readonly ok: true; | ||
| readonly summary: string; | ||
| readonly target: { | ||
| readonly familyId: string; | ||
| readonly id: string; | ||
| }; | ||
| readonly schema: TSchemaIR; | ||
| readonly meta?: { | ||
| readonly configPath?: string; | ||
| readonly dbUrl?: string; | ||
| }; | ||
| readonly timings: { | ||
| readonly total: number; | ||
| }; | ||
| } | ||
| export interface SignDatabaseResult { | ||
| readonly ok: boolean; | ||
| readonly summary: string; | ||
| readonly contract: { | ||
| readonly storageHash: string; | ||
| readonly profileHash?: string; | ||
| }; | ||
| readonly target: { | ||
| readonly expected: string; | ||
| readonly actual?: string; | ||
| }; | ||
| readonly marker: { | ||
| readonly created: boolean; | ||
| readonly updated: boolean; | ||
| readonly previous?: { | ||
| readonly storageHash?: string; | ||
| readonly profileHash?: string; | ||
| }; | ||
| }; | ||
| readonly meta?: { | ||
| readonly configPath?: string; | ||
| readonly contractPath: string; | ||
| }; | ||
| readonly timings: { | ||
| readonly total: number; | ||
| }; | ||
| } |
| import type { ExpectationFailureReason } from './control-operation-results'; | ||
| export interface SchemaDiffIssue<TNode extends DiffableNode = DiffableNode> { | ||
| /** Path from the root node down to the diffed node, as a sequence of local keys. */ | ||
| readonly path: readonly string[]; | ||
| /** Why the actual state fails the expectation. Consumers filter on this field. */ | ||
| readonly reason: ExpectationFailureReason; | ||
| /** The expected (desired-side) node, when available. Absent for `not-expected` issues. */ | ||
| readonly expected?: TNode; | ||
| /** The actual (current-side) node, when available. Absent for `not-found` issues. */ | ||
| readonly actual?: TNode; | ||
| } | ||
| /** | ||
| * A node in the schema tree. Every node in the tree implements this interface. | ||
| * | ||
| * The differ pairs siblings by the combination of `nodeKind` and `id`, not by | ||
| * `id` alone: `id` needs only be unique among siblings of the same | ||
| * `nodeKind` at the same level, not globally unique at that level. Two | ||
| * distinct kinds of child in distinct slots (e.g. a role and a namespace) may | ||
| * legitimately share a name — they are never paired against each other, so | ||
| * the collision is harmless. A node never folds its kind into its id string | ||
| * to route around this; `nodeKind` is the discriminant that does that job. | ||
| * A same-`nodeKind`/same-`id` collision among siblings is a genuine | ||
| * duplicate and is enforced by a throw. The differ accumulates ids (not | ||
| * nodeKind) into a path that stamps every emitted issue. | ||
| */ | ||
| export interface DiffableNode { | ||
| readonly id: string; | ||
| readonly nodeKind: string; | ||
| isEqualTo(other: DiffableNode): boolean; | ||
| children(): readonly DiffableNode[]; | ||
| } | ||
| /** Delimiter joining `nodeKind` and `id` into one sibling-map key. Every `nodeKind` is a code-defined literal (kebab-case-style), so a null character can never appear in one. */ | ||
| const SIBLING_KEY_DELIMITER = '\u0000'; | ||
| function siblingKey(node: DiffableNode): string { | ||
| return `${node.nodeKind}${SIBLING_KEY_DELIMITER}${node.id}`; | ||
| } | ||
| function insertNode(map: Map<string, DiffableNode>, node: DiffableNode): void { | ||
| const key = siblingKey(node); | ||
| if (map.has(key)) { | ||
| throw new Error(`diffSchemas: duplicate id among siblings: ${node.nodeKind}/${node.id}`); | ||
| } | ||
| map.set(key, node); | ||
| } | ||
| function emitMissingSubtree(node: DiffableNode, parentPath: readonly string[]): SchemaDiffIssue[] { | ||
| const path = [...parentPath, node.id]; | ||
| return [ | ||
| { | ||
| path, | ||
| reason: 'not-found', | ||
| expected: node, | ||
| }, | ||
| ...node.children().flatMap((c) => emitMissingSubtree(c, path)), | ||
| ]; | ||
| } | ||
| function emitExtraSubtree(node: DiffableNode, parentPath: readonly string[]): SchemaDiffIssue[] { | ||
| const path = [...parentPath, node.id]; | ||
| return [ | ||
| { | ||
| path, | ||
| reason: 'not-expected', | ||
| actual: node, | ||
| }, | ||
| ...node.children().flatMap((c) => emitExtraSubtree(c, path)), | ||
| ]; | ||
| } | ||
| /** | ||
| * Diff two schema trees starting from their roots. | ||
| * | ||
| * The differ is **total**: every node-level difference is reported. An unmatched | ||
| * non-leaf node emits its own issue and descends, emitting an issue for every | ||
| * node in the missing/extra subtree. Coalescing a parent change over its | ||
| * children is the planner's responsibility. Ownership filtering (dropping `extra` | ||
| * issues in namespaces a contract doesn't own) is the caller's responsibility. | ||
| */ | ||
| export function diffSchemas( | ||
| expected: DiffableNode, | ||
| actual: DiffableNode, | ||
| ): readonly SchemaDiffIssue[] { | ||
| return diffPair(expected, actual, []); | ||
| } | ||
| function diffPair( | ||
| expected: DiffableNode, | ||
| actual: DiffableNode, | ||
| parentPath: readonly string[], | ||
| ): readonly SchemaDiffIssue[] { | ||
| const path = [...parentPath, expected.id]; | ||
| const issues: SchemaDiffIssue[] = []; | ||
| if (!expected.isEqualTo(actual)) { | ||
| issues.push({ | ||
| path, | ||
| reason: 'not-equal', | ||
| expected, | ||
| actual, | ||
| }); | ||
| } | ||
| issues.push(...diffChildren(expected.children(), actual.children(), path)); | ||
| return issues; | ||
| } | ||
| /** | ||
| * Align one level of nodes by `(nodeKind, id)`; emit issues in input order | ||
| * and recurse. | ||
| * | ||
| * A missing node emits one issue for itself and one for every node in its | ||
| * subtree (total descent). Same for extra nodes. A matched pair recurses via | ||
| * `diffPair`. | ||
| */ | ||
| function diffChildren( | ||
| expected: readonly DiffableNode[], | ||
| actual: readonly DiffableNode[], | ||
| parentPath: readonly string[], | ||
| ): readonly SchemaDiffIssue[] { | ||
| const expectedMap = new Map<string, DiffableNode>(); | ||
| for (const node of expected) { | ||
| insertNode(expectedMap, node); | ||
| } | ||
| const actualMap = new Map<string, DiffableNode>(); | ||
| for (const node of actual) { | ||
| insertNode(actualMap, node); | ||
| } | ||
| const issues: SchemaDiffIssue[] = []; | ||
| for (const [key, expectedNode] of expectedMap) { | ||
| const actualNode = actualMap.get(key); | ||
| if (actualNode === undefined) { | ||
| issues.push(...emitMissingSubtree(expectedNode, parentPath)); | ||
| } else { | ||
| issues.push(...diffPair(expectedNode, actualNode, parentPath)); | ||
| } | ||
| } | ||
| for (const [key, actualNode] of actualMap) { | ||
| if (!expectedMap.has(key)) { | ||
| issues.push(...emitExtraSubtree(actualNode, parentPath)); | ||
| } | ||
| } | ||
| return issues; | ||
| } | ||
| /** | ||
| * The result of diffing a contract's expected schema against the introspected | ||
| * actual schema: one node-typed issue list. Carries no verdict, verification | ||
| * tree, or counts — those are the verifier's own presentation, built from the | ||
| * same underlying comparison. | ||
| * | ||
| * `TNode` is the concrete schema-IR node the issues carry; it defaults to | ||
| * `DiffableNode`, so this is purely additive — a caller that wants the | ||
| * concrete node opts in (the Postgres planner uses the concrete node type), | ||
| * everyone else keeps the default unchanged. | ||
| */ | ||
| export class SchemaDiff<TNode extends DiffableNode = DiffableNode> { | ||
| readonly issues: readonly SchemaDiffIssue<TNode>[]; | ||
| constructor(issues: readonly SchemaDiffIssue<TNode>[]) { | ||
| this.issues = issues; | ||
| } | ||
| /** Returns a new `SchemaDiff` narrowed to the issues `keep` returns true for. */ | ||
| filter(keep: (issue: SchemaDiffIssue<TNode>) => boolean): SchemaDiff<TNode> { | ||
| return new SchemaDiff(this.issues.filter(keep)); | ||
| } | ||
| } |
| import { blindCast } from '@prisma-next/utils/casts'; | ||
| import { UNBOUND_NAMESPACE_ID } from './namespace'; | ||
| import type { Storage } from './storage'; | ||
| /** | ||
| * Extracts the entries map of a contract's single default namespace | ||
| * (`UNBOUND_NAMESPACE_ID`). Both single-namespace families (Mongo, SQLite) | ||
| * store all entities under this one namespace. | ||
| */ | ||
| export type DefaultNamespaceEntries<TStorage extends { readonly namespaces: object }> = | ||
| TStorage['namespaces'] extends Record<typeof UNBOUND_NAMESPACE_ID, { readonly entries: infer E }> | ||
| ? E | ||
| : never; | ||
| /** | ||
| * Generic single-namespace projection shape — one namespace's entity-kind slots. | ||
| * A family supplies: | ||
| * - `TEntries` — the family's `*NamespaceEntries` type for the namespace. | ||
| * - `TBuiltinKinds` — the union of the family's statically-named built-in kind | ||
| * keys (Mongo `'collection'`; SQL `'table' | 'valueSet'`). | ||
| * | ||
| * Each built-in kind becomes a top-level accessor; the remaining pack-contributed | ||
| * kinds stay under `.entries` (keyed by their registered singular kind string). | ||
| * | ||
| * A built-in kind that the emitted contract does not carry resolves to an empty | ||
| * map (`Record<string, never>`), matching the runtime which always materializes | ||
| * each built-in slot. The `& string` index-signature member of `TEntries` is | ||
| * excluded from `.entries` so only the literal pack-kind keys remain. | ||
| */ | ||
| export type SingleNamespaceView<TEntries, TBuiltinKinds extends string> = { | ||
| readonly [K in TBuiltinKinds]-?: K extends keyof TEntries | ||
| ? NonNullable<TEntries[K]> | ||
| : Record<string, never>; | ||
| } & { | ||
| readonly entries: { | ||
| readonly [K in Exclude<keyof TEntries, TBuiltinKinds | number | symbol> as string extends K | ||
| ? never | ||
| : K]: TEntries[K]; | ||
| }; | ||
| }; | ||
| /** The `entries` shape of one namespace in a storage map. */ | ||
| type EntriesOf<TNamespace> = TNamespace extends { readonly entries: infer E } ? E : never; | ||
| /** | ||
| * The namespace-keyed entity-view map — every storage namespace keyed by its raw | ||
| * id, each projected to its {@link SingleNamespaceView}. Mirrors | ||
| * `NamespacedEnums` from `@prisma-next/contract/enum-accessor`: the migration | ||
| * author's storage-side `view.namespace.<nsId>` is the twin of the runtime's | ||
| * `db.enums.<nsId>`. Nesting the schema map under one fixed `namespace` member | ||
| * makes it collision-proof — a schema named `storage` is `view.namespace.storage`, | ||
| * never a contract-root key. | ||
| */ | ||
| export type NamespacedEntities< | ||
| TStorage extends { readonly namespaces: object }, | ||
| TBuiltinKinds extends string, | ||
| > = { | ||
| readonly [Ns in keyof TStorage['namespaces']]: SingleNamespaceView< | ||
| EntriesOf<TStorage['namespaces'][Ns]>, | ||
| TBuiltinKinds | ||
| >; | ||
| }; | ||
| /** | ||
| * Projects one namespace's `entries` into the view shape: each built-in kind | ||
| * becomes a top-level slot (materialized empty if absent), and the remaining | ||
| * pack-contributed kinds sit under `.entries`. Shared by the single-namespace | ||
| * builder and the namespace-map builder. | ||
| */ | ||
| export function promoteBuiltinKinds<TView>( | ||
| entries: Readonly<Record<string, unknown>>, | ||
| builtinKinds: readonly string[], | ||
| ): TView { | ||
| const view: Record<string, unknown> = {}; | ||
| const rest: Record<string, unknown> = {}; | ||
| for (const [kind, kindMap] of Object.entries(entries)) { | ||
| if (builtinKinds.includes(kind)) { | ||
| view[kind] = kindMap; | ||
| } else { | ||
| rest[kind] = kindMap; | ||
| } | ||
| } | ||
| for (const kind of builtinKinds) { | ||
| if (!(kind in view)) { | ||
| view[kind] = {}; | ||
| } | ||
| } | ||
| view['entries'] = rest; | ||
| return blindCast<TView, 'view is built to the SingleNamespaceView shape the caller parametrizes'>( | ||
| view, | ||
| ); | ||
| } | ||
| /** | ||
| * Builds one namespace's entity view: promotes the given built-in kind slots to | ||
| * top-level for the default (`UNBOUND_NAMESPACE_ID`) namespace. Single-namespace | ||
| * targets (Mongo, SQLite) use this to unwrap their sole namespace to the root. | ||
| * | ||
| * Throws if the contract has no default (`UNBOUND_NAMESPACE_ID`) namespace. | ||
| */ | ||
| export function buildSingleNamespaceView<TView>( | ||
| storage: Storage, | ||
| builtinKinds: readonly string[], | ||
| ): TView { | ||
| const defaultNs = storage.namespaces[UNBOUND_NAMESPACE_ID]; | ||
| if (defaultNs === undefined) { | ||
| throw new Error(`ContractView: contract has no default namespace (${UNBOUND_NAMESPACE_ID})`); | ||
| } | ||
| const entries = blindCast< | ||
| Record<string, unknown>, | ||
| 'Namespace.entries is the open ADR 224 dictionary Record<string, Record<string, unknown>>' | ||
| >(defaultNs.entries); | ||
| return promoteBuiltinKinds<TView>(entries, builtinKinds); | ||
| } | ||
| /** | ||
| * Builds the namespace-keyed entity-view map (`{ <nsId>: SingleNamespaceView }`) | ||
| * for every namespace in the storage, keyed by raw namespace id. Mirrors | ||
| * `buildNamespacedEnums(domain)` — the storage-side twin. | ||
| */ | ||
| export function buildNamespacedEntities<TMap>( | ||
| storage: Storage, | ||
| builtinKinds: readonly string[], | ||
| ): TMap { | ||
| const out: Record<string, unknown> = {}; | ||
| for (const [nsId, ns] of Object.entries(storage.namespaces)) { | ||
| out[nsId] = promoteBuiltinKinds( | ||
| blindCast< | ||
| Readonly<Record<string, unknown>>, | ||
| 'Namespace.entries is the open ADR 224 dictionary Record<string, Record<string, unknown>>' | ||
| >(ns.entries), | ||
| builtinKinds, | ||
| ); | ||
| } | ||
| return blindCast< | ||
| TMap, | ||
| 'each namespace projected to its SingleNamespaceView; keys mirror the storage namespace ids' | ||
| >(out); | ||
| } |
| import type { JsonValue } from '@prisma-next/contract/types'; | ||
| /** | ||
| * Renders a codec-encoded value as a TypeScript literal (e.g. `'low'`, `1`, `true`), or `undefined` | ||
| * when the value isn't literal-expressible (objects, arrays, null). | ||
| * | ||
| * Valid **only for identity codecs** whose `encodeJson` output equals their decoded output type | ||
| * (text, int, float, bool). A non-identity codec (e.g. one that encodes to an int but decodes to a | ||
| * string literal) must NOT use this: it has to `decodeJson` first, then render, in its own | ||
| * `renderValueLiteral`. | ||
| * | ||
| * String values are fully escaped for a single-quoted `.d.ts` literal: backslash, single quote, and | ||
| * every character a raw single-quoted TS literal cannot contain — newline, carriage return, and the | ||
| * U+2028/U+2029 line/paragraph separators (which JS also treats as line terminators). | ||
| */ | ||
| export function renderTsLiteral(value: JsonValue): string | undefined { | ||
| if (typeof value === 'string') { | ||
| const escaped = value | ||
| .replace(/\\/g, '\\\\') | ||
| .replace(/'/g, "\\'") | ||
| .replace(/\n/g, '\\n') | ||
| .replace(/\r/g, '\\r') | ||
| .replace(/\u2028/g, '\\u2028') | ||
| .replace(/\u2029/g, '\\u2029'); | ||
| return `'${escaped}'`; | ||
| } | ||
| if (typeof value === 'number' || typeof value === 'boolean') { | ||
| return String(value); | ||
| } | ||
| return undefined; | ||
| } |
@@ -1,2 +0,2 @@ | ||
| import { A as mergeAuthoringNamespaces, C as instantiateAuthoringFieldPreset, D as isAuthoringFieldPresetDescriptor, E as isAuthoringEntityTypeDescriptor, F as PslBlockParamOption, G as PslExtensionBlockParamRef, I as PslBlockParamRef, K as PslExtensionBlockParamScalarValue, L as PslBlockParamValue, M as validateAuthoringHelperArguments, N as PslBlockParam, O as isAuthoringPslBlockDescriptor, P as PslBlockParamList, S as instantiateAuthoringEntityType, T as isAuthoringArgRef, U as PslExtensionBlockParamList, W as PslExtensionBlockParamOption, _ as AuthoringTemplateValue, a as AuthoringDiagnosticSink, b as assertNoCrossRegistryCollisions, c as AuthoringEntityTypeFactoryOutput, d as AuthoringFieldNamespace, f as AuthoringFieldPresetDescriptor, g as AuthoringStorageTypeTemplate, h as AuthoringPslBlockDescriptorNamespace, i as AuthoringContributions, j as resolveAuthoringTemplateValue, k as isAuthoringTypeConstructorDescriptor, l as AuthoringEntityTypeNamespace, m as AuthoringPslBlockDescriptor, n as AuthoringArgumentDescriptor, o as AuthoringEntityContext, p as AuthoringFieldPresetOutput, q as PslExtensionBlockParamValue, r as AuthoringColumnDefaultTemplate, s as AuthoringEntityTypeDescriptor, t as AuthoringArgRef, u as AuthoringEntityTypeTemplateOutput, v as AuthoringTypeConstructorDescriptor, w as instantiateAuthoringTypeConstructor, x as hasRegisteredFieldNamespace, y as AuthoringTypeNamespace, z as PslExtensionBlock } from "./framework-authoring-CJC4jwGo.mjs"; | ||
| export { type AuthoringArgRef, type AuthoringArgumentDescriptor, type AuthoringColumnDefaultTemplate, type AuthoringContributions, type AuthoringDiagnosticSink, type AuthoringEntityContext, type AuthoringEntityTypeDescriptor, type AuthoringEntityTypeFactoryOutput, type AuthoringEntityTypeNamespace, type AuthoringEntityTypeTemplateOutput, type AuthoringFieldNamespace, type AuthoringFieldPresetDescriptor, type AuthoringFieldPresetOutput, type AuthoringPslBlockDescriptor, type AuthoringPslBlockDescriptorNamespace, type AuthoringStorageTypeTemplate, type AuthoringTemplateValue, type AuthoringTypeConstructorDescriptor, type AuthoringTypeNamespace, type PslBlockParam, type PslBlockParamList, type PslBlockParamOption, type PslBlockParamRef, type PslBlockParamValue, type PslExtensionBlock, type PslExtensionBlockParamList, type PslExtensionBlockParamOption, type PslExtensionBlockParamRef, type PslExtensionBlockParamScalarValue, type PslExtensionBlockParamValue, assertNoCrossRegistryCollisions, hasRegisteredFieldNamespace, instantiateAuthoringEntityType, instantiateAuthoringFieldPreset, instantiateAuthoringTypeConstructor, isAuthoringArgRef, isAuthoringEntityTypeDescriptor, isAuthoringFieldPresetDescriptor, isAuthoringPslBlockDescriptor, isAuthoringTypeConstructorDescriptor, mergeAuthoringNamespaces, resolveAuthoringTemplateValue, validateAuthoringHelperArguments }; | ||
| import { $ as PslExtensionBlockParamRef, A as instantiateAuthoringTypeConstructor, B as validateAuthoringHelperArguments, C as AuthoringTypeConstructorEntityRef, D as hasRegisteredFieldNamespace, E as classifyEnumMemberType, F as isAuthoringPslBlockDescriptor, G as PslBlockParamValue, H as PslBlockParamList, I as isAuthoringTypeConstructorDescriptor, L as mergeAuthoringNamespaces, M as isAuthoringEntityTypeDescriptor, N as isAuthoringFieldPresetDescriptor, O as instantiateAuthoringEntityType, P as isAuthoringModelAttributeDescriptor, Q as PslExtensionBlockParamOption, R as resolveAuthoringTemplateValue, S as AuthoringTypeConstructorDescriptor, T as assertNoCrossRegistryCollisions, U as PslBlockParamOption, V as PslBlockParam, W as PslBlockParamRef, Z as PslExtensionBlockParamList, _ as AuthoringModelAttributeLoweringOutput, a as AuthoringDiagnosticSink, b as AuthoringStorageTypeTemplate, c as AuthoringEntityTypeFactoryOutput, d as AuthoringFieldNamespace, et as PslExtensionBlockParamScalarValue, f as AuthoringFieldPresetDescriptor, g as AuthoringModelAttributeDescriptorNamespace, h as AuthoringModelAttributeDescriptor, i as AuthoringContributions, j as isAuthoringArgRef, k as instantiateAuthoringFieldPreset, l as AuthoringEntityTypeNamespace, m as AuthoringModelAttributeContext, n as AuthoringArgumentDescriptor, o as AuthoringEntityContext, p as AuthoringFieldPresetOutput, q as PslExtensionBlock, r as AuthoringColumnDefaultTemplate, s as AuthoringEntityTypeDescriptor, t as AuthoringArgRef, tt as PslExtensionBlockParamValue, u as AuthoringEntityTypeTemplateOutput, v as AuthoringPslBlockDescriptor, w as AuthoringTypeNamespace, x as AuthoringTemplateValue, y as AuthoringPslBlockDescriptorNamespace, z as resolveEnumCodecId } from "./framework-authoring-DEadmUb3.mjs"; | ||
| export { type AuthoringArgRef, type AuthoringArgumentDescriptor, type AuthoringColumnDefaultTemplate, type AuthoringContributions, type AuthoringDiagnosticSink, type AuthoringEntityContext, type AuthoringEntityTypeDescriptor, type AuthoringEntityTypeFactoryOutput, type AuthoringEntityTypeNamespace, type AuthoringEntityTypeTemplateOutput, type AuthoringFieldNamespace, type AuthoringFieldPresetDescriptor, type AuthoringFieldPresetOutput, type AuthoringModelAttributeContext, type AuthoringModelAttributeDescriptor, type AuthoringModelAttributeDescriptorNamespace, type AuthoringModelAttributeLoweringOutput, type AuthoringPslBlockDescriptor, type AuthoringPslBlockDescriptorNamespace, type AuthoringStorageTypeTemplate, type AuthoringTemplateValue, type AuthoringTypeConstructorDescriptor, type AuthoringTypeConstructorEntityRef, type AuthoringTypeNamespace, type PslBlockParam, type PslBlockParamList, type PslBlockParamOption, type PslBlockParamRef, type PslBlockParamValue, type PslExtensionBlock, type PslExtensionBlockParamList, type PslExtensionBlockParamOption, type PslExtensionBlockParamRef, type PslExtensionBlockParamScalarValue, type PslExtensionBlockParamValue, assertNoCrossRegistryCollisions, classifyEnumMemberType, hasRegisteredFieldNamespace, instantiateAuthoringEntityType, instantiateAuthoringFieldPreset, instantiateAuthoringTypeConstructor, isAuthoringArgRef, isAuthoringEntityTypeDescriptor, isAuthoringFieldPresetDescriptor, isAuthoringModelAttributeDescriptor, isAuthoringPslBlockDescriptor, isAuthoringTypeConstructorDescriptor, mergeAuthoringNamespaces, resolveAuthoringTemplateValue, resolveEnumCodecId, validateAuthoringHelperArguments }; |
@@ -1,2 +0,2 @@ | ||
| import { a as instantiateAuthoringTypeConstructor, c as isAuthoringFieldPresetDescriptor, d as mergeAuthoringNamespaces, f as resolveAuthoringTemplateValue, i as instantiateAuthoringFieldPreset, l as isAuthoringPslBlockDescriptor, n as hasRegisteredFieldNamespace, o as isAuthoringArgRef, p as validateAuthoringHelperArguments, r as instantiateAuthoringEntityType, s as isAuthoringEntityTypeDescriptor, t as assertNoCrossRegistryCollisions, u as isAuthoringTypeConstructorDescriptor } from "./framework-authoring-Dv5F3EFC.mjs"; | ||
| export { assertNoCrossRegistryCollisions, hasRegisteredFieldNamespace, instantiateAuthoringEntityType, instantiateAuthoringFieldPreset, instantiateAuthoringTypeConstructor, isAuthoringArgRef, isAuthoringEntityTypeDescriptor, isAuthoringFieldPresetDescriptor, isAuthoringPslBlockDescriptor, isAuthoringTypeConstructorDescriptor, mergeAuthoringNamespaces, resolveAuthoringTemplateValue, validateAuthoringHelperArguments }; | ||
| import { a as instantiateAuthoringFieldPreset, c as isAuthoringEntityTypeDescriptor, d as isAuthoringPslBlockDescriptor, f as isAuthoringTypeConstructorDescriptor, g as validateAuthoringHelperArguments, h as resolveEnumCodecId, i as instantiateAuthoringEntityType, l as isAuthoringFieldPresetDescriptor, m as resolveAuthoringTemplateValue, n as classifyEnumMemberType, o as instantiateAuthoringTypeConstructor, p as mergeAuthoringNamespaces, r as hasRegisteredFieldNamespace, s as isAuthoringArgRef, t as assertNoCrossRegistryCollisions, u as isAuthoringModelAttributeDescriptor } from "./framework-authoring-Bz_vaNZw.mjs"; | ||
| export { assertNoCrossRegistryCollisions, classifyEnumMemberType, hasRegisteredFieldNamespace, instantiateAuthoringEntityType, instantiateAuthoringFieldPreset, instantiateAuthoringTypeConstructor, isAuthoringArgRef, isAuthoringEntityTypeDescriptor, isAuthoringFieldPresetDescriptor, isAuthoringModelAttributeDescriptor, isAuthoringPslBlockDescriptor, isAuthoringTypeConstructorDescriptor, mergeAuthoringNamespaces, resolveAuthoringTemplateValue, resolveEnumCodecId, validateAuthoringHelperArguments }; |
+41
-2
@@ -1,2 +0,3 @@ | ||
| import { a as CodecRef, c as emptyCodecLookup, d as CodecImpl, f as AnyCodecDescriptor, i as CodecMeta, l as voidParamsSchema, m as CodecDescriptorImpl, n as CodecInstanceContext, o as CodecRegistry, p as CodecDescriptor, r as CodecLookup, s as CodecTrait, t as CodecCallContext, u as Codec } from "./codec-types-yY3eSmi0.mjs"; | ||
| import { a as CodecRef, c as emptyCodecLookup, d as CodecImpl, f as AnyCodecDescriptor, i as CodecMeta, l as voidParamsSchema, m as CodecDescriptorImpl, n as CodecInstanceContext, o as CodecRegistry, p as CodecDescriptor, r as CodecLookup, s as CodecTrait, t as CodecCallContext, u as Codec } from "./codec-types-e32YHT3D.mjs"; | ||
| import { JsonValue, ValueSetRef } from "@prisma-next/contract/types"; | ||
@@ -16,4 +17,26 @@ //#region src/shared/column-spec.d.ts | ||
| readonly typeRef?: string; | ||
| /** | ||
| * Storage-plane value-set ref, set by an authoring path that resolves a | ||
| * field's type against a value-set-deriving entity (e.g. a PSL entity-ref | ||
| * type constructor like `pg.enum(Ref)`, or a TS `enumType` handle). | ||
| * Threaded straight onto the storage node this descriptor builds, where it | ||
| * drives value-set → codec typing. Every codec's own descriptor leaves this | ||
| * unset. | ||
| */ | ||
| readonly valueSet?: ValueSetRef; | ||
| readonly entityRef?: EntityRef; | ||
| }; | ||
| /** | ||
| * Late-resolved pack-entity reference — a field on the type descriptor it is | ||
| * declared on: `entityKind`/`entityName` identify a pack entity whose final | ||
| * placement depends on data not yet known when the descriptor carrying this | ||
| * reference is built — e.g. an owning namespace resolved only once the | ||
| * surrounding structure is assembled. | ||
| */ | ||
| type EntityRef = { | ||
| readonly entityKind: string; | ||
| readonly entityName: string; | ||
| readonly entity: unknown; | ||
| }; | ||
| /** | ||
| * Column spec carrying the codec factory closure alongside the {@link ColumnTypeDescriptor} fields. Codec authors return a `ColumnSpec` from per-codec column helpers; the runtime materializes the codec instance by calling `codecFactory(ctx)` once it knows the column's `CodecInstanceContext`. | ||
@@ -48,2 +71,18 @@ * | ||
| //#endregion | ||
| //#region src/shared/render-ts-literal.d.ts | ||
| /** | ||
| * Renders a codec-encoded value as a TypeScript literal (e.g. `'low'`, `1`, `true`), or `undefined` | ||
| * when the value isn't literal-expressible (objects, arrays, null). | ||
| * | ||
| * Valid **only for identity codecs** whose `encodeJson` output equals their decoded output type | ||
| * (text, int, float, bool). A non-identity codec (e.g. one that encodes to an int but decodes to a | ||
| * string literal) must NOT use this: it has to `decodeJson` first, then render, in its own | ||
| * `renderValueLiteral`. | ||
| * | ||
| * String values are fully escaped for a single-quoted `.d.ts` literal: backslash, single quote, and | ||
| * every character a raw single-quoted TS literal cannot contain — newline, carriage return, and the | ||
| * U+2028/U+2029 line/paragraph separators (which JS also treats as line terminators). | ||
| */ | ||
| declare function renderTsLiteral(value: JsonValue): string | undefined; | ||
| //#endregion | ||
| //#region src/shared/resolve-codec.d.ts | ||
@@ -78,3 +117,3 @@ declare const CONTRACT_CODEC_DESCRIPTOR_MISSING: "CONTRACT.CODEC_DESCRIPTOR_MISSING"; | ||
| //#endregion | ||
| export { type AnyCodecDescriptor, CONTRACT_CODEC_DESCRIPTOR_MISSING, type Codec, type CodecCallContext, type CodecDescriptor, CodecDescriptorImpl, CodecImpl, type CodecInstanceContext, type CodecLookup, type CodecMeta, type CodecRef, type CodecRegistry, type CodecTrait, type ColumnHelperFor, type ColumnHelperForStrict, type ColumnSpec, type ColumnTypeDescriptor, column, emptyCodecLookup, materializeCodec, resolveCodecDescriptorOrThrow, validateCodecTypeParams, voidParamsSchema }; | ||
| export { type AnyCodecDescriptor, CONTRACT_CODEC_DESCRIPTOR_MISSING, type Codec, type CodecCallContext, type CodecDescriptor, CodecDescriptorImpl, CodecImpl, type CodecInstanceContext, type CodecLookup, type CodecMeta, type CodecRef, type CodecRegistry, type CodecTrait, type ColumnHelperFor, type ColumnHelperForStrict, type ColumnSpec, type ColumnTypeDescriptor, column, emptyCodecLookup, materializeCodec, renderTsLiteral, resolveCodecDescriptorOrThrow, validateCodecTypeParams, voidParamsSchema }; | ||
| //# sourceMappingURL=codec.d.mts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"codec.d.mts","names":[],"sources":["../src/shared/column-spec.ts","../src/shared/resolve-codec.ts"],"mappings":";;;;;;;;;AAsBkB;KAJN,oBAAA;EAAA,SACD,OAAA,EAAS,QAAA;EAAA,SACT,UAAA;EAAA,SACA,UAAA,GAAa,MAAM;EAAA,SACnB,OAAA;AAAA;;;;;;UAQM,UAAA,cAAwB,MAAA,uCAC/B,oBAAA;EAAA,SACC,YAAA,GAAe,GAAA,EAAK,oBAAA,KAAyB,CAAA;EAAA,SAC7C,UAAA,EAAY,CAAA;AAAA;;;;;;iBAQP,MAAA,cAAoB,MAAA,+BAClC,YAAA,GAAe,GAAA,EAAK,oBAAA,KAAyB,CAAA,EAC7C,OAAA,UACA,UAAA,EAAY,CAAA,EACZ,UAAA,WACC,UAAA,CAAW,CAAA,EAAG,CAAA;AAbO;AAQxB;;;;AARwB,KA4BZ,eAAA,WAA0B,eAAA,aAEjC,IAAA,YACA,UAAA,UAAoB,kBAAA,CAAmB,CAAA;;;;KAMhC,qBAAA,WAAgC,eAAA,aAEvC,IAAA,YACA,UAAA,CAAW,UAAA,CAAW,UAAA,CAAW,CAAA,eAAgB,kBAAA,CAAmB,CAAA;;;;KAMpE,kBAAA,WAA6B,eAAA,SAChC,UAAA,CAAW,CAAA,wBAAyB,MAAA,oBAChC,UAAA,CAAW,CAAA;;;cC3EJ,iCAAA;;;;;;;iBAQG,6BAAA,CACd,aAAA,GAAgB,OAAA,aAAoB,kBAAA,cACpC,GAAA,EAAK,QAAA,EACL,IAAA,6EACC,kBAAA;;;;;ADIe;AAQlB;;;iBCMgB,uBAAA,CAAwB,UAAA,EAAY,kBAAA,EAAoB,GAAA,EAAK,QAAQ;;;;;;;;;;iBAuCrE,gBAAA,CACd,UAAA,EAAY,kBAAA,EACZ,GAAA,EAAK,QAAA,EACL,GAAA,EAAK,oBAAA,GACJ,KAAA"} | ||
| {"version":3,"file":"codec.d.mts","names":[],"sources":["../src/shared/column-spec.ts","../src/shared/render-ts-literal.ts","../src/shared/resolve-codec.ts"],"mappings":";;;;;;;;;;;KAmBY,oBAAA;EAAA,SACD,OAAA,EAAS,QAAA;EAAA,SACT,UAAA;EAAA,SACA,UAAA,GAAa,MAAA;EAAA,SACb,OAAA;EAUA;;;AAAqB;AAUhC;;;;EAVW,SADA,QAAA,GAAW,WAAA;EAAA,SACX,SAAA,GAAY,SAAA;AAAA;;AAaN;AAQjB;;;;;KAXY,SAAA;EAAA,SACD,UAAA;EAAA,SACA,UAAA;EAAA,SACA,MAAA;AAAA;;;;;;UAQM,UAAA,cAAwB,MAAA,uCAC/B,oBAAA;EAAA,SACC,YAAA,GAAe,GAAA,EAAK,oBAAA,KAAyB,CAAA;EAAA,SAC7C,UAAA,EAAY,CAAA;AAAA;;;AAAC;AAQxB;;iBAAgB,MAAA,cAAoB,MAAA,+BAClC,YAAA,GAAe,GAAA,EAAK,oBAAA,KAAyB,CAAA,EAC7C,OAAA,UACA,UAAA,EAAY,CAAA,EACZ,UAAA,WACC,UAAA,CAAW,CAAA,EAAG,CAAA;;;;;;KAeL,eAAA,WAA0B,eAAA,aAEjC,IAAA,YACA,UAAA,UAAoB,kBAAA,CAAmB,CAAA;;;;KAMhC,qBAAA,WAAgC,eAAA,aAEvC,IAAA,YACA,UAAA,CAAW,UAAA,CAAW,UAAA,CAAW,CAAA,eAAgB,kBAAA,CAAmB,CAAA;;;;KAMpE,kBAAA,WAA6B,eAAA,SAChC,UAAA,CAAW,CAAA,wBAAyB,MAAA,oBAChC,UAAA,CAAW,CAAA;;;;;;AAtFjB;;;;;;;;;;iBCJgB,eAAA,CAAgB,KAAgB,EAAT,SAAS;;;cCTnC,iCAAA;AFab;;;;;;AAAA,iBELgB,6BAAA,CACd,aAAA,GAAgB,OAAA,aAAoB,kBAAA,cACpC,GAAA,EAAK,QAAA,EACL,IAAA,6EACC,kBAAA;;;;;;;;;iBAkBa,uBAAA,CAAwB,UAAA,EAAY,kBAAA,EAAoB,GAAA,EAAK,QAAQ;;;;;;AFHrD;AAUhC;;;iBEgCgB,gBAAA,CACd,UAAA,EAAY,kBAAA,EACZ,GAAA,EAAK,QAAA,EACL,GAAA,EAAK,oBAAA,GACJ,KAAA"} |
+21
-2
@@ -6,3 +6,3 @@ import { i as validateCodecTypeParams, n as materializeCodec, r as resolveCodecDescriptorOrThrow, t as CONTRACT_CODEC_DESCRIPTOR_MISSING } from "./resolve-codec-D8EPZosv.mjs"; | ||
| * | ||
| * Codec authors extend this class with their typed `Id`, `TTraits`, `TWire`, `TInput` and override `encode`/`decode` (and optionally `encodeJson`/`decodeJson`). The runtime instance carries only its `id` (proxied through the descriptor so alias subclasses inherit the descriptor's id automatically) and the conversion methods — static metadata lives on the {@link CodecDescriptor}. | ||
| * Codec authors extend this class with their typed `Id`, `TTraits`, `TWire`, `TInput` and override all four abstract conversion methods: `encode`, `decode`, `encodeJson`, and `decodeJson`. The runtime instance carries only its `id` (proxied through the descriptor so alias subclasses inherit the descriptor's id automatically) and the conversion methods — static metadata lives on the {@link CodecDescriptor}. | ||
| */ | ||
@@ -69,4 +69,23 @@ var CodecImpl = class { | ||
| //#endregion | ||
| export { CONTRACT_CODEC_DESCRIPTOR_MISSING, CodecDescriptorImpl, CodecImpl, column, emptyCodecLookup, materializeCodec, resolveCodecDescriptorOrThrow, validateCodecTypeParams, voidParamsSchema }; | ||
| //#region src/shared/render-ts-literal.ts | ||
| /** | ||
| * Renders a codec-encoded value as a TypeScript literal (e.g. `'low'`, `1`, `true`), or `undefined` | ||
| * when the value isn't literal-expressible (objects, arrays, null). | ||
| * | ||
| * Valid **only for identity codecs** whose `encodeJson` output equals their decoded output type | ||
| * (text, int, float, bool). A non-identity codec (e.g. one that encodes to an int but decodes to a | ||
| * string literal) must NOT use this: it has to `decodeJson` first, then render, in its own | ||
| * `renderValueLiteral`. | ||
| * | ||
| * String values are fully escaped for a single-quoted `.d.ts` literal: backslash, single quote, and | ||
| * every character a raw single-quoted TS literal cannot contain — newline, carriage return, and the | ||
| * U+2028/U+2029 line/paragraph separators (which JS also treats as line terminators). | ||
| */ | ||
| function renderTsLiteral(value) { | ||
| if (typeof value === "string") return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029")}'`; | ||
| if (typeof value === "number" || typeof value === "boolean") return String(value); | ||
| } | ||
| //#endregion | ||
| export { CONTRACT_CODEC_DESCRIPTOR_MISSING, CodecDescriptorImpl, CodecImpl, column, emptyCodecLookup, materializeCodec, renderTsLiteral, resolveCodecDescriptorOrThrow, validateCodecTypeParams, voidParamsSchema }; | ||
| //# sourceMappingURL=codec.mjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"codec.mjs","names":[],"sources":["../src/shared/codec.ts","../src/shared/codec-types.ts","../src/shared/codec-descriptor.ts","../src/shared/column-spec.ts"],"sourcesContent":["/**\n * Codec interface (consumer surface) and abstract `CodecImpl` base (codec-author surface).\n *\n * Consumers depend on the {@link Codec} interface — it describes the runtime instance returned by a descriptor's curried factory and is what the framework threads through emit, validate, and execute paths.\n *\n * Codec authors `extend` the {@link CodecImpl} abstract class to declare a typed runtime codec instance. The class carries a variance-erased descriptor reference (`CodecDescriptor<any>`); `id` proxies through the descriptor so one source of truth governs both metadata reads and aliasing semantics (alias subclasses inherit the descriptor's id automatically).\n *\n * Class generic shape: `Id`, `TTraits`, `TWire`, `TInput`. Method generics on the codec subclass's own surface (e.g. arktype-json's schema generic, pgvector's dimension generic) flow through the subclass's constructor and propagate via the descriptor's typed `factory(params)` return at *direct* call sites.\n */\n\nimport type { JsonValue } from '@prisma-next/contract/types';\nimport type { CodecDescriptor } from './codec-descriptor';\nimport type { CodecCallContext, CodecTrait } from './codec-types';\n\n/**\n * A codec is the contract between an application value and its on-wire and on-contract-disk representations.\n *\n * The author's mental model is two JS-side types — `TInput` (the application JS type) and `TWire` (the database driver wire format) — plus `JsonValue` for build-time contract artifacts. The codec translates `TInput` to `TWire` on writes and back on reads, and to/from `JsonValue` during contract emission and loading.\n *\n * Three representations participate:\n * - **Input** (`TInput`): the JS type at the application boundary.\n * - **Wire** (`TWire`): the format exchanged with the database driver.\n * - **JSON** (`JsonValue`): a JSON-safe form used in contract artifacts.\n *\n * The runtime instance carries only its `id` (the descriptor's `codecId`, set by the factory) and the four conversion methods. Static metadata (`traits`, `targetTypes`, `meta`) and the build-time `renderOutputType` renderer live on the {@link CodecDescriptor} keyed by `codecId` — the read-surface single source of truth. Consumers that need them resolve through `descriptorFor(codecId)`.\n *\n * Codec methods split into two groups:\n *\n * - **Query-time** methods (`encode`, `decode`) run per row/parameter at the IO boundary; they are required and Promise-returning. The per-family codec factory accepts sync or async author functions and lifts sync ones to Promise-shaped methods automatically.\n * - **Build-time** methods (`encodeJson`, `decodeJson`) run when the contract is serialized or loaded. They stay synchronous so contract validation and client construction are synchronous.\n *\n * Target-family codec interfaces extend this base; family-specific concerns (e.g. the SQL `column?` per-call context) layer on through the `CodecCallContext` extension pattern.\n */\nexport interface Codec<\n Id extends string = string,\n TTraits extends readonly CodecTrait[] = readonly CodecTrait[],\n TWire = unknown,\n TInput = unknown,\n> {\n /** Unique codec identifier in `namespace/name@version` format (e.g. `pg/timestamptz@1`). The factory sets this to the descriptor's `codecId`; consumers use it as a back-reference for descriptor lookups and for decode-error diagnostics. */\n readonly id: Id;\n /** Phantom carrier for the `TTraits` generic; type-only, undefined at runtime. Runtime traits live on {@link CodecDescriptor.traits}. Implemented as a string-key phantom (`__codecTraits`) rather than `unique symbol` so bundlers that split `.d.ts` chunks do not strand symbol identity on chunk-private paths (the same `TS2742` family that the public re-export of `CodecTypes` works around). */\n readonly __codecTraits?: TTraits;\n /** Converts a JS value to the wire format expected by the database driver. Always Promise-returning at the boundary. The {@link CodecCallContext} is supplied by the runtime on every call (allocated once per `runtime.execute()`); family layers may narrow the ctx to extend it (e.g. SQL adds `column`). Author-side single-arg `(value) => …` functions remain legal via TypeScript's bivariance for trailing parameters. */\n encode(value: TInput, ctx: CodecCallContext): Promise<TWire>;\n /** Converts a wire value from the database driver into the JS application type. Always Promise-returning at the boundary. The {@link CodecCallContext} is supplied by the runtime on every call (allocated once per `runtime.execute()`); family layers may narrow the ctx to extend it (e.g. SQL adds `column`). Author-side single-arg `(wire) => …` functions remain legal via TypeScript's bivariance for trailing parameters. */\n decode(wire: TWire, ctx: CodecCallContext): Promise<TInput>;\n /** Converts a JS value to a JSON-safe representation for contract serialization. Synchronous; called during contract emission. */\n encodeJson(value: TInput): JsonValue;\n /** Converts a JSON representation back to the JS input type. Synchronous; called during contract loading via `family.deserializeContract`. */\n decodeJson(json: JsonValue): TInput;\n}\n\n/**\n * Abstract base class for concrete codec implementations.\n *\n * Codec authors extend this class with their typed `Id`, `TTraits`, `TWire`, `TInput` and override `encode`/`decode` (and optionally `encodeJson`/`decodeJson`). The runtime instance carries only its `id` (proxied through the descriptor so alias subclasses inherit the descriptor's id automatically) and the conversion methods — static metadata lives on the {@link CodecDescriptor}.\n */\nexport abstract class CodecImpl<\n Id extends string = string,\n TTraits extends readonly CodecTrait[] = readonly CodecTrait[],\n TWire = unknown,\n TInput = unknown,\n> implements Codec<Id, TTraits, TWire, TInput>\n{\n /**\n * Variance-erased descriptor reference. Concrete codec subclasses receive the typed descriptor in their own constructors and forward it via `super(descriptor)`; the variance erasure lives at this base because the abstract surface can't carry the concrete `TParams`.\n */\n // biome-ignore lint/suspicious/noExplicitAny: variance-erased descriptor reference; subclasses retain typed access via their own state\n constructor(public readonly descriptor: CodecDescriptor<any>) {}\n\n get id(): Id {\n return this.descriptor.codecId as Id;\n }\n\n abstract encode(value: TInput, ctx: CodecCallContext): Promise<TWire>;\n abstract decode(wire: TWire, ctx: CodecCallContext): Promise<TInput>;\n abstract encodeJson(value: TInput): JsonValue;\n abstract decodeJson(json: JsonValue): TInput;\n}\n","import type { JsonValue } from '@prisma-next/contract/types';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Codec } from './codec';\n\nexport type CodecTrait = 'equality' | 'order' | 'boolean' | 'numeric' | 'textual';\n\n/**\n * Serializable codec identity carried by every codec-bearing AST node.\n *\n * `(codecId, typeParams?)` is the single fact the runtime needs to materialize a codec via `descriptorFor(codecId).factory(typeParams)(ctx)`. The pair is content-keyed: two refs with the same `codecId` and structurally equal `typeParams` (regardless of object key ordering) resolve to the same memoized {@link Codec} instance.\n *\n * `typeParams` is `JsonValue`-constrained so the ref survives JSON serialization (relevant for AST-embedded migration ops). Non-parameterized codecs leave `typeParams` undefined; the descriptor's `paramsSchema` validates the value at the JSON boundary.\n *\n * Family-agnostic by design — both SQL and Mongo AST nodes carry `codec: CodecRef | undefined`, and the resolver is the only dispatch path that survives serialization.\n */\nexport interface CodecRef {\n readonly codecId: string;\n readonly typeParams?: JsonValue;\n}\n\n/**\n * Per-call context the runtime threads to every `codec.encode` / `codec.decode` invocation for a single `runtime.execute()` call.\n *\n * The framework-level shape is family-agnostic and carries one field:\n *\n * - `signal?: AbortSignal` — per-query cancellation. The runtime returns a `RUNTIME.ABORTED` envelope when the signal aborts; codec authors who forward `signal` to their underlying SDK get true cancellation of in-flight network calls.\n *\n * Family layers extend this base with their own shape-of-call metadata: the SQL family adds `column?: SqlColumnRef` via `SqlCodecCallContext` (see `@prisma-next/sql-relational-core`). Mongo currently uses this framework type unchanged. Column metadata is intentionally **not** on the framework type — it is a SQL-family concept rooted in SQL's `(table, column)` addressing model and would not generalise to other families.\n *\n * The interface is named explicitly (not inlined) so future framework fields and family extensions can land additively without breaking codec author signatures.\n */\nexport interface CodecCallContext {\n readonly signal?: AbortSignal;\n}\n\n/**\n * Codec-id-keyed read surface threaded into emit and authoring paths.\n *\n * - `get(id)` returns a representative {@link Codec} instance for the codec id (used by `family.deserializeContract` for `decodeJson` of literal column defaults). For parameterized codecs whose factory requires concrete params, this may return `undefined` — use `CodecRegistry.forCodecRef` instead.\n * - `targetTypesFor(id)` exposes the codec-id-keyed `targetTypes` metadata the runtime instance no longer carries (TML-2357). Returns the same array `CodecDescriptor.targetTypes` would; for Mongo (whose registration doesn't yet resolve through the unified descriptor map — TML-2324) the family-side assembly populates this directly from the contributor's codec metadata.\n * - `metaFor(id)` exposes the codec-id-keyed `meta` (e.g. SQL-side `db.sql.postgres.nativeType`) the runtime instance no longer carries.\n * - `renderOutputTypeFor(id, params)` exposes the codec-id-keyed `renderOutputType` renderer the runtime instance no longer carries. Returns `undefined` when the codec doesn't render a custom type or when the codec id is unknown.\n */\nexport interface CodecLookup {\n get(id: string): Codec | undefined;\n targetTypesFor(id: string): readonly string[] | undefined;\n metaFor(id: string): CodecMeta | undefined;\n renderOutputTypeFor(id: string, params: Record<string, unknown>): string | undefined;\n /** Codec-id-keyed `renderInputType` renderer for the `contract.d.ts` input position. Optional so existing lookups need not provide it; returns `undefined` when the codec renders no custom input type or the id is unknown. */\n renderInputTypeFor?(id: string, params: Record<string, unknown>): string | undefined;\n}\n\n/**\n * Full codec registry — the read surface of {@link CodecLookup} plus codec resolution by ref or\n * column coordinate. Built once by `extractCodecLookup` and passed by reference to adapters and\n * other consumers that need to materialise codecs at runtime.\n *\n * - `forCodecRef(ref)` materialises a codec from a {@link CodecRef}. Throws\n * `RUNTIME.CODEC_DESCRIPTOR_MISSING` for unknown ids and `RUNTIME.TYPE_PARAMS_INVALID` on param\n * schema rejection.\n * - `forColumn(namespaceId, table, column)` returns the codec for a specific column coordinate, or\n * `undefined` when no column-to-codec mapping is present. This registry is contract-free so it\n * always returns `undefined` — the method exists so the object structurally satisfies the SQL\n * `ContractCodecRegistry` interface.\n */\nexport interface CodecRegistry extends CodecLookup {\n forCodecRef(ref: CodecRef): Codec;\n forColumn(namespaceId: string, table: string, column: string): Codec | undefined;\n}\n\nexport const emptyCodecLookup: CodecLookup = {\n get: () => undefined,\n targetTypesFor: () => undefined,\n metaFor: () => undefined,\n renderOutputTypeFor: () => undefined,\n};\n\n/**\n * Family-agnostic per-instance context supplied by the framework when applying a higher-order codec factory. Allows stateful codecs (e.g. column-scoped encryption) to derive per-instance state from the materialization site.\n *\n * - `name` — the family-agnostic instance identity. For SQL, the runtime populates this as the `storage.types` instance name (e.g. `Embedding1536`) for typeRef-shaped columns, an inline-column sentinel (`<col:Document.embedding>`) for inline-`typeParams` columns, a shared codec-id sentinel (`<codec:pg/text@1>`) for non-parameterized codec ids, or the canonical cache key (`<codecId>:<canonicalizeJson(typeParams)>`) for ad-hoc refs the contract walk did not pre-populate. Other families pick the analogous identity for their materialization sites.\n *\n * Family-specific extensions (e.g. {@link import('@prisma-next/sql-relational-core/ast').SqlCodecInstanceContext} in the SQL layer) augment this base with domain-shaped column-set metadata. Codec authors target the base when they don't read family-specific metadata; they target the family extension when they do.\n */\nexport interface CodecInstanceContext {\n readonly name: string;\n}\n\n/**\n * Family-agnostic codec metadata. Family-specific extensions augment the base `db.<family>.<target>` block with native-type information; the base shape is an empty object so non-relational codecs can carry no metadata.\n */\nexport interface CodecMeta {\n readonly db?: Record<string, unknown>;\n}\n\n/**\n * Standard Schema validator for `void` params. Accepts only `undefined` (or absent input); rejects any other value so a contract that tries to thread `typeParams` through a non-parameterized codec id fails fast at the JSON boundary instead of silently coercing the value away. Used by the framework-supplied non-parameterized descriptor synthesizer.\n */\nexport const voidParamsSchema: StandardSchemaV1<void> = {\n '~standard': {\n version: 1,\n vendor: 'prisma-next',\n validate: (input) =>\n input === undefined\n ? { value: undefined }\n : {\n issues: [\n {\n message: 'unexpected typeParams for non-parameterized codec (void params expected)',\n },\n ],\n },\n },\n};\n","/**\n * Codec descriptor interface (consumer surface) and abstract `CodecDescriptorImpl` base (codec-author surface).\n *\n * Consumers depend on the {@link CodecDescriptor} interface — it is the codec-id-keyed source of truth for static metadata (`traits`, `targetTypes`, `meta`) and registration concerns (`paramsSchema`; optional `renderOutputType`). The runtime `Codec` instance returned by `factory(params)(ctx)` carries only the conversion behavior.\n *\n * Codec authors `extend` the {@link CodecDescriptorImpl} abstract class to declare their codec id, traits, target types, params schema, the `factory(params)` that materializes a typed `Codec<...>`, and (optionally) a `renderOutputType(params)` for the emit path.\n *\n * The factory's method-level generic is the load-bearing piece for literal preservation: per-codec column helpers invoke `descriptor.factory(...)` *directly*, and the direct call binds the generic at its call site. Type extraction (`ReturnType<D['factory']>`, structural matching) widens method generics to their constraint — that's why the column-helper surface is per-codec, not polymorphic.\n */\n\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Codec } from './codec';\nimport {\n type CodecInstanceContext,\n type CodecMeta,\n type CodecTrait,\n voidParamsSchema,\n} from './codec-types';\n\n/**\n * Unified codec descriptor. Every codec in the framework registers through this shape — non-parameterized codecs use `P = void` and a constant factory that returns the same shared codec instance for every column; parameterized codecs use a non-empty `P` and a curried higher-order factory that returns a per-instance codec.\n *\n * The descriptor is the codec-id-keyed source of truth for static metadata (`traits`, `targetTypes`, `meta`) and registration concerns (`paramsSchema` for JSON-boundary validation; optional `renderOutputType` for the `contract.d.ts` emit path). The runtime `Codec` instance returned by `factory(params)(ctx)` carries only the conversion behavior.\n *\n * Whether a codec id \"is parameterized\" stops being a registration-time distinction — it's a property of `P` on the descriptor. The descriptor map indexes every descriptor by `codecId`; both `descriptorFor(codecId)` and `forColumn(table, column)` resolve through the same map without branching on parameterization.\n *\n * @template P - The shape of the params accepted by the factory (`void` for non-parameterized codecs; a record like `{ length: number }` for parameterized codecs).\n *\n * Codec-registry-unification project § Decision.\n */\nexport interface CodecDescriptor<P = void> {\n /** The codec ID this descriptor applies to (e.g. `pg/vector@1`, `pg/text@1`). */\n readonly codecId: string;\n /** Semantic traits for operator gating (e.g. equality, order, numeric). */\n readonly traits: readonly CodecTrait[];\n /** Database-native type names this codec handles (e.g. `['timestamptz']`). */\n readonly targetTypes: readonly string[];\n /** Optional family-specific metadata (e.g. SQL-side `db.sql.postgres.nativeType`). */\n readonly meta?: CodecMeta;\n /** Standard Schema validator for the factory's params. Validates JSON-sourced params at the contract boundary (PSL → IR; `contract.json` → runtime). For non-parameterized codecs (`P = void`), the schema validates `void`/`undefined` — the framework supplies no params at the call boundary. */\n readonly paramsSchema: StandardSchemaV1<P>;\n /** Whether this descriptor is parameterized — i.e. its `paramsSchema` is something other than the singleton `voidParamsSchema`. Consumers that need to gate column-aware dispatch read this directly rather than threading a free-floating `(codecId) => boolean` callback. */\n readonly isParameterized: boolean;\n /** Emit-path string renderer for `contract.d.ts`. Returns the TypeScript output type expression for given params (e.g. `Vector<1536>`). Optional; absent renderers cause the emitter to fall back to the codec's base output type. Non-parameterized codecs typically omit it. */\n readonly renderOutputType?: (params: P) => string | undefined;\n /** Emit-path string renderer for the `contract.d.ts` *input* position (create/update values). Returns the TypeScript input type expression for given params. Optional; absent renderers fall back to the codec's base input type. A codec supplies this when its write type is narrower than the generic codec input — e.g. an enum whose input should be the literal member union, not `string`. */\n readonly renderInputType?: (params: P) => string | undefined;\n /** The curried higher-order codec. For non-parameterized codecs, the factory is constant — every call returns the same shared codec instance. For parameterized codecs, the factory is called once per `storage.types` instance (or once per inline-`typeParams` column), with `ctx` carrying the column set the resulting codec serves. */\n readonly factory: (params: P) => (ctx: CodecInstanceContext) => Codec;\n}\n\n/**\n * Variance-erased {@link CodecDescriptor} alias. `CodecDescriptor<P>` is invariant in `P` (the `factory` and `renderOutputType` slots use `P` contravariantly), so `CodecDescriptor<P>` does not extend `CodecDescriptor<unknown>` for specific `P`. Heterogeneous descriptor collections — e.g. `SqlStaticContributions.codecs:` returning a list that mixes parameterized and non-parameterized descriptors — type against this alias and narrow per codec id at the consumer.\n *\n * Codec-registry-unification spec § Decision: every codec resolves through one descriptor map; reads are non-branching.\n */\n// biome-ignore lint/suspicious/noExplicitAny: variance erasure for heterogeneous descriptor collections\nexport type AnyCodecDescriptor = CodecDescriptor<any>;\n\n/**\n * Abstract base class for concrete codec descriptors.\n *\n * Codec authors extend this class with their typed `TParams` and declare `codecId`, `traits`, `targetTypes`, `paramsSchema`, the curried `factory(params)`, and (optionally) `renderOutputType`.\n *\n * Implements the {@link CodecDescriptor} interface so a concrete subclass instance is directly usable wherever the framework expects a `CodecDescriptor<P>`.\n */\nexport abstract class CodecDescriptorImpl<TParams = void> implements CodecDescriptor<TParams> {\n abstract readonly codecId: string;\n abstract readonly traits: readonly CodecTrait[];\n abstract readonly targetTypes: readonly string[];\n readonly meta?: CodecMeta;\n\n abstract readonly paramsSchema: StandardSchemaV1<TParams>;\n\n /** Boolean derived from `paramsSchema`: `true` whenever the schema is not the singleton `voidParamsSchema`. */\n get isParameterized(): boolean {\n return this.paramsSchema !== voidParamsSchema;\n }\n\n /** Optional emit-path string renderer for `contract.d.ts`. Returns the TypeScript output type expression for the given params (e.g. `Vector<1536>`). Non-parameterized codecs typically omit it. */\n renderOutputType?(params: TParams): string | undefined;\n\n /** Optional emit-path string renderer for the `contract.d.ts` input position. Returns the TypeScript input type expression for the given params; supplied when the write type is narrower than the generic codec input (e.g. an enum's literal member union). */\n renderInputType?(params: TParams): string | undefined;\n\n /**\n * Materialize a curried codec factory for the given params. Concrete subclasses override with a typed return type (e.g. `factory<N>(params: { length: N }): (ctx) => VectorCodec<N>`); per-codec helpers read the typed return at the *direct* call site, which is what preserves method-level generics. Type extraction (e.g. `ReturnType<D['factory']>`) widens method generics to their constraint — that's why the column-helper surface is per-codec, not polymorphic.\n */\n abstract factory(\n params: TParams,\n ): (ctx: CodecInstanceContext) => Codec<string, readonly CodecTrait[], unknown, unknown>;\n}\n","/**\n * `column()` packager + `ColumnSpec<R, P>` shape + `ColumnHelperFor<D>` variants for tying per-codec column helpers to their descriptor.\n *\n * `ColumnSpec<R, P>` extends {@link ColumnTypeDescriptor} so it remains a drop-in for contract authoring sites that consume `ColumnTypeDescriptor` shapes — both types live at the framework-components layer so the `extends` clause is real (no structural mirror).\n *\n * `column()` is a trivial, non-polymorphic packager. Generic over `R` (the codec instance type returned by the descriptor's curried factory) and `P` (the typeParams record). The framework does NOT try to infer `R` and `P` from a descriptor — that path is the variance trap. Per-codec helpers absorb the descriptor relationship instead and tie themselves to their descriptor via `satisfies ColumnHelperFor<D>` or `satisfies ColumnHelperForStrict<D>`.\n */\n\nimport type { CodecDescriptor } from './codec-descriptor';\nimport type { CodecInstanceContext } from './codec-types';\n\n/**\n * Authored column-type descriptor — the data shape an authoring site (PSL or TypeScript builders) attaches to a column to identify its codec and its native database type.\n *\n * Lives at the framework-components layer alongside the codec types so codec-author packages (e.g. column-spec / `column()` packagers) can extend it directly without crossing layer boundaries.\n *\n * @template TCodecId Narrowed codec id literal for sites that thread a specific codec id through the type system.\n */\nexport type ColumnTypeDescriptor<TCodecId extends string = string> = {\n readonly codecId: TCodecId;\n readonly nativeType: string;\n readonly typeParams?: Record<string, unknown> | undefined;\n readonly typeRef?: string;\n};\n\n/**\n * Column spec carrying the codec factory closure alongside the {@link ColumnTypeDescriptor} fields. Codec authors return a `ColumnSpec` from per-codec column helpers; the runtime materializes the codec instance by calling `codecFactory(ctx)` once it knows the column's `CodecInstanceContext`.\n *\n * Extends {@link ColumnTypeDescriptor} so `ColumnSpec` instances flow directly into contract-authoring sites that consume the descriptor shape — no structural mirroring required.\n */\nexport interface ColumnSpec<R, P extends Record<string, unknown> | undefined>\n extends ColumnTypeDescriptor {\n readonly codecFactory: (ctx: CodecInstanceContext) => R;\n readonly typeParams: P;\n}\n\n/**\n * Trivial column packager. Per-codec helpers call this directly with the result of `descriptor.factory(params)` — direct method invocation binds the descriptor's method-level generic at the call site and the literal flows through `R`.\n *\n * `nativeType` is the column's database-native type spelling — the value the postgres adapter's migration planner, the SQL renderer's cast policy, and the contract's `meta.db.<family>.<target>.nativeType` slot read. Per-codec helpers pass the literal native-type string for their codec (e.g. `'text'`, `'int4'`, `'character varying'`); for codecs whose native-type spelling depends on parameters (none today; reserved for future shapes), the helper computes the rendered string before calling `column`. The framework does not derive the value from `codecId` — that mapping is target-specific and lives at the helper.\n */\nexport function column<R, P extends Record<string, unknown> | undefined>(\n codecFactory: (ctx: CodecInstanceContext) => R,\n codecId: string,\n typeParams: P,\n nativeType: string,\n): ColumnSpec<R, P> {\n return {\n codecFactory,\n codecId,\n typeParams,\n nativeType,\n };\n}\n\n/**\n * Coarse `satisfies` shape — checks the helper's typeParams record matches the descriptor's factory params. Catches \"wrong typeParams shape\" wiring mistakes; does NOT catch \"wrong descriptor's factory\" mistakes (the codec slot is left as `unknown`).\n *\n * Use when the codec's `ReturnType<factory>` is unstable (e.g. heavily overloaded factories where extraction widens too much).\n */\n// biome-ignore lint/suspicious/noExplicitAny: variance erasure — `CodecDescriptor<P>` is invariant in P, so concrete subclasses do not extend `CodecDescriptor<unknown>`; matches the existing `AnyCodecDescriptor` pattern\nexport type ColumnHelperFor<D extends CodecDescriptor<any>> = (\n // biome-ignore lint/suspicious/noExplicitAny: helper signature is the verification subject; satisfies clauses can't narrow this without circular inference\n ...args: any[]\n) => ColumnSpec<unknown, ColumnHelperParams<D>>;\n\n/**\n * Strict `satisfies` shape — also checks the helper's codec is at least the *base* codec instance type the descriptor's factory returns. `ReturnType<ReturnType<D['factory']>>` widens method generics to their constraint, so this only sanity-checks the wiring at the base type level. Literal preservation comes from the direct `descriptor.factory(...)` call inside the helper, not from `satisfies`.\n */\n// biome-ignore lint/suspicious/noExplicitAny: variance erasure — `CodecDescriptor<P>` is invariant in P, so concrete subclasses do not extend `CodecDescriptor<unknown>`; matches the existing `AnyCodecDescriptor` pattern\nexport type ColumnHelperForStrict<D extends CodecDescriptor<any>> = (\n // biome-ignore lint/suspicious/noExplicitAny: helper signature is the verification subject; satisfies clauses can't narrow this without circular inference\n ...args: any[]\n) => ColumnSpec<ReturnType<ReturnType<D['factory']>>, ColumnHelperParams<D>>;\n\n/**\n * Coerce a descriptor's `factory` first parameter into the typeParams shape `ColumnSpec` accepts. Non-parameterized descriptors (factory with no params, or `params: void`) collapse to `undefined`; parameterized descriptors keep the params record shape.\n */\n// biome-ignore lint/suspicious/noExplicitAny: variance erasure — see above\ntype ColumnHelperParams<D extends CodecDescriptor<any>> =\n Parameters<D['factory']>[0] extends Record<string, unknown>\n ? Parameters<D['factory']>[0]\n : undefined;\n"],"mappings":";;;;;;;AA0DA,IAAsB,YAAtB,MAMA;CAK8B;;;;CAA5B,YAAY,YAAkD;EAAlC,KAAA,aAAA;CAAmC;CAE/D,IAAI,KAAS;EACX,OAAO,KAAK,WAAW;CACzB;AAMF;;;ACTA,MAAa,mBAAgC;CAC3C,WAAW,KAAA;CACX,sBAAsB,KAAA;CACtB,eAAe,KAAA;CACf,2BAA2B,KAAA;AAC7B;;;;AAuBA,MAAa,mBAA2C,EACtD,aAAa;CACX,SAAS;CACT,QAAQ;CACR,WAAW,UACT,UAAU,KAAA,IACN,EAAE,OAAO,KAAA,EAAU,IACnB,EACE,QAAQ,CACN,EACE,SAAS,2EACX,CACF,EACF;AACR,EACF;;;;;;;;;;AC/CA,IAAsB,sBAAtB,MAA8F;CAI5F;;CAKA,IAAI,kBAA2B;EAC7B,OAAO,KAAK,iBAAiB;CAC/B;AAcF;;;;;;;;AClDA,SAAgB,OACd,cACA,SACA,YACA,YACkB;CAClB,OAAO;EACL;EACA;EACA;EACA;CACF;AACF"} | ||
| {"version":3,"file":"codec.mjs","names":[],"sources":["../src/shared/codec.ts","../src/shared/codec-types.ts","../src/shared/codec-descriptor.ts","../src/shared/column-spec.ts","../src/shared/render-ts-literal.ts"],"sourcesContent":["/**\n * Codec interface (consumer surface) and abstract `CodecImpl` base (codec-author surface).\n *\n * Consumers depend on the {@link Codec} interface — it describes the runtime instance returned by a descriptor's curried factory and is what the framework threads through emit, validate, and execute paths.\n *\n * Codec authors `extend` the {@link CodecImpl} abstract class to declare a typed runtime codec instance. The class carries a variance-erased descriptor reference (`CodecDescriptor<any>`); `id` proxies through the descriptor so one source of truth governs both metadata reads and aliasing semantics (alias subclasses inherit the descriptor's id automatically).\n *\n * Class generic shape: `Id`, `TTraits`, `TWire`, `TInput`. Method generics on the codec subclass's own surface (e.g. arktype-json's schema generic, pgvector's dimension generic) flow through the subclass's constructor and propagate via the descriptor's typed `factory(params)` return at *direct* call sites.\n */\n\nimport type { JsonValue } from '@prisma-next/contract/types';\nimport type { CodecDescriptor } from './codec-descriptor';\nimport type { CodecCallContext, CodecTrait } from './codec-types';\n\n/**\n * A codec is the contract between an application value and its driver-wire and JSON representations.\n *\n * The author's mental model is two JS-side types — `TInput` (the application JS type) and `TWire` (the database driver wire format) — plus a target-defined `JsonValue`. The codec translates `TInput` to `TWire` on writes and back on ordinary reads, and to/from the target's JSON representation for contract artifacts and database-produced JSON values.\n *\n * Three representations participate:\n * - **Input** (`TInput`): the JS type at the application boundary.\n * - **Wire** (`TWire`): the format exchanged with the database driver.\n * - **JSON** (`JsonValue`): the target-defined JSON-safe form used in contract artifacts. It uses the exact scalar shape the target produces inside JSON values, which can differ from the ordinary wire format.\n *\n * The runtime instance carries only its `id` (the descriptor's `codecId`, set by the factory) and the four conversion methods. Static metadata (`traits`, `targetTypes`, `meta`) and the build-time `renderOutputType` renderer live on the {@link CodecDescriptor} keyed by `codecId` — the read-surface single source of truth. Consumers that need them resolve through `descriptorFor(codecId)`.\n *\n * Codec methods split into two groups:\n *\n * - **Query-time** methods (`encode`, `decode`) run per row/parameter at the IO boundary; they are required and Promise-returning. The per-family codec factory accepts sync or async author functions and lifts sync ones to Promise-shaped methods automatically.\n * - **JSON** methods (`encodeJson`, `decodeJson`) run when the contract is serialized or loaded. Runtimes may also use `decodeJson` for values embedded in database-produced JSON results. They stay synchronous so contract validation and client construction are synchronous.\n *\n * Target-family codec interfaces extend this base; family-specific concerns (e.g. the SQL `column?` per-call context) layer on through the `CodecCallContext` extension pattern.\n */\nexport interface Codec<\n Id extends string = string,\n TTraits extends readonly CodecTrait[] = readonly CodecTrait[],\n TWire = unknown,\n TInput = unknown,\n> {\n /** Unique codec identifier in `namespace/name@version` format (e.g. `pg/timestamptz@1`). The factory sets this to the descriptor's `codecId`; consumers use it as a back-reference for descriptor lookups and for decode-error diagnostics. */\n readonly id: Id;\n /** Phantom carrier for the `TTraits` generic; type-only, undefined at runtime. Runtime traits live on {@link CodecDescriptor.traits}. Implemented as a string-key phantom (`__codecTraits`) rather than `unique symbol` so bundlers that split `.d.ts` chunks do not strand symbol identity on chunk-private paths (the same `TS2742` family that the public re-export of `CodecTypes` works around). */\n readonly __codecTraits?: TTraits;\n /** Converts a JS value to the wire format expected by the database driver. Always Promise-returning at the boundary. The {@link CodecCallContext} is supplied by the runtime on every call (allocated once per `runtime.execute()`); family layers may narrow the ctx to extend it (e.g. SQL adds `column`). Author-side single-arg `(value) => …` functions remain legal via TypeScript's bivariance for trailing parameters. */\n encode(value: TInput, ctx: CodecCallContext): Promise<TWire>;\n /** Converts a wire value from the database driver into the JS application type. Always Promise-returning at the boundary. The {@link CodecCallContext} is supplied by the runtime on every call (allocated once per `runtime.execute()`); family layers may narrow the ctx to extend it (e.g. SQL adds `column`). Author-side single-arg `(wire) => …` functions remain legal via TypeScript's bivariance for trailing parameters. */\n decode(wire: TWire, ctx: CodecCallContext): Promise<TInput>;\n /** Converts a JS value to the target-defined JSON representation used for contract serialization. This must match the scalar shape produced by the target inside JSON values. Synchronous; called during contract emission. */\n encodeJson(value: TInput): JsonValue;\n /** Converts the target-defined JSON representation back to the JS input type. Synchronous; called during contract loading via `family.deserializeContract` and may be called by runtimes for embedded JSON values. */\n decodeJson(json: JsonValue): TInput;\n}\n\n/**\n * Abstract base class for concrete codec implementations.\n *\n * Codec authors extend this class with their typed `Id`, `TTraits`, `TWire`, `TInput` and override all four abstract conversion methods: `encode`, `decode`, `encodeJson`, and `decodeJson`. The runtime instance carries only its `id` (proxied through the descriptor so alias subclasses inherit the descriptor's id automatically) and the conversion methods — static metadata lives on the {@link CodecDescriptor}.\n */\nexport abstract class CodecImpl<\n Id extends string = string,\n TTraits extends readonly CodecTrait[] = readonly CodecTrait[],\n TWire = unknown,\n TInput = unknown,\n> implements Codec<Id, TTraits, TWire, TInput>\n{\n /**\n * Variance-erased descriptor reference. Concrete codec subclasses receive the typed descriptor in their own constructors and forward it via `super(descriptor)`; the variance erasure lives at this base because the abstract surface can't carry the concrete `TParams`.\n */\n // biome-ignore lint/suspicious/noExplicitAny: variance-erased descriptor reference; subclasses retain typed access via their own state\n constructor(public readonly descriptor: CodecDescriptor<any>) {}\n\n get id(): Id {\n return this.descriptor.codecId as Id;\n }\n\n abstract encode(value: TInput, ctx: CodecCallContext): Promise<TWire>;\n abstract decode(wire: TWire, ctx: CodecCallContext): Promise<TInput>;\n abstract encodeJson(value: TInput): JsonValue;\n abstract decodeJson(json: JsonValue): TInput;\n}\n","import type { JsonValue } from '@prisma-next/contract/types';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Codec } from './codec';\nimport type { AnyCodecDescriptor } from './codec-descriptor';\n\nexport type CodecTrait = 'equality' | 'order' | 'boolean' | 'numeric' | 'textual';\n\n/**\n * Serializable codec identity carried by every codec-bearing AST node.\n *\n * `(codecId, typeParams?)` is the single fact the runtime needs to materialize a codec via `descriptorFor(codecId).factory(typeParams)(ctx)`. The pair is content-keyed: two refs with the same `codecId` and structurally equal `typeParams` (regardless of object key ordering) resolve to the same memoized {@link Codec} instance.\n *\n * `typeParams` is `JsonValue`-constrained so the ref survives JSON serialization (relevant for AST-embedded migration ops). Non-parameterized codecs leave `typeParams` undefined; the descriptor's `paramsSchema` validates the value at the JSON boundary.\n *\n * `many` marks a scalar-array (list-typed) column. When `true`, the encode/decode paths map the element codec over the JS array rather than applying the codec to the whole value. The element codec id is `codecId`; the driver owns the array wire framing (`{…}`) in both directions. Absent for scalar columns.\n *\n * Family-agnostic by design — both SQL and Mongo AST nodes carry `codec: CodecRef | undefined`, and the resolver is the only dispatch path that survives serialization.\n */\nexport interface CodecRef {\n readonly codecId: string;\n readonly typeParams?: JsonValue;\n readonly many?: boolean;\n}\n\n/**\n * Per-call context the runtime threads to every `codec.encode` / `codec.decode` invocation for a single `runtime.execute()` call.\n *\n * The framework-level shape is family-agnostic and carries one field:\n *\n * - `signal?: AbortSignal` — per-query cancellation. The runtime returns a `RUNTIME.ABORTED` envelope when the signal aborts; codec authors who forward `signal` to their underlying SDK get true cancellation of in-flight network calls.\n *\n * Family layers extend this base with their own shape-of-call metadata: the SQL family adds `column?: SqlColumnRef` via `SqlCodecCallContext` (see `@prisma-next/sql-relational-core`). Mongo currently uses this framework type unchanged. Column metadata is intentionally **not** on the framework type — it is a SQL-family concept rooted in SQL's `(table, column)` addressing model and would not generalise to other families.\n *\n * The interface is named explicitly (not inlined) so future framework fields and family extensions can land additively without breaking codec author signatures.\n */\nexport interface CodecCallContext {\n readonly signal?: AbortSignal;\n}\n\n/**\n * Codec-id-keyed read surface threaded into emit and authoring paths.\n *\n * - `get(id)` returns a representative {@link Codec} instance for the codec id (used by `family.deserializeContract` for `decodeJson` of literal column defaults). For parameterized codecs whose factory requires concrete params, this may return `undefined` — use `CodecRegistry.forCodecRef` instead.\n * - `targetTypesFor(id)` exposes the codec-id-keyed `targetTypes` metadata the runtime instance no longer carries (TML-2357). Returns the same array `CodecDescriptor.targetTypes` would; for Mongo (whose registration doesn't yet resolve through the unified descriptor map — TML-2324) the family-side assembly populates this directly from the contributor's codec metadata.\n * - `metaFor(id, typeParams)` exposes the codec-id-keyed `meta` (e.g. SQL-side `db.sql.postgres.nativeType`) the runtime instance no longer carries. `typeParams` is optional: when given and the codec descriptor implements a params-aware `metaFor`, the descriptor computes its meta from those params (e.g. a native enum's per-instance Postgres type name); otherwise (or when `typeParams` is omitted) the codec's static `meta` is returned.\n * - `renderOutputTypeFor(id, params)` exposes the codec-id-keyed `renderOutputType` renderer the runtime instance no longer carries. Returns `undefined` when the codec doesn't render a custom type or when the codec id is unknown.\n */\nexport interface CodecLookup {\n get(id: string): Codec | undefined;\n targetTypesFor(id: string): readonly string[] | undefined;\n metaFor(id: string, typeParams?: Record<string, unknown> | JsonValue): CodecMeta | undefined;\n renderOutputTypeFor(id: string, params: Record<string, unknown>): string | undefined;\n /** Codec-id-keyed `renderInputType` renderer for the `contract.d.ts` input position. Optional so existing lookups need not provide it; returns `undefined` when the codec renders no custom input type or the id is unknown. */\n renderInputTypeFor?(id: string, params: Record<string, unknown>): string | undefined;\n /** Codec-id-keyed `renderValueLiteral` renderer for the emit path (`side`: `output` = read type, `input` = create/update type). Optional so existing lookups need not provide it; returns `undefined` when the codec's output isn't literal-expressible or the id is unknown. */\n renderValueLiteralFor?(\n id: string,\n value: JsonValue,\n side: 'output' | 'input',\n ): string | undefined;\n /**\n * Codec-id-keyed descriptor accessor. Returns the full registered\n * {@link AnyCodecDescriptor} for `id`, or `undefined` if no descriptor is\n * registered. Optional so existing lookups need not provide it; a consumer\n * that needs more than the derived per-id readers above — e.g. an\n * authoring-time hook a target-specific descriptor exposes but this\n * framework interface does not model generically — fetches the descriptor\n * itself and narrows it with its own structural predicate.\n */\n descriptorFor?(id: string): AnyCodecDescriptor | undefined;\n}\n\n/**\n * Full codec registry — the read surface of {@link CodecLookup} plus codec resolution by ref or\n * column coordinate. Built once by `extractCodecLookup` and passed by reference to adapters and\n * other consumers that need to materialise codecs at runtime.\n *\n * - `forCodecRef(ref)` materialises a codec from a {@link CodecRef}. Throws\n * `RUNTIME.CODEC_DESCRIPTOR_MISSING` for unknown ids and `RUNTIME.TYPE_PARAMS_INVALID` on param\n * schema rejection.\n * - `forColumn(namespaceId, table, column)` returns the codec for a specific column coordinate, or\n * `undefined` when no column-to-codec mapping is present. This registry is contract-free so it\n * always returns `undefined` — the method exists so the object structurally satisfies the SQL\n * `ContractCodecRegistry` interface.\n */\nexport interface CodecRegistry extends CodecLookup {\n forCodecRef(ref: CodecRef): Codec;\n forColumn(namespaceId: string, table: string, column: string): Codec | undefined;\n}\n\nexport const emptyCodecLookup: CodecLookup = {\n get: () => undefined,\n targetTypesFor: () => undefined,\n metaFor: () => undefined,\n renderOutputTypeFor: () => undefined,\n};\n\n/**\n * Family-agnostic per-instance context supplied by the framework when applying a higher-order codec factory. Allows stateful codecs (e.g. column-scoped encryption) to derive per-instance state from the materialization site.\n *\n * - `name` — the family-agnostic instance identity. For SQL, the runtime populates this as the `storage.types` instance name (e.g. `Embedding1536`) for typeRef-shaped columns, an inline-column sentinel (`<col:Document.embedding>`) for inline-`typeParams` columns, a shared codec-id sentinel (`<codec:pg/text@1>`) for non-parameterized codec ids, or the canonical cache key (`<codecId>:<canonicalizeJson(typeParams)>`) for ad-hoc refs the contract walk did not pre-populate. Other families pick the analogous identity for their materialization sites.\n *\n * Family-specific extensions (e.g. {@link import('@prisma-next/sql-relational-core/ast').SqlCodecInstanceContext} in the SQL layer) augment this base with domain-shaped column-set metadata. Codec authors target the base when they don't read family-specific metadata; they target the family extension when they do.\n */\nexport interface CodecInstanceContext {\n readonly name: string;\n}\n\n/**\n * Family-agnostic codec metadata. Family-specific extensions augment the base `db.<family>.<target>` block with native-type information; the base shape is an empty object so non-relational codecs can carry no metadata.\n */\nexport interface CodecMeta {\n readonly db?: Record<string, unknown>;\n}\n\n/**\n * Standard Schema validator for `void` params. Accepts only `undefined` (or absent input); rejects any other value so a contract that tries to thread `typeParams` through a non-parameterized codec id fails fast at the JSON boundary instead of silently coercing the value away. Used by the framework-supplied non-parameterized descriptor synthesizer.\n */\nexport const voidParamsSchema: StandardSchemaV1<void> = {\n '~standard': {\n version: 1,\n vendor: 'prisma-next',\n validate: (input) =>\n input === undefined\n ? { value: undefined }\n : {\n issues: [\n {\n message: 'unexpected typeParams for non-parameterized codec (void params expected)',\n },\n ],\n },\n },\n};\n","/**\n * Codec descriptor interface (consumer surface) and abstract `CodecDescriptorImpl` base (codec-author surface).\n *\n * Consumers depend on the {@link CodecDescriptor} interface — it is the codec-id-keyed source of truth for static metadata (`traits`, `targetTypes`, `meta`) and registration concerns (`paramsSchema`; optional `renderOutputType`). The runtime `Codec` instance returned by `factory(params)(ctx)` carries only the conversion behavior.\n *\n * Codec authors `extend` the {@link CodecDescriptorImpl} abstract class to declare their codec id, traits, target types, params schema, the `factory(params)` that materializes a typed `Codec<...>`, and (optionally) a `renderOutputType(params)` for the emit path.\n *\n * The factory's method-level generic is the load-bearing piece for literal preservation: per-codec column helpers invoke `descriptor.factory(...)` *directly*, and the direct call binds the generic at its call site. Type extraction (`ReturnType<D['factory']>`, structural matching) widens method generics to their constraint — that's why the column-helper surface is per-codec, not polymorphic.\n */\n\nimport type { JsonValue } from '@prisma-next/contract/types';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Codec } from './codec';\nimport {\n type CodecInstanceContext,\n type CodecMeta,\n type CodecTrait,\n voidParamsSchema,\n} from './codec-types';\n\n/**\n * Unified codec descriptor. Every codec in the framework registers through this shape — non-parameterized codecs use `P = void` and a constant factory that returns the same shared codec instance for every column; parameterized codecs use a non-empty `P` and a curried higher-order factory that returns a per-instance codec.\n *\n * The descriptor is the codec-id-keyed source of truth for static metadata (`traits`, `targetTypes`, `meta`) and registration concerns (`paramsSchema` for JSON-boundary validation; optional `renderOutputType` for the `contract.d.ts` emit path). The runtime `Codec` instance returned by `factory(params)(ctx)` carries only the conversion behavior.\n *\n * Whether a codec id \"is parameterized\" stops being a registration-time distinction — it's a property of `P` on the descriptor. The descriptor map indexes every descriptor by `codecId`; both `descriptorFor(codecId)` and `forColumn(table, column)` resolve through the same map without branching on parameterization.\n *\n * @template P - The shape of the params accepted by the factory (`void` for non-parameterized codecs; a record like `{ length: number }` for parameterized codecs).\n *\n * Codec-registry-unification project § Decision.\n */\nexport interface CodecDescriptor<P = void> {\n /** The codec ID this descriptor applies to (e.g. `pg/vector@1`, `pg/text@1`). */\n readonly codecId: string;\n /** Semantic traits for operator gating (e.g. equality, order, numeric). */\n readonly traits: readonly CodecTrait[];\n /** Database-native type names this codec handles (e.g. `['timestamptz']`). */\n readonly targetTypes: readonly string[];\n /** Optional family-specific metadata (e.g. SQL-side `db.sql.postgres.nativeType`). */\n readonly meta?: CodecMeta;\n /** Standard Schema validator for the factory's params. Validates JSON-sourced params at the contract boundary (PSL → IR; `contract.json` → runtime). For non-parameterized codecs (`P = void`), the schema validates `void`/`undefined` — the framework supplies no params at the call boundary. */\n readonly paramsSchema: StandardSchemaV1<P>;\n /** Whether this descriptor is parameterized — i.e. its `paramsSchema` is something other than the singleton `voidParamsSchema`. Consumers that need to gate column-aware dispatch read this directly rather than threading a free-floating `(codecId) => boolean` callback. */\n readonly isParameterized: boolean;\n /** Optional params-aware metadata renderer. Computes this codec instance's `CodecMeta` from its `typeParams` (e.g. a per-instance identifier derived from an enum's declared member set). Optional; absent renderers cause `CodecLookup.metaFor` to fall back to the codec's static `meta`. Non-parameterized codecs typically omit it. */\n readonly metaFor?: (params: P) => CodecMeta | undefined;\n /** Emit-path string renderer for `contract.d.ts`. Returns the TypeScript output type expression for given params (e.g. `Vector<1536>`). Optional; absent renderers cause the emitter to fall back to the codec's base output type. Non-parameterized codecs typically omit it. */\n readonly renderOutputType?: (params: P) => string | undefined;\n /** Emit-path string renderer for the `contract.d.ts` *input* position (create/update values). Returns the TypeScript input type expression for given params. Optional; absent renderers fall back to the codec's base input type. A codec supplies this when its write type is narrower than the generic codec input — e.g. an enum whose input should be the literal member union, not `string`. */\n readonly renderInputType?: (params: P) => string | undefined;\n /**\n * Given one stored (codec-encoded) value, return the TypeScript literal type to print for it\n * (e.g. `'low'`, `1`), or `undefined` if this codec's output isn't literal-expressible (e.g. a\n * Date-output codec).\n *\n * `value` is the `encodeJson` form stored in the value set. `side` selects which type to print:\n * `output` = the read/SELECT type; `input` = the create/update type. Most codecs render the same\n * literal for both, but a codec whose read and write types differ can render per side. Called once\n * per permitted value; the caller joins the results with `|`.\n */\n readonly renderValueLiteral?: (value: JsonValue, side: 'output' | 'input') => string | undefined;\n /** The curried higher-order codec. For non-parameterized codecs, the factory is constant — every call returns the same shared codec instance. For parameterized codecs, the factory is called once per `storage.types` instance (or once per inline-`typeParams` column), with `ctx` carrying the column set the resulting codec serves. */\n readonly factory: (params: P) => (ctx: CodecInstanceContext) => Codec;\n}\n\n/**\n * Variance-erased {@link CodecDescriptor} alias. `CodecDescriptor<P>` is invariant in `P` (the `factory` and `renderOutputType` slots use `P` contravariantly), so `CodecDescriptor<P>` does not extend `CodecDescriptor<unknown>` for specific `P`. Heterogeneous descriptor collections — e.g. `SqlStaticContributions.codecs:` returning a list that mixes parameterized and non-parameterized descriptors — type against this alias and narrow per codec id at the consumer.\n *\n * Codec-registry-unification spec § Decision: every codec resolves through one descriptor map; reads are non-branching.\n */\n// biome-ignore lint/suspicious/noExplicitAny: variance erasure for heterogeneous descriptor collections\nexport type AnyCodecDescriptor = CodecDescriptor<any>;\n\n/**\n * Abstract base class for concrete codec descriptors.\n *\n * Codec authors extend this class with their typed `TParams` and declare `codecId`, `traits`, `targetTypes`, `paramsSchema`, the curried `factory(params)`, and (optionally) `renderOutputType`.\n *\n * Implements the {@link CodecDescriptor} interface so a concrete subclass instance is directly usable wherever the framework expects a `CodecDescriptor<P>`.\n */\nexport abstract class CodecDescriptorImpl<TParams = void> implements CodecDescriptor<TParams> {\n abstract readonly codecId: string;\n abstract readonly traits: readonly CodecTrait[];\n abstract readonly targetTypes: readonly string[];\n readonly meta?: CodecMeta;\n\n abstract readonly paramsSchema: StandardSchemaV1<TParams>;\n\n /** Boolean derived from `paramsSchema`: `true` whenever the schema is not the singleton `voidParamsSchema`. */\n get isParameterized(): boolean {\n return this.paramsSchema !== voidParamsSchema;\n }\n\n /** Optional params-aware metadata renderer. Computes this codec instance's `CodecMeta` from its `typeParams` (e.g. a per-instance identifier derived from an enum's declared member set). Non-parameterized codecs typically omit it. */\n metaFor?(params: TParams): CodecMeta | undefined;\n\n /** Optional emit-path string renderer for `contract.d.ts`. Returns the TypeScript output type expression for the given params (e.g. `Vector<1536>`). Non-parameterized codecs typically omit it. */\n renderOutputType?(params: TParams): string | undefined;\n\n /** Optional emit-path string renderer for the `contract.d.ts` input position. Returns the TypeScript input type expression for the given params; supplied when the write type is narrower than the generic codec input (e.g. an enum's literal member union). */\n renderInputType?(params: TParams): string | undefined;\n\n /** Optional emit-path renderer for a single stored value. See {@link CodecDescriptor.renderValueLiteral}. */\n renderValueLiteral?(value: JsonValue, side: 'output' | 'input'): string | undefined;\n\n /**\n * Materialize a curried codec factory for the given params. Concrete subclasses override with a typed return type (e.g. `factory<N>(params: { length: N }): (ctx) => VectorCodec<N>`); per-codec helpers read the typed return at the *direct* call site, which is what preserves method-level generics. Type extraction (e.g. `ReturnType<D['factory']>`) widens method generics to their constraint — that's why the column-helper surface is per-codec, not polymorphic.\n */\n abstract factory(\n params: TParams,\n ): (ctx: CodecInstanceContext) => Codec<string, readonly CodecTrait[], unknown, unknown>;\n}\n","/**\n * `column()` packager + `ColumnSpec<R, P>` shape + `ColumnHelperFor<D>` variants for tying per-codec column helpers to their descriptor.\n *\n * `ColumnSpec<R, P>` extends {@link ColumnTypeDescriptor} so it remains a drop-in for contract authoring sites that consume `ColumnTypeDescriptor` shapes — both types live at the framework-components layer so the `extends` clause is real (no structural mirror).\n *\n * `column()` is a trivial, non-polymorphic packager. Generic over `R` (the codec instance type returned by the descriptor's curried factory) and `P` (the typeParams record). The framework does NOT try to infer `R` and `P` from a descriptor — that path is the variance trap. Per-codec helpers absorb the descriptor relationship instead and tie themselves to their descriptor via `satisfies ColumnHelperFor<D>` or `satisfies ColumnHelperForStrict<D>`.\n */\n\nimport type { ValueSetRef } from '@prisma-next/contract/types';\nimport type { CodecDescriptor } from './codec-descriptor';\nimport type { CodecInstanceContext } from './codec-types';\n\n/**\n * Authored column-type descriptor — the data shape an authoring site (PSL or TypeScript builders) attaches to a column to identify its codec and its native database type.\n *\n * Lives at the framework-components layer alongside the codec types so codec-author packages (e.g. column-spec / `column()` packagers) can extend it directly without crossing layer boundaries.\n *\n * @template TCodecId Narrowed codec id literal for sites that thread a specific codec id through the type system.\n */\nexport type ColumnTypeDescriptor<TCodecId extends string = string> = {\n readonly codecId: TCodecId;\n readonly nativeType: string;\n readonly typeParams?: Record<string, unknown> | undefined;\n readonly typeRef?: string;\n /**\n * Storage-plane value-set ref, set by an authoring path that resolves a\n * field's type against a value-set-deriving entity (e.g. a PSL entity-ref\n * type constructor like `pg.enum(Ref)`, or a TS `enumType` handle).\n * Threaded straight onto the storage node this descriptor builds, where it\n * drives value-set → codec typing. Every codec's own descriptor leaves this\n * unset.\n */\n readonly valueSet?: ValueSetRef;\n readonly entityRef?: EntityRef;\n};\n\n/**\n * Late-resolved pack-entity reference — a field on the type descriptor it is\n * declared on: `entityKind`/`entityName` identify a pack entity whose final\n * placement depends on data not yet known when the descriptor carrying this\n * reference is built — e.g. an owning namespace resolved only once the\n * surrounding structure is assembled.\n */\nexport type EntityRef = {\n readonly entityKind: string;\n readonly entityName: string;\n readonly entity: unknown;\n};\n\n/**\n * Column spec carrying the codec factory closure alongside the {@link ColumnTypeDescriptor} fields. Codec authors return a `ColumnSpec` from per-codec column helpers; the runtime materializes the codec instance by calling `codecFactory(ctx)` once it knows the column's `CodecInstanceContext`.\n *\n * Extends {@link ColumnTypeDescriptor} so `ColumnSpec` instances flow directly into contract-authoring sites that consume the descriptor shape — no structural mirroring required.\n */\nexport interface ColumnSpec<R, P extends Record<string, unknown> | undefined>\n extends ColumnTypeDescriptor {\n readonly codecFactory: (ctx: CodecInstanceContext) => R;\n readonly typeParams: P;\n}\n\n/**\n * Trivial column packager. Per-codec helpers call this directly with the result of `descriptor.factory(params)` — direct method invocation binds the descriptor's method-level generic at the call site and the literal flows through `R`.\n *\n * `nativeType` is the column's database-native type spelling — the value the postgres adapter's migration planner, the SQL renderer's cast policy, and the contract's `meta.db.<family>.<target>.nativeType` slot read. Per-codec helpers pass the literal native-type string for their codec (e.g. `'text'`, `'int4'`, `'character varying'`); for codecs whose native-type spelling depends on parameters (none today; reserved for future shapes), the helper computes the rendered string before calling `column`. The framework does not derive the value from `codecId` — that mapping is target-specific and lives at the helper.\n */\nexport function column<R, P extends Record<string, unknown> | undefined>(\n codecFactory: (ctx: CodecInstanceContext) => R,\n codecId: string,\n typeParams: P,\n nativeType: string,\n): ColumnSpec<R, P> {\n return {\n codecFactory,\n codecId,\n typeParams,\n nativeType,\n };\n}\n\n/**\n * Coarse `satisfies` shape — checks the helper's typeParams record matches the descriptor's factory params. Catches \"wrong typeParams shape\" wiring mistakes; does NOT catch \"wrong descriptor's factory\" mistakes (the codec slot is left as `unknown`).\n *\n * Use when the codec's `ReturnType<factory>` is unstable (e.g. heavily overloaded factories where extraction widens too much).\n */\n// biome-ignore lint/suspicious/noExplicitAny: variance erasure — `CodecDescriptor<P>` is invariant in P, so concrete subclasses do not extend `CodecDescriptor<unknown>`; matches the existing `AnyCodecDescriptor` pattern\nexport type ColumnHelperFor<D extends CodecDescriptor<any>> = (\n // biome-ignore lint/suspicious/noExplicitAny: helper signature is the verification subject; satisfies clauses can't narrow this without circular inference\n ...args: any[]\n) => ColumnSpec<unknown, ColumnHelperParams<D>>;\n\n/**\n * Strict `satisfies` shape — also checks the helper's codec is at least the *base* codec instance type the descriptor's factory returns. `ReturnType<ReturnType<D['factory']>>` widens method generics to their constraint, so this only sanity-checks the wiring at the base type level. Literal preservation comes from the direct `descriptor.factory(...)` call inside the helper, not from `satisfies`.\n */\n// biome-ignore lint/suspicious/noExplicitAny: variance erasure — `CodecDescriptor<P>` is invariant in P, so concrete subclasses do not extend `CodecDescriptor<unknown>`; matches the existing `AnyCodecDescriptor` pattern\nexport type ColumnHelperForStrict<D extends CodecDescriptor<any>> = (\n // biome-ignore lint/suspicious/noExplicitAny: helper signature is the verification subject; satisfies clauses can't narrow this without circular inference\n ...args: any[]\n) => ColumnSpec<ReturnType<ReturnType<D['factory']>>, ColumnHelperParams<D>>;\n\n/**\n * Coerce a descriptor's `factory` first parameter into the typeParams shape `ColumnSpec` accepts. Non-parameterized descriptors (factory with no params, or `params: void`) collapse to `undefined`; parameterized descriptors keep the params record shape.\n */\n// biome-ignore lint/suspicious/noExplicitAny: variance erasure — see above\ntype ColumnHelperParams<D extends CodecDescriptor<any>> =\n Parameters<D['factory']>[0] extends Record<string, unknown>\n ? Parameters<D['factory']>[0]\n : undefined;\n","import type { JsonValue } from '@prisma-next/contract/types';\n\n/**\n * Renders a codec-encoded value as a TypeScript literal (e.g. `'low'`, `1`, `true`), or `undefined`\n * when the value isn't literal-expressible (objects, arrays, null).\n *\n * Valid **only for identity codecs** whose `encodeJson` output equals their decoded output type\n * (text, int, float, bool). A non-identity codec (e.g. one that encodes to an int but decodes to a\n * string literal) must NOT use this: it has to `decodeJson` first, then render, in its own\n * `renderValueLiteral`.\n *\n * String values are fully escaped for a single-quoted `.d.ts` literal: backslash, single quote, and\n * every character a raw single-quoted TS literal cannot contain — newline, carriage return, and the\n * U+2028/U+2029 line/paragraph separators (which JS also treats as line terminators).\n */\nexport function renderTsLiteral(value: JsonValue): string | undefined {\n if (typeof value === 'string') {\n const escaped = value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/'/g, \"\\\\'\")\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n return `'${escaped}'`;\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n return undefined;\n}\n"],"mappings":";;;;;;;AA0DA,IAAsB,YAAtB,MAMA;CAK8B;;;;CAA5B,YAAY,YAAkD;EAAlC,KAAA,aAAA;CAAmC;CAE/D,IAAI,KAAS;EACX,OAAO,KAAK,WAAW;CACzB;AAMF;;;ACWA,MAAa,mBAAgC;CAC3C,WAAW,KAAA;CACX,sBAAsB,KAAA;CACtB,eAAe,KAAA;CACf,2BAA2B,KAAA;AAC7B;;;;AAuBA,MAAa,mBAA2C,EACtD,aAAa;CACX,SAAS;CACT,QAAQ;CACR,WAAW,UACT,UAAU,KAAA,IACN,EAAE,OAAO,KAAA,EAAU,IACnB,EACE,QAAQ,CACN,EACE,SAAS,2EACX,CACF,EACF;AACR,EACF;;;;;;;;;;ACrDA,IAAsB,sBAAtB,MAA8F;CAI5F;;CAKA,IAAI,kBAA2B;EAC7B,OAAO,KAAK,iBAAiB;CAC/B;AAoBF;;;;;;;;AC9CA,SAAgB,OACd,cACA,SACA,YACA,YACkB;CAClB,OAAO;EACL;EACA;EACA;EACA;CACF;AACF;;;;;;;;;;;;;;;;AC9DA,SAAgB,gBAAgB,OAAsC;CACpE,IAAI,OAAO,UAAU,UAQnB,OAAO,IAPS,MACb,QAAQ,OAAO,MAAM,CAAC,CACtB,QAAQ,MAAM,KAAK,CAAC,CACpB,QAAQ,OAAO,KAAK,CAAC,CACrB,QAAQ,OAAO,KAAK,CAAC,CACrB,QAAQ,WAAW,SAAS,CAAC,CAC7B,QAAQ,WAAW,SACL,EAAE;CAErB,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,WAChD,OAAO,OAAO,KAAK;AAGvB"} |
@@ -1,34 +0,3 @@ | ||
| import { S as checkContractComponentRequirements, _ as PackRefBase, a as ComponentMetadata, b as TargetInstance, c as DriverDescriptor, d as ExtensionDescriptor, f as ExtensionInstance, g as FamilyPackRef, h as FamilyInstance, i as ComponentDescriptor, l as DriverInstance, m as FamilyDescriptor, n as AdapterInstance, o as ContractComponentRequirementsCheckInput, p as ExtensionPackRef, r as AdapterPackRef, s as ContractComponentRequirementsCheckResult, t as AdapterDescriptor, u as DriverPackRef, v as TargetBoundComponentDescriptor, x as TargetPackRef, y as TargetDescriptor } from "./framework-components-5hA9ij1v.mjs"; | ||
| //#region src/shared/capabilities.d.ts | ||
| /** | ||
| * Capability matrix merge primitive shared by emit-time and runtime stack composition. | ||
| * | ||
| * The CLI's `enrichContract` and the SQL runtime's `createExecutionContext` both need | ||
| * to fold a stack of component descriptors' `capabilities` declarations into a single | ||
| * matrix keyed by namespace. Keeping the primitive here lets both call sites stay | ||
| * byte-for-byte consistent without one depending on the other. | ||
| */ | ||
| /** | ||
| * Merge an ordered list of contributor capability declarations into a base matrix. | ||
| * | ||
| * Behaviour: | ||
| * - `base` and each contributor's `capabilities` are filtered through the same | ||
| * structural extraction: non-plain-object namespace blocks are dropped, | ||
| * non-boolean leaves inside a namespace block are dropped, and a namespace | ||
| * block that ends up with zero boolean leaves is omitted entirely (so a | ||
| * later contributor with a malformed namespace cannot erase a namespace | ||
| * already present in `base`). | ||
| * - Non-plain-object `capabilities` on a contributor (including `undefined`, | ||
| * `null`, arrays, primitives) are skipped silently — the contributor | ||
| * contributes nothing. | ||
| * - Later contributors win on `(namespace, key)` collisions. | ||
| * - The returned object is fresh — neither `base` nor any contributor is mutated. | ||
| * - Output keys are sorted lexicographically at every plain-object level. | ||
| */ | ||
| declare function mergeCapabilityMatrices(base: Record<string, Record<string, boolean>>, contributors: ReadonlyArray<{ | ||
| readonly capabilities?: unknown; | ||
| }>): Record<string, Record<string, boolean>>; | ||
| //#endregion | ||
| export { type AdapterDescriptor, type AdapterInstance, type AdapterPackRef, type ComponentDescriptor, type ComponentMetadata, type ContractComponentRequirementsCheckInput, type ContractComponentRequirementsCheckResult, type DriverDescriptor, type DriverInstance, type DriverPackRef, type ExtensionDescriptor, type ExtensionInstance, type ExtensionPackRef, type FamilyDescriptor, type FamilyInstance, type FamilyPackRef, type PackRefBase, type TargetBoundComponentDescriptor, type TargetDescriptor, type TargetInstance, type TargetPackRef, checkContractComponentRequirements, mergeCapabilityMatrices }; | ||
| //# sourceMappingURL=components.d.mts.map | ||
| import { n as mergeCapabilityMatrices, t as CapabilityMatrix } from "./capabilities-Cupq4-1-.mjs"; | ||
| import { S as checkContractComponentRequirements, _ as PackRefBase, a as ComponentMetadata, b as TargetInstance, c as DriverDescriptor, d as ExtensionDescriptor, f as ExtensionInstance, g as FamilyPackRef, h as FamilyInstance, i as ComponentDescriptor, l as DriverInstance, m as FamilyDescriptor, n as AdapterInstance, o as ContractComponentRequirementsCheckInput, p as ExtensionPackRef, r as AdapterPackRef, s as ContractComponentRequirementsCheckResult, t as AdapterDescriptor, u as DriverPackRef, v as TargetBoundComponentDescriptor, x as TargetPackRef, y as TargetDescriptor } from "./framework-components-D1rRo9Oa.mjs"; | ||
| export { type AdapterDescriptor, type AdapterInstance, type AdapterPackRef, type CapabilityMatrix, type ComponentDescriptor, type ComponentMetadata, type ContractComponentRequirementsCheckInput, type ContractComponentRequirementsCheckResult, type DriverDescriptor, type DriverInstance, type DriverPackRef, type ExtensionDescriptor, type ExtensionInstance, type ExtensionPackRef, type FamilyDescriptor, type FamilyInstance, type FamilyPackRef, type PackRefBase, type TargetBoundComponentDescriptor, type TargetDescriptor, type TargetInstance, type TargetPackRef, checkContractComponentRequirements, mergeCapabilityMatrices }; |
+1
-63
@@ -0,65 +1,3 @@ | ||
| import { t as mergeCapabilityMatrices } from "./capabilities-BnRAFKP5.mjs"; | ||
| import { t as checkContractComponentRequirements } from "./framework-components-DbCS57go.mjs"; | ||
| import { blindCast } from "@prisma-next/utils/casts"; | ||
| //#region src/shared/capabilities.ts | ||
| /** | ||
| * Capability matrix merge primitive shared by emit-time and runtime stack composition. | ||
| * | ||
| * The CLI's `enrichContract` and the SQL runtime's `createExecutionContext` both need | ||
| * to fold a stack of component descriptors' `capabilities` declarations into a single | ||
| * matrix keyed by namespace. Keeping the primitive here lets both call sites stay | ||
| * byte-for-byte consistent without one depending on the other. | ||
| */ | ||
| function isPlainObject(value) { | ||
| return typeof value === "object" && value !== null && !Array.isArray(value); | ||
| } | ||
| function sortDeep(value) { | ||
| if (Array.isArray(value)) return value.map(sortDeep); | ||
| if (!isPlainObject(value)) return value; | ||
| const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b)); | ||
| const next = {}; | ||
| for (const [key, child] of entries) next[key] = sortDeep(child); | ||
| return next; | ||
| } | ||
| function extractCapabilityMatrix(value) { | ||
| if (!isPlainObject(value)) return {}; | ||
| const out = {}; | ||
| for (const [namespace, maybeCaps] of Object.entries(value)) { | ||
| if (!isPlainObject(maybeCaps)) continue; | ||
| const caps = {}; | ||
| for (const [key, flag] of Object.entries(maybeCaps)) if (typeof flag === "boolean") caps[key] = flag; | ||
| if (Object.keys(caps).length > 0) out[namespace] = caps; | ||
| } | ||
| return out; | ||
| } | ||
| /** | ||
| * Merge an ordered list of contributor capability declarations into a base matrix. | ||
| * | ||
| * Behaviour: | ||
| * - `base` and each contributor's `capabilities` are filtered through the same | ||
| * structural extraction: non-plain-object namespace blocks are dropped, | ||
| * non-boolean leaves inside a namespace block are dropped, and a namespace | ||
| * block that ends up with zero boolean leaves is omitted entirely (so a | ||
| * later contributor with a malformed namespace cannot erase a namespace | ||
| * already present in `base`). | ||
| * - Non-plain-object `capabilities` on a contributor (including `undefined`, | ||
| * `null`, arrays, primitives) are skipped silently — the contributor | ||
| * contributes nothing. | ||
| * - Later contributors win on `(namespace, key)` collisions. | ||
| * - The returned object is fresh — neither `base` nor any contributor is mutated. | ||
| * - Output keys are sorted lexicographically at every plain-object level. | ||
| */ | ||
| function mergeCapabilityMatrices(base, contributors) { | ||
| const merged = extractCapabilityMatrix(base); | ||
| for (const contributor of contributors) { | ||
| const extracted = extractCapabilityMatrix(contributor.capabilities); | ||
| for (const [namespace, capabilities] of Object.entries(extracted)) merged[namespace] = { | ||
| ...merged[namespace] ?? {}, | ||
| ...capabilities | ||
| }; | ||
| } | ||
| return blindCast(sortDeep(merged)); | ||
| } | ||
| //#endregion | ||
| export { checkContractComponentRequirements, mergeCapabilityMatrices }; | ||
| //# sourceMappingURL=components.mjs.map |
+395
-269
@@ -1,7 +0,8 @@ | ||
| import { o as CodecRegistry } from "./codec-types-yY3eSmi0.mjs"; | ||
| import { d as AuthoringFieldNamespace, h as AuthoringPslBlockDescriptorNamespace, i as AuthoringContributions, l as AuthoringEntityTypeNamespace, y as AuthoringTypeNamespace } from "./framework-authoring-CJC4jwGo.mjs"; | ||
| import { A as LoweredDefaultResult, C as ControlMutationDefaultEntry, D as DefaultFunctionLoweringHandler, E as DefaultFunctionLoweringContext, F as SourceSpan, M as MutationDefaultGeneratorDescriptor, N as ParsedDefaultFunctionCall, O as DefaultFunctionRegistry, P as SourceDiagnostic, T as ControlMutationDefaults, a as ComponentMetadata, b as TargetInstance, c as DriverDescriptor, d as ExtensionDescriptor, f as ExtensionInstance, h as FamilyInstance, j as LoweredDefaultValue, k as DefaultFunctionRegistryEntry, l as DriverInstance, m as FamilyDescriptor, n as AdapterInstance, t as AdapterDescriptor, v as TargetBoundComponentDescriptor, w as ControlMutationDefaultRegistry, y as TargetDescriptor } from "./framework-components-5hA9ij1v.mjs"; | ||
| import { o as CodecRegistry } from "./codec-types-e32YHT3D.mjs"; | ||
| import { d as AuthoringFieldNamespace, g as AuthoringModelAttributeDescriptorNamespace, i as AuthoringContributions, l as AuthoringEntityTypeNamespace, w as AuthoringTypeNamespace, y as AuthoringPslBlockDescriptorNamespace } from "./framework-authoring-DEadmUb3.mjs"; | ||
| import { t as CapabilityMatrix } from "./capabilities-Cupq4-1-.mjs"; | ||
| import { A as SourceDiagnostic, C as ControlMutationDefaultEntry, D as LoweredDefaultResult, E as DefaultFunctionLoweringContext, M as TypedDefaultFunctionCall, O as LoweredDefaultValue, T as ControlMutationDefaults, a as ComponentMetadata, b as TargetInstance, c as DriverDescriptor, d as ExtensionDescriptor, f as ExtensionInstance, h as FamilyInstance, j as SourceSpan, k as MutationDefaultGeneratorDescriptor, l as DriverInstance, m as FamilyDescriptor, n as AdapterInstance, t as AdapterDescriptor, v as TargetBoundComponentDescriptor, w as ControlMutationDefaultRegistry, y as TargetDescriptor } from "./framework-components-D1rRo9Oa.mjs"; | ||
| import { t as TypesImportSpec } from "./types-import-spec-DRKzrJ20.mjs"; | ||
| import { t as EmissionSpi } from "./emission-types-C561PwcN.mjs"; | ||
| import { m as PslDocumentAst } from "./psl-ast-B-C_9dWr.mjs"; | ||
| import { t as EmissionSpi } from "./emission-types-BQMFUNQO.mjs"; | ||
| import { m as PslDocumentAst } from "./psl-ast-jgAyMeUx.mjs"; | ||
| import { Contract, ContractMarkerRecord, ControlPolicy, LedgerEntryRecord } from "@prisma-next/contract/types"; | ||
@@ -71,3 +72,62 @@ import { ImportRequirement, ImportRequirement as ImportRequirement$1 } from "@prisma-next/ts-render"; | ||
| //#endregion | ||
| //#region src/control/control-result-types.d.ts | ||
| //#region src/control/schema-diff.d.ts | ||
| interface SchemaDiffIssue<TNode extends DiffableNode = DiffableNode> { | ||
| /** Path from the root node down to the diffed node, as a sequence of local keys. */ | ||
| readonly path: readonly string[]; | ||
| /** Why the actual state fails the expectation. Consumers filter on this field. */ | ||
| readonly reason: ExpectationFailureReason; | ||
| /** The expected (desired-side) node, when available. Absent for `not-expected` issues. */ | ||
| readonly expected?: TNode; | ||
| /** The actual (current-side) node, when available. Absent for `not-found` issues. */ | ||
| readonly actual?: TNode; | ||
| } | ||
| /** | ||
| * A node in the schema tree. Every node in the tree implements this interface. | ||
| * | ||
| * The differ pairs siblings by the combination of `nodeKind` and `id`, not by | ||
| * `id` alone: `id` needs only be unique among siblings of the same | ||
| * `nodeKind` at the same level, not globally unique at that level. Two | ||
| * distinct kinds of child in distinct slots (e.g. a role and a namespace) may | ||
| * legitimately share a name — they are never paired against each other, so | ||
| * the collision is harmless. A node never folds its kind into its id string | ||
| * to route around this; `nodeKind` is the discriminant that does that job. | ||
| * A same-`nodeKind`/same-`id` collision among siblings is a genuine | ||
| * duplicate and is enforced by a throw. The differ accumulates ids (not | ||
| * nodeKind) into a path that stamps every emitted issue. | ||
| */ | ||
| interface DiffableNode { | ||
| readonly id: string; | ||
| readonly nodeKind: string; | ||
| isEqualTo(other: DiffableNode): boolean; | ||
| children(): readonly DiffableNode[]; | ||
| } | ||
| /** | ||
| * Diff two schema trees starting from their roots. | ||
| * | ||
| * The differ is **total**: every node-level difference is reported. An unmatched | ||
| * non-leaf node emits its own issue and descends, emitting an issue for every | ||
| * node in the missing/extra subtree. Coalescing a parent change over its | ||
| * children is the planner's responsibility. Ownership filtering (dropping `extra` | ||
| * issues in namespaces a contract doesn't own) is the caller's responsibility. | ||
| */ | ||
| declare function diffSchemas(expected: DiffableNode, actual: DiffableNode): readonly SchemaDiffIssue[]; | ||
| /** | ||
| * The result of diffing a contract's expected schema against the introspected | ||
| * actual schema: one node-typed issue list. Carries no verdict, verification | ||
| * tree, or counts — those are the verifier's own presentation, built from the | ||
| * same underlying comparison. | ||
| * | ||
| * `TNode` is the concrete schema-IR node the issues carry; it defaults to | ||
| * `DiffableNode`, so this is purely additive — a caller that wants the | ||
| * concrete node opts in (the Postgres planner uses the concrete node type), | ||
| * everyone else keeps the default unchanged. | ||
| */ | ||
| declare class SchemaDiff<TNode extends DiffableNode = DiffableNode> { | ||
| readonly issues: readonly SchemaDiffIssue<TNode>[]; | ||
| constructor(issues: readonly SchemaDiffIssue<TNode>[]); | ||
| /** Returns a new `SchemaDiff` narrowed to the issues `keep` returns true for. */ | ||
| filter(keep: (issue: SchemaDiffIssue<TNode>) => boolean): SchemaDiff<TNode>; | ||
| } | ||
| //#endregion | ||
| //#region src/control/control-operation-results.d.ts | ||
| declare const VERIFY_CODE_MARKER_MISSING = "PN-RUN-3001"; | ||
@@ -108,53 +168,27 @@ declare const VERIFY_CODE_HASH_MISMATCH = "PN-RUN-3002"; | ||
| } | ||
| interface BaseSchemaIssue { | ||
| readonly kind: 'missing_schema' | 'missing_table' | 'missing_column' | 'extra_table' | 'extra_column' | 'extra_primary_key' | 'extra_foreign_key' | 'extra_unique_constraint' | 'extra_index' | 'extra_validator' | 'type_mismatch' | 'type_missing' | 'type_values_mismatch' | 'nullability_mismatch' | 'primary_key_mismatch' | 'foreign_key_mismatch' | 'unique_constraint_mismatch' | 'index_mismatch' | 'default_missing' | 'default_mismatch' | 'extra_default' | 'check_missing' | 'check_removed' | 'check_mismatch'; | ||
| readonly table?: string; | ||
| /** | ||
| * Namespace coordinate of the issue's subject (e.g. the schema a SQL | ||
| * table lives in). Populated by family verifiers that have the | ||
| * coordinate in scope when constructing the issue; absent for issues | ||
| * whose family has no namespace concept (e.g. Mongo collections) or | ||
| * whose subject isn't in any contract namespace (e.g. an extra-table | ||
| * issue raised for a table that exists in the live DB but not in the | ||
| * contract). | ||
| * | ||
| * Downstream planners trust this field as the authoritative subject | ||
| * coordinate and do not re-derive it by name lookup. A finer-grained | ||
| * structural split between framework-shared and family-specific issue | ||
| * fields is tracked under a follow-up ticket. | ||
| */ | ||
| readonly namespaceId?: string; | ||
| readonly column?: string; | ||
| readonly indexOrConstraint?: string; | ||
| readonly typeName?: string; | ||
| readonly expected?: string; | ||
| readonly actual?: string; | ||
| readonly message: string; | ||
| } | ||
| interface EnumValuesChangedIssue { | ||
| readonly kind: 'enum_values_changed'; | ||
| /** | ||
| * Namespace coordinate of the enum type that changed values. Populated by | ||
| * family verifiers that have the coordinate in scope when constructing the | ||
| * issue. Downstream planners trust this field as the authoritative subject | ||
| * coordinate and do not re-derive it by name lookup. | ||
| */ | ||
| readonly namespaceId: string; | ||
| readonly typeName: string; | ||
| readonly addedValues: readonly string[]; | ||
| readonly removedValues: readonly string[]; | ||
| readonly message: string; | ||
| } | ||
| type SchemaIssue = BaseSchemaIssue | EnumValuesChangedIssue; | ||
| interface SchemaVerificationNode { | ||
| readonly status: 'pass' | 'warn' | 'fail'; | ||
| readonly kind: string; | ||
| readonly name: string; | ||
| readonly contractPath: string; | ||
| readonly code: string; | ||
| readonly message: string; | ||
| readonly expected: unknown; | ||
| readonly actual: unknown; | ||
| readonly children: readonly SchemaVerificationNode[]; | ||
| } | ||
| /** | ||
| * The three ways an actual state can fail an expectation: it contains a node | ||
| * that was not expected, lacks a node that was expected, or holds a node that | ||
| * is not equal to the expected one. Expected is the desired side and actual the | ||
| * current side of whatever comparison produced the issue — contract-vs-database, | ||
| * or contract-vs-contract in an offline plan — so the vocabulary is | ||
| * comparison-relative and never ambiguous about a base. | ||
| * | ||
| * The failure reason is a structural characteristic carried as a declared | ||
| * field: consumers filter on `reason`, never by enumerating kind strings or | ||
| * family-invented node codes. | ||
| */ | ||
| type ExpectationFailureReason = 'not-expected' | 'not-found' | 'not-equal'; | ||
| /** | ||
| * The issue-based schema-verify result. `ok` derives from the FAILURE list | ||
| * only: a verify passes exactly when `schema.issues` is empty, post | ||
| * strict-gating and control-policy disposition. | ||
| * | ||
| * `schema.warnings` carries warn-graded issues (an `observed`-policy | ||
| * subject's drift, and any other `warn` disposition) in the same shape. | ||
| * Warnings are informational — they never affect `ok` — but they MUST be | ||
| * surfaced: an `observed` table that drifted yields `ok: true` with a | ||
| * non-empty warnings channel, which is what distinguishes "watch without | ||
| * failing" from full suppression. | ||
| */ | ||
| interface VerifyDatabaseSchemaResult { | ||
@@ -173,9 +207,5 @@ readonly ok: boolean; | ||
| readonly schema: { | ||
| readonly issues: readonly SchemaIssue[]; | ||
| readonly root: SchemaVerificationNode; | ||
| readonly counts: { | ||
| readonly pass: number; | ||
| readonly warn: number; | ||
| readonly fail: number; | ||
| readonly totalNodes: number; | ||
| readonly issues: readonly SchemaDiffIssue[]; | ||
| readonly warnings?: { | ||
| readonly issues: readonly SchemaDiffIssue[]; | ||
| }; | ||
@@ -262,10 +292,9 @@ }; | ||
| /** | ||
| * Verify a contract against an already-introspected schema slice. | ||
| * Verify a contract against an already-introspected schema. | ||
| * | ||
| * Callers that need to verify against the live database compose | ||
| * {@link introspect} + `verifySchema` directly; the family | ||
| * interface deliberately exposes the introspection step so callers | ||
| * can pre-project the schema (e.g. the aggregate verifier projects | ||
| * each member's claimed slice via | ||
| * {@link import('@prisma-next/migration-tools/aggregate').projectSchemaToSpace}). | ||
| * {@link introspect} + `verifySchema` directly. The aggregate verifier | ||
| * verifies each member against the full introspected schema and scopes the | ||
| * result to that member's contract space afterwards — it never prunes the | ||
| * schema up front. | ||
| * | ||
@@ -337,116 +366,2 @@ * Synchronous — no I/O. Idempotent. | ||
| //#endregion | ||
| //#region src/control/control-stack.d.ts | ||
| interface AssembledAuthoringContributions { | ||
| readonly field: AuthoringFieldNamespace; | ||
| readonly type: AuthoringTypeNamespace; | ||
| readonly entityTypes: AuthoringEntityTypeNamespace; | ||
| readonly pslBlockDescriptors: AuthoringPslBlockDescriptorNamespace; | ||
| } | ||
| interface ControlStack<TFamilyId extends string = string, TTargetId extends string = string> { | ||
| readonly family: ControlFamilyDescriptor<TFamilyId>; | ||
| readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>; | ||
| readonly adapter?: ControlAdapterDescriptor<TFamilyId, TTargetId> | undefined; | ||
| readonly driver?: ControlDriverDescriptor<TFamilyId, TTargetId> | undefined; | ||
| readonly extensionPacks: readonly ControlExtensionDescriptor<TFamilyId, TTargetId>[]; | ||
| readonly codecTypeImports: ReadonlyArray<TypesImportSpec>; | ||
| readonly queryOperationTypeImports: ReadonlyArray<TypesImportSpec>; | ||
| readonly extensionIds: ReadonlyArray<string>; | ||
| readonly codecLookup: CodecRegistry; | ||
| readonly authoringContributions: AssembledAuthoringContributions; | ||
| readonly scalarTypeDescriptors: ReadonlyMap<string, string>; | ||
| readonly controlMutationDefaults: ControlMutationDefaults; | ||
| } | ||
| interface CreateControlStackInput<TFamilyId extends string = string, TTargetId extends string = string> { | ||
| readonly family: ControlFamilyDescriptor<TFamilyId>; | ||
| readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>; | ||
| readonly adapter?: ControlAdapterDescriptor<TFamilyId, TTargetId> | undefined; | ||
| readonly driver?: ControlDriverDescriptor<TFamilyId, TTargetId> | undefined; | ||
| readonly extensionPacks?: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>> | undefined; | ||
| } | ||
| declare function assertUniqueCodecOwner(options: { | ||
| readonly codecId: string; | ||
| readonly owners: Map<string, string>; | ||
| readonly descriptorId: string; | ||
| readonly entityLabel: string; | ||
| readonly entityOwnershipLabel: string; | ||
| }): void; | ||
| declare function extractCodecTypeImports(descriptors: ReadonlyArray<Pick<ComponentMetadata, 'types'>>): ReadonlyArray<TypesImportSpec>; | ||
| declare function extractQueryOperationTypeImports(descriptors: ReadonlyArray<Pick<ComponentMetadata, 'types'>>): ReadonlyArray<TypesImportSpec>; | ||
| declare function extractComponentIds(family: { | ||
| readonly id: string; | ||
| }, target: { | ||
| readonly id: string; | ||
| }, adapter: { | ||
| readonly id: string; | ||
| } | undefined, extensions: ReadonlyArray<{ | ||
| readonly id: string; | ||
| }>): ReadonlyArray<string>; | ||
| declare function assembleAuthoringContributions(descriptors: ReadonlyArray<{ | ||
| readonly authoring?: AuthoringContributions; | ||
| }>): AssembledAuthoringContributions; | ||
| declare function assembleScalarTypeDescriptors(descriptors: ReadonlyArray<Pick<ComponentMetadata, 'scalarTypeDescriptors'> & { | ||
| readonly id?: string; | ||
| }>): ReadonlyMap<string, string>; | ||
| declare function assembleControlMutationDefaults(descriptors: ReadonlyArray<Pick<ComponentMetadata, 'controlMutationDefaults'> & { | ||
| readonly id?: string; | ||
| }>): ControlMutationDefaults; | ||
| declare function extractCodecLookup(descriptors: ReadonlyArray<Pick<ComponentMetadata & { | ||
| id: string; | ||
| }, 'types' | 'id'>>): CodecRegistry; | ||
| interface DependencyDeclaringDescriptor { | ||
| readonly id: string; | ||
| readonly contractSpace?: { | ||
| readonly contractJson?: { | ||
| readonly extensionPacks?: Readonly<Record<string, unknown>>; | ||
| }; | ||
| }; | ||
| } | ||
| /** | ||
| * Builds a dependency-respecting load order for the given extension descriptors | ||
| * using Kahn's topological sort algorithm. Dependencies (packs declared in | ||
| * `contractSpace.contractJson.extensionPacks`) are placed before the extensions | ||
| * that depend on them. | ||
| * | ||
| * Throws if the dependency graph contains a cycle, with an error message that | ||
| * names every extension involved in the cycle. | ||
| * | ||
| * Throws if any extension declares a dependency on a pack ID that is not present | ||
| * in the provided list — add the missing pack to the `extensionPacks` list to | ||
| * resolve the error. | ||
| */ | ||
| declare function buildExtensionLoadOrder(extensions: ReadonlyArray<DependencyDeclaringDescriptor>): readonly string[]; | ||
| declare function createControlStack<TFamilyId extends string, TTargetId extends string>(input: CreateControlStackInput<TFamilyId, TTargetId>): ControlStack<TFamilyId, TTargetId>; | ||
| //#endregion | ||
| //#region src/control/control-descriptors.d.ts | ||
| interface ControlFamilyDescriptor<TFamilyId extends string, TFamilyInstance extends ControlFamilyInstance<TFamilyId, unknown> = ControlFamilyInstance<TFamilyId, unknown>> extends FamilyDescriptor<TFamilyId> { | ||
| readonly emission: EmissionSpi; | ||
| create<TTargetId extends string>(stack: ControlStack<TFamilyId, TTargetId>): TFamilyInstance; | ||
| } | ||
| interface ControlTargetDescriptor<TFamilyId extends string, TTargetId extends string, TTargetInstance extends ControlTargetInstance<TFamilyId, TTargetId> = ControlTargetInstance<TFamilyId, TTargetId>, TContract extends Contract = Contract> extends TargetDescriptor<TFamilyId, TTargetId> { | ||
| /** | ||
| * JSON ⇄ class boundary for this target's contract. Every target | ||
| * ships the SPI: framework consumers reach the serializer through | ||
| * `descriptor.contractSerializer` rather than importing a per-target | ||
| * `deserializeContract` helper. The descriptor IS the aggregator. | ||
| */ | ||
| readonly contractSerializer: ContractSerializer<TContract>; | ||
| create(): TTargetInstance; | ||
| } | ||
| interface ControlAdapterDescriptor<TFamilyId extends string, TTargetId extends string, TAdapterInstance extends ControlAdapterInstance<TFamilyId, TTargetId> = ControlAdapterInstance<TFamilyId, TTargetId>> extends AdapterDescriptor<TFamilyId, TTargetId> { | ||
| /** | ||
| * Construct a control adapter instance for this stack. | ||
| * | ||
| * The `stack` argument mirrors `ControlFamilyDescriptor.create(stack)`: | ||
| * adapter implementations may inspect `stack.codecLookup`, extension packs, | ||
| * or other assembled metadata when constructing the instance. | ||
| */ | ||
| create(stack: ControlStack<TFamilyId, TTargetId>): TAdapterInstance; | ||
| } | ||
| interface ControlDriverDescriptor<TFamilyId extends string, TTargetId extends string, TDriverInstance extends ControlDriverInstance<TFamilyId, TTargetId> = ControlDriverInstance<TFamilyId, TTargetId>, TConnection = string> extends DriverDescriptor<TFamilyId, TTargetId> { | ||
| create(connection: TConnection): Promise<TDriverInstance>; | ||
| } | ||
| interface ControlExtensionDescriptor<TFamilyId extends string, TTargetId extends string, TExtensionInstance extends ControlExtensionInstance<TFamilyId, TTargetId> = ControlExtensionInstance<TFamilyId, TTargetId>> extends ExtensionDescriptor<TFamilyId, TTargetId> { | ||
| create(): TExtensionInstance; | ||
| } | ||
| //#endregion | ||
| //#region src/control/control-migration-types.d.ts | ||
@@ -742,2 +657,49 @@ /** | ||
| /** | ||
| * The canonical schema-IR entity coordinate: which namespace, which kind of | ||
| * entity, and which name. A bare entity name is not a unique identity — | ||
| * two namespaces can each declare an entity of the same name, and one | ||
| * namespace can declare two different-kind entities that share a name — so | ||
| * every schema-IR consumer that addresses one live or declared entity does | ||
| * it by this full triple. | ||
| * | ||
| * `entityKind` uses the same vocabulary as the contract storage's `entries` | ||
| * dictionary — the same vocabulary | ||
| * {@link import('../ir/storage').elementCoordinates} walks. This type has no | ||
| * `plane`: schema IR is storage-only (contract IR spans domain and storage, | ||
| * which is why its own coordinate type carries a plane), so a plane field | ||
| * here would always read `'storage'` and say nothing. | ||
| */ | ||
| interface SchemaEntityCoordinate { | ||
| readonly namespaceId: string; | ||
| readonly entityKind: string; | ||
| readonly entityName: string; | ||
| } | ||
| /** | ||
| * Contract-space ownership query the planner consults while planning one | ||
| * space against a live database. | ||
| * | ||
| * A live schema node the planned space does not own surfaces from the diff | ||
| * as `not-expected` (an extra). Before treating such a node as this plan's | ||
| * to drop, the planner asks the ownership oracle whether *any* contract | ||
| * space in the composition declares it: a node another (sibling) space owns | ||
| * is not an orphan, so it is left untouched; a node no space owns is a | ||
| * genuine extra the planner may drop under a destructive policy. (A node the | ||
| * planned space itself owns is in its expected tree and never surfaces as an | ||
| * extra, so a positive answer always means a sibling.) | ||
| * | ||
| * The oracle is a real domain object — the passive | ||
| * {@link import('@prisma-next/migration-tools/aggregate').ContractSpaceAggregate}, | ||
| * which answers this from its loaded contract spaces. The planner holds no | ||
| * list of other spaces' names and no ownership rules of its own; it only | ||
| * asks. Single-space plans (offline `migration plan`) pass an aggregate of | ||
| * one — the same path, no special-casing. | ||
| */ | ||
| interface SchemaOwnership { | ||
| /** | ||
| * True when some contract space in the composition declares a storage | ||
| * entity at this coordinate. | ||
| */ | ||
| declaresEntity(coordinate: SchemaEntityCoordinate): boolean; | ||
| } | ||
| /** | ||
| * Migration planner interface for planning schema changes. | ||
@@ -784,2 +746,12 @@ * This is the minimal interface that CLI commands use. | ||
| readonly spaceId: string; | ||
| /** | ||
| * Ownership oracle over the whole contract-space composition (the | ||
| * passive aggregate). The planner asks it, per live extra node, whether | ||
| * any space declares that entity: a sibling-owned node is left | ||
| * untouched, an unowned node is a genuine extra. The planner holds no | ||
| * list of other spaces' names — ownership lives in the aggregate; it | ||
| * only asks. Absent for a single-space plan handed no aggregate. | ||
| * See {@link SchemaOwnership}. | ||
| */ | ||
| readonly ownership?: SchemaOwnership; | ||
| }): MigrationPlannerResult; | ||
@@ -847,2 +819,3 @@ /** | ||
| readonly operationCount: number; | ||
| readonly destinationContractJson?: unknown; | ||
| }>; | ||
@@ -919,2 +892,207 @@ } | ||
| //#endregion | ||
| //#region src/control/control-spaces.d.ts | ||
| /** | ||
| * Canonical control-plane identifiers for contract spaces. | ||
| * | ||
| * A contract space is the disjoint `(contract.json, migration-graph)` unit | ||
| * the per-space planner / runner / verifier (project: extension contract | ||
| * spaces, TML-2397) operates on. The application owns one well-known | ||
| * space — the value below — and each loaded extension that contributes | ||
| * schema owns a uniquely-named space. | ||
| * | ||
| * Lives in `framework-components/control` so every layer that has to | ||
| * reason about space identity (the migration tooling, the SQL runtime's | ||
| * marker reader, target-side statement builders, target-side adapters) | ||
| * can import a single value rather than duplicating the literal. Raw | ||
| * `'app'` string literals in framework / target / runtime / adapter | ||
| * source code are forbidden and policed by | ||
| * `scripts/lint-app-space-id.mjs` (wired into `pnpm lint:deps`). | ||
| * | ||
| * @see specs/framework-mechanism.spec.md § 3 — Layout convention (γ). | ||
| */ | ||
| declare const APP_SPACE_ID: "app"; | ||
| /** | ||
| * Head ref for a contract space — the `(hash, invariants)` tuple | ||
| * a runner targets when applying that space's migration graph. Identical | ||
| * in shape to the on-disk `migrations/<space-id>/refs/head.json` the | ||
| * framework writes per loaded extension, and to the app-space | ||
| * `<projectRoot>/refs/head.json`. Family-agnostic: SQL, Mongo, and any | ||
| * future family share the same head-ref shape. | ||
| * | ||
| * @see specs/framework-mechanism.spec.md § 1. | ||
| */ | ||
| interface ContractSpaceHeadRef { | ||
| readonly hash: string; | ||
| readonly invariants: readonly string[]; | ||
| } | ||
| /** | ||
| * Canonical structural shape of a migration package — the unit a planner | ||
| * produces and a runner consumes: a directory name, the metadata | ||
| * envelope, and the operation list. | ||
| * | ||
| * In-memory by default. Readers in `@prisma-next/migration-tools` | ||
| * (`readMigrationPackage` / `readMigrationsDir`) return the augmented | ||
| * {@link import('@prisma-next/migration-tools/package').OnDiskMigrationPackage} | ||
| * variant which adds `dirPath`; everything else operates against the | ||
| * canonical shape so the same value flows through pre-emission | ||
| * authoring, on-disk loading, and runner execution without conversion. | ||
| * | ||
| * @see specs/framework-mechanism.spec.md § 1. | ||
| */ | ||
| interface MigrationPackage { | ||
| readonly dirName: string; | ||
| readonly metadata: MigrationMetadata; | ||
| readonly ops: readonly MigrationPlanOperation[]; | ||
| /** | ||
| * Contract IR JSON of this migration's destination state, populated by | ||
| * the on-disk readers from the sibling `end-contract.json` file when | ||
| * present (raw parsed JSON). Absent for packages loaded without the | ||
| * snapshot file — the runner never requires it (see ADR 199: identity | ||
| * is anchored on the storage-hash bookends). The edge's *start* state | ||
| * is deliberately not carried: it is by construction the end state of | ||
| * the predecessor edge, so consumers derive it from the previous row. | ||
| */ | ||
| readonly endContractJson?: unknown; | ||
| } | ||
| /** | ||
| * Canonical structural shape of a contract space — one disjoint | ||
| * `(contractJson, migration-graph)` unit the per-space planner / runner | ||
| * / verifier operates on. The application owns one well-known space | ||
| * ({@link APP_SPACE_ID}); each loaded extension that contributes schema | ||
| * owns a uniquely-named space. Whether a value is the app's space or an | ||
| * extension's space is a control-plane concern; the type carries no | ||
| * such distinction. | ||
| * | ||
| * Generic over the contract so each family pins a typed contract value | ||
| * at consumption time. The SQL family specialises to | ||
| * `ContractSpace<Contract<SqlStorage>>` at the descriptor surface; | ||
| * Mongo's symmetrical `ContractSpace<Contract<MongoStorage>>` will land | ||
| * with that family. | ||
| * | ||
| * @see specs/framework-mechanism.spec.md § 1. | ||
| */ | ||
| interface ContractSpace<TContract extends Contract = Contract> { | ||
| readonly contractJson: TContract; | ||
| readonly migrations: readonly MigrationPackage[]; | ||
| readonly headRef: ContractSpaceHeadRef; | ||
| } | ||
| //#endregion | ||
| //#region src/control/control-stack.d.ts | ||
| interface AssembledAuthoringContributions { | ||
| readonly field: AuthoringFieldNamespace; | ||
| readonly type: AuthoringTypeNamespace; | ||
| readonly entityTypes: AuthoringEntityTypeNamespace; | ||
| readonly pslBlockDescriptors: AuthoringPslBlockDescriptorNamespace; | ||
| readonly modelAttributes: AuthoringModelAttributeDescriptorNamespace; | ||
| } | ||
| interface ControlStack<TFamilyId extends string = string, TTargetId extends string = string> { | ||
| readonly family: ControlFamilyDescriptor<TFamilyId>; | ||
| readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>; | ||
| readonly adapter?: ControlAdapterDescriptor<TFamilyId, TTargetId> | undefined; | ||
| readonly driver?: ControlDriverDescriptor<TFamilyId, TTargetId> | undefined; | ||
| readonly extensionPacks: readonly ControlExtensionDescriptor<TFamilyId, TTargetId>[]; | ||
| readonly extensionContracts: ReadonlyMap<string, Contract>; | ||
| readonly codecTypeImports: ReadonlyArray<TypesImportSpec>; | ||
| readonly queryOperationTypeImports: ReadonlyArray<TypesImportSpec>; | ||
| readonly extensionIds: ReadonlyArray<string>; | ||
| readonly codecLookup: CodecRegistry; | ||
| readonly authoringContributions: AssembledAuthoringContributions; | ||
| readonly scalarTypeDescriptors: ReadonlyMap<string, string>; | ||
| readonly controlMutationDefaults: ControlMutationDefaults; | ||
| readonly capabilities: CapabilityMatrix; | ||
| } | ||
| interface CreateControlStackInput<TFamilyId extends string = string, TTargetId extends string = string> { | ||
| readonly family: ControlFamilyDescriptor<TFamilyId>; | ||
| readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>; | ||
| readonly adapter?: ControlAdapterDescriptor<TFamilyId, TTargetId> | undefined; | ||
| readonly driver?: ControlDriverDescriptor<TFamilyId, TTargetId> | undefined; | ||
| readonly extensionPacks?: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>> | undefined; | ||
| } | ||
| declare function assertUniqueCodecOwner(options: { | ||
| readonly codecId: string; | ||
| readonly owners: Map<string, string>; | ||
| readonly descriptorId: string; | ||
| readonly entityLabel: string; | ||
| readonly entityOwnershipLabel: string; | ||
| }): void; | ||
| declare function extractCodecTypeImports(descriptors: ReadonlyArray<Pick<ComponentMetadata, 'types'>>): ReadonlyArray<TypesImportSpec>; | ||
| declare function extractQueryOperationTypeImports(descriptors: ReadonlyArray<Pick<ComponentMetadata, 'types'>>): ReadonlyArray<TypesImportSpec>; | ||
| declare function extractComponentIds(family: { | ||
| readonly id: string; | ||
| }, target: { | ||
| readonly id: string; | ||
| }, adapter: { | ||
| readonly id: string; | ||
| } | undefined, extensions: ReadonlyArray<{ | ||
| readonly id: string; | ||
| }>): ReadonlyArray<string>; | ||
| declare function assembleAuthoringContributions(descriptors: ReadonlyArray<{ | ||
| readonly authoring?: AuthoringContributions; | ||
| }>): AssembledAuthoringContributions; | ||
| declare function assembleScalarTypeDescriptors(descriptors: ReadonlyArray<Pick<ComponentMetadata, 'scalarTypeDescriptors'> & { | ||
| readonly id?: string; | ||
| }>): ReadonlyMap<string, string>; | ||
| declare function assembleControlMutationDefaults(descriptors: ReadonlyArray<Pick<ComponentMetadata, 'controlMutationDefaults'> & { | ||
| readonly id?: string; | ||
| }>): ControlMutationDefaults; | ||
| declare function extractCodecLookup(descriptors: ReadonlyArray<Pick<ComponentMetadata & { | ||
| id: string; | ||
| }, 'types' | 'id'>>): CodecRegistry; | ||
| interface DependencyDeclaringDescriptor { | ||
| readonly id: string; | ||
| readonly contractSpace?: { | ||
| readonly contractJson?: { | ||
| readonly extensionPacks?: Readonly<Record<string, unknown>>; | ||
| }; | ||
| }; | ||
| } | ||
| /** | ||
| * Builds a dependency-respecting load order for the given extension descriptors | ||
| * using Kahn's topological sort algorithm. Dependencies (packs declared in | ||
| * `contractSpace.contractJson.extensionPacks`) are placed before the extensions | ||
| * that depend on them. | ||
| * | ||
| * Throws if the dependency graph contains a cycle, with an error message that | ||
| * names every extension involved in the cycle. | ||
| * | ||
| * Throws if any extension declares a dependency on a pack ID that is not present | ||
| * in the provided list — add the missing pack to the `extensionPacks` list to | ||
| * resolve the error. | ||
| */ | ||
| declare function buildExtensionLoadOrder(extensions: ReadonlyArray<DependencyDeclaringDescriptor>): readonly string[]; | ||
| declare function createControlStack<TFamilyId extends string, TTargetId extends string>(input: CreateControlStackInput<TFamilyId, TTargetId>): ControlStack<TFamilyId, TTargetId>; | ||
| //#endregion | ||
| //#region src/control/control-descriptors.d.ts | ||
| interface ControlFamilyDescriptor<TFamilyId extends string, TFamilyInstance extends ControlFamilyInstance<TFamilyId, unknown> = ControlFamilyInstance<TFamilyId, unknown>> extends FamilyDescriptor<TFamilyId> { | ||
| readonly emission: EmissionSpi; | ||
| create<TTargetId extends string>(stack: ControlStack<TFamilyId, TTargetId>): TFamilyInstance; | ||
| } | ||
| interface ControlTargetDescriptor<TFamilyId extends string, TTargetId extends string, TTargetInstance extends ControlTargetInstance<TFamilyId, TTargetId> = ControlTargetInstance<TFamilyId, TTargetId>, TContract extends Contract = Contract> extends TargetDescriptor<TFamilyId, TTargetId> { | ||
| /** | ||
| * JSON ⇄ class boundary for this target's contract. Every target | ||
| * ships the SPI: framework consumers reach the serializer through | ||
| * `descriptor.contractSerializer` rather than importing a per-target | ||
| * `deserializeContract` helper. The descriptor IS the aggregator. | ||
| */ | ||
| readonly contractSerializer: ContractSerializer<TContract>; | ||
| create(): TTargetInstance; | ||
| } | ||
| interface ControlAdapterDescriptor<TFamilyId extends string, TTargetId extends string, TAdapterInstance extends ControlAdapterInstance<TFamilyId, TTargetId> = ControlAdapterInstance<TFamilyId, TTargetId>> extends AdapterDescriptor<TFamilyId, TTargetId> { | ||
| /** | ||
| * Construct a control adapter instance for this stack. | ||
| * | ||
| * The `stack` argument mirrors `ControlFamilyDescriptor.create(stack)`: | ||
| * adapter implementations may inspect `stack.codecLookup`, extension packs, | ||
| * or other assembled metadata when constructing the instance. | ||
| */ | ||
| create(stack: ControlStack<TFamilyId, TTargetId>): TAdapterInstance; | ||
| } | ||
| interface ControlDriverDescriptor<TFamilyId extends string, TTargetId extends string, TDriverInstance extends ControlDriverInstance<TFamilyId, TTargetId> = ControlDriverInstance<TFamilyId, TTargetId>, TConnection = string> extends DriverDescriptor<TFamilyId, TTargetId> { | ||
| create(connection: TConnection): Promise<TDriverInstance>; | ||
| } | ||
| interface ControlExtensionDescriptor<TFamilyId extends string, TTargetId extends string, TExtensionInstance extends ControlExtensionInstance<TFamilyId, TTargetId> = ControlExtensionInstance<TFamilyId, TTargetId>> extends ExtensionDescriptor<TFamilyId, TTargetId> { | ||
| readonly contractSpace?: ContractSpace; | ||
| create(): TExtensionInstance; | ||
| } | ||
| //#endregion | ||
| //#region src/control/control-operation-preview.d.ts | ||
@@ -1007,79 +1185,36 @@ /** | ||
| declare function hasOperationPreview<TFamilyId extends string, TSchemaIR>(instance: ControlFamilyInstance<TFamilyId, TSchemaIR>): instance is ControlFamilyInstance<TFamilyId, TSchemaIR> & OperationPreviewCapable; | ||
| //#endregion | ||
| //#region src/control/control-spaces.d.ts | ||
| /** | ||
| * Canonical control-plane identifiers for contract spaces. | ||
| * The granularity of a {@link SchemaDiffIssue}'s subject, resolved on demand | ||
| * from the issue's node `nodeKind` — never stamped on the issue or the node. | ||
| * | ||
| * A contract space is the disjoint `(contract.json, migration-graph)` unit | ||
| * the per-space planner / runner / verifier (project: extension contract | ||
| * spaces, TML-2397) operates on. The application owns one well-known | ||
| * space — the value below — and each loaded extension that contributes | ||
| * schema owns a uniquely-named space. | ||
| * | ||
| * Lives in `framework-components/control` so every layer that has to | ||
| * reason about space identity (the migration tooling, the SQL runtime's | ||
| * marker reader, target-side statement builders, target-side adapters) | ||
| * can import a single value rather than duplicating the literal. Raw | ||
| * `'app'` string literals in framework / target / runtime / adapter | ||
| * source code are forbidden and policed by | ||
| * `scripts/lint-app-space-id.mjs` (wired into `pnpm lint:deps`). | ||
| * | ||
| * @see specs/framework-mechanism.spec.md § 3 — Layout convention (γ). | ||
| * - `namespace`: a whole namespace. | ||
| * - `entity`: a whole top-level entity (the thing a namespace contains). | ||
| * - `field`: a field of an entity. | ||
| * - `auxiliary`: a secondary part of an entity (an index, a default, a key). | ||
| * - `structural`: a cross-cutting object (an access policy, a tree root) that | ||
| * is the owning space's own concern, never a sibling's unclaimed entity — | ||
| * its extras fail verify in both modes. | ||
| */ | ||
| declare const APP_SPACE_ID: "app"; | ||
| type DiffSubjectGranularity = 'namespace' | 'entity' | 'field' | 'auxiliary' | 'structural'; | ||
| /** | ||
| * Head ref for a contract space — the `(hash, invariants)` tuple | ||
| * a runner targets when applying that space's migration graph. Identical | ||
| * in shape to the on-disk `migrations/<space-id>/refs/head.json` the | ||
| * framework writes per loaded extension, and to the app-space | ||
| * `<projectRoot>/refs/head.json`. Family-agnostic: SQL, Mongo, and any | ||
| * future family share the same head-ref shape. | ||
| * Capability declaring that a family can classify a {@link SchemaDiffIssue}'s | ||
| * subject granularity, and separately its storage `entityKind`, on demand — | ||
| * both resolved from its node's `nodeKind` through the family/target | ||
| * vocabulary it owns. Consumed by framework code that spans contract spaces | ||
| * (the migration aggregate's unclaimed-elements sweep) and cannot itself read | ||
| * family/target node vocabulary, so it asks this capability instead of | ||
| * hardcoding a family entity kind. `undefined` when the issue's node kind is | ||
| * unrecognized, or when the family injects no classifier at all — callers | ||
| * fall back to path shape in that case. | ||
| * | ||
| * @see specs/framework-mechanism.spec.md § 1. | ||
| * `classifyEntityKind` returns the same per-family vocabulary as the contract | ||
| * storage's `entries` dictionary keys (the vocabulary | ||
| * {@link import('../ir/storage').elementCoordinates} walks) — never a | ||
| * granularity word, and never a word this framework layer names itself. | ||
| */ | ||
| interface ContractSpaceHeadRef { | ||
| readonly hash: string; | ||
| readonly invariants: readonly string[]; | ||
| interface SchemaSubjectClassifierCapable { | ||
| classifySubjectGranularity(issue: SchemaDiffIssue): DiffSubjectGranularity | undefined; | ||
| classifyEntityKind(issue: SchemaDiffIssue): string | undefined; | ||
| } | ||
| /** | ||
| * Canonical structural shape of a migration package — the unit a planner | ||
| * produces and a runner consumes: a directory name, the metadata | ||
| * envelope, and the operation list. | ||
| * | ||
| * In-memory by default. Readers in `@prisma-next/migration-tools` | ||
| * (`readMigrationPackage` / `readMigrationsDir`) return the augmented | ||
| * {@link import('@prisma-next/migration-tools/package').OnDiskMigrationPackage} | ||
| * variant which adds `dirPath`; everything else operates against the | ||
| * canonical shape so the same value flows through pre-emission | ||
| * authoring, on-disk loading, and runner execution without conversion. | ||
| * | ||
| * @see specs/framework-mechanism.spec.md § 1. | ||
| */ | ||
| interface MigrationPackage { | ||
| readonly dirName: string; | ||
| readonly metadata: MigrationMetadata; | ||
| readonly ops: readonly MigrationPlanOperation[]; | ||
| } | ||
| /** | ||
| * Canonical structural shape of a contract space — one disjoint | ||
| * `(contractJson, migration-graph)` unit the per-space planner / runner | ||
| * / verifier operates on. The application owns one well-known space | ||
| * ({@link APP_SPACE_ID}); each loaded extension that contributes schema | ||
| * owns a uniquely-named space. Whether a value is the app's space or an | ||
| * extension's space is a control-plane concern; the type carries no | ||
| * such distinction. | ||
| * | ||
| * Generic over the contract so each family pins a typed contract value | ||
| * at consumption time. The SQL family specialises to | ||
| * `ContractSpace<Contract<SqlStorage>>` at the descriptor surface; | ||
| * Mongo's symmetrical `ContractSpace<Contract<MongoStorage>>` will land | ||
| * with that family. | ||
| * | ||
| * @see specs/framework-mechanism.spec.md § 1. | ||
| */ | ||
| interface ContractSpace<TContract extends Contract = Contract> { | ||
| readonly contractJson: TContract; | ||
| readonly migrations: readonly MigrationPackage[]; | ||
| readonly headRef: ContractSpaceHeadRef; | ||
| } | ||
| declare function hasSchemaSubjectClassifier<TFamilyId extends string, TSchemaIR>(instance: ControlFamilyInstance<TFamilyId, TSchemaIR>): instance is ControlFamilyInstance<TFamilyId, TSchemaIR> & SchemaSubjectClassifierCapable; | ||
| //#endregion | ||
@@ -1095,4 +1230,3 @@ //#region src/control/schema-verifier.d.ts | ||
| * per space, and wraps the per-target results into a unified | ||
| * `VerifyDatabaseSchemaResult` with timings, summary, and per-node | ||
| * verification tree. | ||
| * `VerifyDatabaseSchemaResult` with timings, summary, and the issue list. | ||
| * | ||
@@ -1103,9 +1237,2 @@ * Family-level abstract bases (e.g. `SqlSchemaVerifierBase`) carry the | ||
| * SqlSchemaVerifierBase`) own the dispatch on target-specific kinds. | ||
| * | ||
| * Target-specific issue kinds (RLS-policy-mismatch, namespace-mismatch, | ||
| * future function-shape-mismatch) are widened target-side; the framework | ||
| * `SchemaIssue` union (in `control-result-types.ts`) is intentionally not | ||
| * generic over target kinds in this project — see the spec's | ||
| * "Forward note: SchemaIssue layering" for the layering observation | ||
| * captured for a future project. | ||
| */ | ||
@@ -1128,13 +1255,12 @@ interface SchemaVerifier<TContract, TSchema> { | ||
| * existing `VerifyDatabaseSchemaResult` envelope (with timings, summary, | ||
| * per-node verification tree); the SPI itself returns just the | ||
| * core ok/issues pair so the seam between target-walk and | ||
| * framework-aggregation is explicit. | ||
| * issue list); the SPI itself returns just the core ok/issues pair so the | ||
| * seam between target-walk and framework-aggregation is explicit. | ||
| */ | ||
| interface SchemaVerifyResult { | ||
| readonly ok: boolean; | ||
| readonly issues: readonly SchemaIssue[]; | ||
| readonly issues: readonly SchemaDiffIssue[]; | ||
| } | ||
| //#endregion | ||
| //#region src/control/verifier-disposition.d.ts | ||
| type VerificationStatus = SchemaVerificationNode['status']; | ||
| type VerificationStatus = 'pass' | 'warn' | 'fail'; | ||
| type VerifierOutcome = VerificationStatus | 'suppress'; | ||
@@ -1169,3 +1295,3 @@ /** | ||
| //#endregion | ||
| export { APP_SPACE_ID, type AssembledAuthoringContributions, type BaseSchemaIssue, type ContractSerializer, type ContractSpace, type ContractSpaceHeadRef, type ControlAdapterDescriptor, type ControlAdapterInstance, type ControlDriverDescriptor, type ControlDriverInstance, type ControlExtensionDescriptor, type ControlExtensionInstance, type ControlFamilyDescriptor, type ControlFamilyInstance, type ControlMutationDefaultEntry, type ControlMutationDefaultRegistry, type ControlMutationDefaults, type ControlStack, type ControlTargetDescriptor, type ControlTargetInstance, type CoreSchemaView, type CreateControlStackInput, type DefaultFunctionLoweringContext, type DefaultFunctionLoweringHandler, type DefaultFunctionRegistry, type DefaultFunctionRegistryEntry, type EmitContractResult, type EnumValuesChangedIssue, type ImportRequirement, type IntrospectSchemaResult, type LoweredDefaultResult, type LoweredDefaultValue, type MigratableTargetDescriptor, type MigrationMetadata, type MigrationOperationClass, type MigrationOperationPolicy, type MigrationPackage, type MigrationPlan, type MigrationPlanOperation, type MigrationPlanWithAuthoringSurface, type MigrationPlanner, type MigrationPlannerConflict, type MigrationPlannerFailureResult, type MigrationPlannerResult, type MigrationPlannerSuccessResult, type MigrationRunner, type MigrationRunnerExecutionChecks, type MigrationRunnerFailure, type MigrationRunnerPerSpaceOptions, type MigrationRunnerPerSpaceSuccessValue, type MigrationRunnerResult, type MigrationRunnerSuccessValue, type MigrationScaffoldContext, type MutationDefaultGeneratorDescriptor, type OpFactoryCall, type OperationContext, type OperationPreview, type OperationPreviewCapable, type OperationPreviewStatement, type ParsedDefaultFunctionCall, type PslContractInferCapable, type SchemaIssue, SchemaTreeNode, type SchemaTreeNodeOptions, type SchemaTreeVisitor, type SchemaVerificationNode, type SchemaVerifier, type SchemaVerifyOptions, type SchemaVerifyResult, type SchemaViewCapable, type SchemaViewNodeKind, type SignDatabaseResult, type SourceDiagnostic, type SourceSpan, type TargetMigrationsCapability, VERIFY_CODE_HASH_MISMATCH, VERIFY_CODE_MARKER_MISSING, VERIFY_CODE_SCHEMA_FAILURE, VERIFY_CODE_TARGET_MISMATCH, type VerificationStatus, type VerifierIssueCategory, type VerifierOutcome, type VerifyDatabaseResult, type VerifyDatabaseSchemaResult, assembleAuthoringContributions, assembleControlMutationDefaults, assembleScalarTypeDescriptors, assertUniqueCodecOwner, buildExtensionLoadOrder, createControlStack, dispositionForCategory, extractCodecLookup, extractCodecTypeImports, extractComponentIds, extractQueryOperationTypeImports, hasMigrations, hasOperationPreview, hasPslContractInfer, hasSchemaView }; | ||
| export { APP_SPACE_ID, type AssembledAuthoringContributions, type ContractSerializer, type ContractSpace, type ContractSpaceHeadRef, type ControlAdapterDescriptor, type ControlAdapterInstance, type ControlDriverDescriptor, type ControlDriverInstance, type ControlExtensionDescriptor, type ControlExtensionInstance, type ControlFamilyDescriptor, type ControlFamilyInstance, type ControlMutationDefaultEntry, type ControlMutationDefaultRegistry, type ControlMutationDefaults, type ControlStack, type ControlTargetDescriptor, type ControlTargetInstance, type CoreSchemaView, type CreateControlStackInput, type DefaultFunctionLoweringContext, type DiffSubjectGranularity, type DiffableNode, type EmitContractResult, type ExpectationFailureReason, type ImportRequirement, type IntrospectSchemaResult, type LoweredDefaultResult, type LoweredDefaultValue, type MigratableTargetDescriptor, type MigrationMetadata, type MigrationOperationClass, type MigrationOperationPolicy, type MigrationPackage, type MigrationPlan, type MigrationPlanOperation, type MigrationPlanWithAuthoringSurface, type MigrationPlanner, type MigrationPlannerConflict, type MigrationPlannerFailureResult, type MigrationPlannerResult, type MigrationPlannerSuccessResult, type MigrationRunner, type MigrationRunnerExecutionChecks, type MigrationRunnerFailure, type MigrationRunnerPerSpaceOptions, type MigrationRunnerPerSpaceSuccessValue, type MigrationRunnerResult, type MigrationRunnerSuccessValue, type MigrationScaffoldContext, type MutationDefaultGeneratorDescriptor, type OpFactoryCall, type OperationContext, type OperationPreview, type OperationPreviewCapable, type OperationPreviewStatement, type PslContractInferCapable, SchemaDiff, type SchemaDiffIssue, type SchemaEntityCoordinate, type SchemaOwnership, type SchemaSubjectClassifierCapable, SchemaTreeNode, type SchemaTreeNodeOptions, type SchemaTreeVisitor, type SchemaVerifier, type SchemaVerifyOptions, type SchemaVerifyResult, type SchemaViewCapable, type SchemaViewNodeKind, type SignDatabaseResult, type SourceDiagnostic, type SourceSpan, type TargetMigrationsCapability, type TypedDefaultFunctionCall, VERIFY_CODE_HASH_MISMATCH, VERIFY_CODE_MARKER_MISSING, VERIFY_CODE_SCHEMA_FAILURE, VERIFY_CODE_TARGET_MISMATCH, type VerificationStatus, type VerifierIssueCategory, type VerifierOutcome, type VerifyDatabaseResult, type VerifyDatabaseSchemaResult, assembleAuthoringContributions, assembleControlMutationDefaults, assembleScalarTypeDescriptors, assertUniqueCodecOwner, buildExtensionLoadOrder, createControlStack, diffSchemas, dispositionForCategory, extractCodecLookup, extractCodecTypeImports, extractComponentIds, extractQueryOperationTypeImports, hasMigrations, hasOperationPreview, hasPslContractInfer, hasSchemaSubjectClassifier, hasSchemaView }; | ||
| //# sourceMappingURL=control.d.mts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"control.d.mts","names":[],"sources":["../src/control/contract-serializer.ts","../src/control/control-result-types.ts","../src/control/control-instances.ts","../src/control/control-stack.ts","../src/control/control-descriptors.ts","../src/control/control-migration-types.ts","../src/control/control-operation-preview.ts","../src/control/control-schema-view.ts","../src/control/control-capabilities.ts","../src/control/control-spaces.ts","../src/control/schema-verifier.ts","../src/control/verifier-disposition.ts"],"mappings":"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"} | ||
| {"version":3,"file":"control.d.mts","names":[],"sources":["../src/control/contract-serializer.ts","../src/control/schema-diff.ts","../src/control/control-operation-results.ts","../src/control/control-instances.ts","../src/control/control-migration-types.ts","../src/control/control-spaces.ts","../src/control/control-stack.ts","../src/control/control-descriptors.ts","../src/control/control-operation-preview.ts","../src/control/control-schema-view.ts","../src/control/control-capabilities.ts","../src/control/schema-verifier.ts","../src/control/verifier-disposition.ts"],"mappings":"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"} |
+141
-12
| import { n as materializeCodec, r as resolveCodecDescriptorOrThrow, t as CONTRACT_CODEC_DESCRIPTOR_MISSING } from "./resolve-codec-D8EPZosv.mjs"; | ||
| import { c as isAuthoringFieldPresetDescriptor, d as mergeAuthoringNamespaces, l as isAuthoringPslBlockDescriptor, s as isAuthoringEntityTypeDescriptor, t as assertNoCrossRegistryCollisions, u as isAuthoringTypeConstructorDescriptor } from "./framework-authoring-Dv5F3EFC.mjs"; | ||
| import { t as mergeCapabilityMatrices } from "./capabilities-BnRAFKP5.mjs"; | ||
| import { p as mergeAuthoringNamespaces, t as assertNoCrossRegistryCollisions } from "./framework-authoring-Bz_vaNZw.mjs"; | ||
| import { blindCast } from "@prisma-next/utils/casts"; | ||
@@ -17,4 +18,7 @@ //#region src/control/control-capabilities.ts | ||
| } | ||
| function hasSchemaSubjectClassifier(instance) { | ||
| return "classifySubjectGranularity" in instance && typeof instance["classifySubjectGranularity"] === "function" && "classifyEntityKind" in instance && typeof instance["classifyEntityKind"] === "function"; | ||
| } | ||
| //#endregion | ||
| //#region src/control/control-result-types.ts | ||
| //#region src/control/control-operation-results.ts | ||
| const VERIFY_CODE_MARKER_MISSING = "PN-RUN-3001"; | ||
@@ -109,7 +113,9 @@ const VERIFY_CODE_HASH_MISMATCH = "PN-RUN-3002"; | ||
| const pslBlockDescriptors = {}; | ||
| const modelAttributes = {}; | ||
| for (const descriptor of descriptors) { | ||
| if (descriptor.authoring?.field) mergeAuthoringNamespaces(field, descriptor.authoring.field, [], isAuthoringFieldPresetDescriptor, "field"); | ||
| if (descriptor.authoring?.type) mergeAuthoringNamespaces(type, descriptor.authoring.type, [], isAuthoringTypeConstructorDescriptor, "type"); | ||
| if (descriptor.authoring?.entityTypes) mergeAuthoringNamespaces(entityTypes, descriptor.authoring.entityTypes, [], isAuthoringEntityTypeDescriptor, "entity"); | ||
| if (descriptor.authoring?.pslBlockDescriptors) mergeAuthoringNamespaces(pslBlockDescriptors, descriptor.authoring.pslBlockDescriptors, [], isAuthoringPslBlockDescriptor, "pslBlock"); | ||
| if (descriptor.authoring?.field) mergeAuthoringNamespaces(field, descriptor.authoring.field, [], "fieldPreset", "field"); | ||
| if (descriptor.authoring?.type) mergeAuthoringNamespaces(type, descriptor.authoring.type, [], "typeConstructor", "type"); | ||
| if (descriptor.authoring?.entityTypes) mergeAuthoringNamespaces(entityTypes, descriptor.authoring.entityTypes, [], "entity", "entity"); | ||
| if (descriptor.authoring?.pslBlockDescriptors) mergeAuthoringNamespaces(pslBlockDescriptors, descriptor.authoring.pslBlockDescriptors, [], "pslBlock", "pslBlock"); | ||
| if (descriptor.authoring?.modelAttributes) mergeAuthoringNamespaces(modelAttributes, descriptor.authoring.modelAttributes, [], "modelAttribute", "modelAttribute"); | ||
| } | ||
@@ -120,3 +126,4 @@ const fieldNamespace = field; | ||
| const pslBlockDescriptorNamespace = blindCast(pslBlockDescriptors); | ||
| assertNoCrossRegistryCollisions(typeNamespace, fieldNamespace, entityTypeNamespace, pslBlockDescriptorNamespace); | ||
| const modelAttributeNamespace = blindCast(modelAttributes); | ||
| assertNoCrossRegistryCollisions(typeNamespace, fieldNamespace, entityTypeNamespace, pslBlockDescriptorNamespace, modelAttributeNamespace); | ||
| return { | ||
@@ -126,3 +133,4 @@ field: fieldNamespace, | ||
| entityTypes: entityTypeNamespace, | ||
| pslBlockDescriptors: pslBlockDescriptorNamespace | ||
| pslBlockDescriptors: pslBlockDescriptorNamespace, | ||
| modelAttributes: modelAttributeNamespace | ||
| }; | ||
@@ -178,4 +186,6 @@ } | ||
| const metaById = /* @__PURE__ */ new Map(); | ||
| const metaRenderersById = /* @__PURE__ */ new Map(); | ||
| const renderersById = /* @__PURE__ */ new Map(); | ||
| const inputRenderersById = /* @__PURE__ */ new Map(); | ||
| const valueLiteralRenderersById = /* @__PURE__ */ new Map(); | ||
| const owners = /* @__PURE__ */ new Map(); | ||
@@ -197,4 +207,6 @@ for (const descriptor of descriptors) { | ||
| if (codecDescriptor.meta !== void 0) metaById.set(codecDescriptor.codecId, codecDescriptor.meta); | ||
| if (typeof codecDescriptor.metaFor === "function") metaRenderersById.set(codecDescriptor.codecId, codecDescriptor.metaFor); | ||
| if (typeof codecDescriptor.renderOutputType === "function") renderersById.set(codecDescriptor.codecId, codecDescriptor.renderOutputType); | ||
| if (typeof codecDescriptor.renderInputType === "function") inputRenderersById.set(codecDescriptor.codecId, codecDescriptor.renderInputType); | ||
| if (typeof codecDescriptor.renderValueLiteral === "function") valueLiteralRenderersById.set(codecDescriptor.codecId, codecDescriptor.renderValueLiteral); | ||
| if (!byId.has(codecDescriptor.codecId)) if (codecDescriptor.isParameterized) try { | ||
@@ -217,7 +229,23 @@ const representative = codecDescriptor.factory({})({ name: `<lookup:${codecDescriptor.codecId}>` }); | ||
| targetTypesFor: (id) => targetTypesById.get(id), | ||
| metaFor: (id) => metaById.get(id), | ||
| metaFor: (id, typeParams) => { | ||
| if (typeParams !== void 0) { | ||
| const paramsAware = metaRenderersById.get(id)?.(typeParams); | ||
| if (paramsAware !== void 0) return paramsAware; | ||
| } | ||
| return metaById.get(id); | ||
| }, | ||
| renderOutputTypeFor: (id, params) => renderersById.get(id)?.(params), | ||
| renderInputTypeFor: (id, params) => inputRenderersById.get(id)?.(params) | ||
| renderInputTypeFor: (id, params) => inputRenderersById.get(id)?.(params), | ||
| renderValueLiteralFor: (id, value, side) => valueLiteralRenderersById.get(id)?.(value, side), | ||
| descriptorFor: (id) => descriptorsById.get(id) | ||
| }; | ||
| } | ||
| function assembleExtensionContracts(extensions) { | ||
| const result = /* @__PURE__ */ new Map(); | ||
| for (const ext of extensions) { | ||
| if (ext.contractSpace === void 0) continue; | ||
| result.set(ext.id, ext.contractSpace.contractJson); | ||
| } | ||
| return result; | ||
| } | ||
| function readDeclaredDependencyIds(descriptor) { | ||
@@ -297,2 +325,3 @@ const packs = descriptor.contractSpace?.contractJson?.extensionPacks; | ||
| extensionPacks: orderedExtensionPacks, | ||
| extensionContracts: assembleExtensionContracts(orderedExtensionPacks), | ||
| codecTypeImports: extractCodecTypeImports(allDescriptors), | ||
@@ -304,6 +333,106 @@ queryOperationTypeImports: extractQueryOperationTypeImports(allDescriptors), | ||
| scalarTypeDescriptors, | ||
| controlMutationDefaults: assembleControlMutationDefaults(allDescriptors) | ||
| controlMutationDefaults: assembleControlMutationDefaults(allDescriptors), | ||
| capabilities: mergeCapabilityMatrices({}, [ | ||
| target, | ||
| ...adapter ? [adapter] : [], | ||
| ...orderedExtensionPacks | ||
| ]) | ||
| }; | ||
| } | ||
| //#endregion | ||
| //#region src/control/schema-diff.ts | ||
| /** Delimiter joining `nodeKind` and `id` into one sibling-map key. Every `nodeKind` is a code-defined literal (kebab-case-style), so a null character can never appear in one. */ | ||
| const SIBLING_KEY_DELIMITER = "\0"; | ||
| function siblingKey(node) { | ||
| return `${node.nodeKind}${SIBLING_KEY_DELIMITER}${node.id}`; | ||
| } | ||
| function insertNode(map, node) { | ||
| const key = siblingKey(node); | ||
| if (map.has(key)) throw new Error(`diffSchemas: duplicate id among siblings: ${node.nodeKind}/${node.id}`); | ||
| map.set(key, node); | ||
| } | ||
| function emitMissingSubtree(node, parentPath) { | ||
| const path = [...parentPath, node.id]; | ||
| return [{ | ||
| path, | ||
| reason: "not-found", | ||
| expected: node | ||
| }, ...node.children().flatMap((c) => emitMissingSubtree(c, path))]; | ||
| } | ||
| function emitExtraSubtree(node, parentPath) { | ||
| const path = [...parentPath, node.id]; | ||
| return [{ | ||
| path, | ||
| reason: "not-expected", | ||
| actual: node | ||
| }, ...node.children().flatMap((c) => emitExtraSubtree(c, path))]; | ||
| } | ||
| /** | ||
| * Diff two schema trees starting from their roots. | ||
| * | ||
| * The differ is **total**: every node-level difference is reported. An unmatched | ||
| * non-leaf node emits its own issue and descends, emitting an issue for every | ||
| * node in the missing/extra subtree. Coalescing a parent change over its | ||
| * children is the planner's responsibility. Ownership filtering (dropping `extra` | ||
| * issues in namespaces a contract doesn't own) is the caller's responsibility. | ||
| */ | ||
| function diffSchemas(expected, actual) { | ||
| return diffPair(expected, actual, []); | ||
| } | ||
| function diffPair(expected, actual, parentPath) { | ||
| const path = [...parentPath, expected.id]; | ||
| const issues = []; | ||
| if (!expected.isEqualTo(actual)) issues.push({ | ||
| path, | ||
| reason: "not-equal", | ||
| expected, | ||
| actual | ||
| }); | ||
| issues.push(...diffChildren(expected.children(), actual.children(), path)); | ||
| return issues; | ||
| } | ||
| /** | ||
| * Align one level of nodes by `(nodeKind, id)`; emit issues in input order | ||
| * and recurse. | ||
| * | ||
| * A missing node emits one issue for itself and one for every node in its | ||
| * subtree (total descent). Same for extra nodes. A matched pair recurses via | ||
| * `diffPair`. | ||
| */ | ||
| function diffChildren(expected, actual, parentPath) { | ||
| const expectedMap = /* @__PURE__ */ new Map(); | ||
| for (const node of expected) insertNode(expectedMap, node); | ||
| const actualMap = /* @__PURE__ */ new Map(); | ||
| for (const node of actual) insertNode(actualMap, node); | ||
| const issues = []; | ||
| for (const [key, expectedNode] of expectedMap) { | ||
| const actualNode = actualMap.get(key); | ||
| if (actualNode === void 0) issues.push(...emitMissingSubtree(expectedNode, parentPath)); | ||
| else issues.push(...diffPair(expectedNode, actualNode, parentPath)); | ||
| } | ||
| for (const [key, actualNode] of actualMap) if (!expectedMap.has(key)) issues.push(...emitExtraSubtree(actualNode, parentPath)); | ||
| return issues; | ||
| } | ||
| /** | ||
| * The result of diffing a contract's expected schema against the introspected | ||
| * actual schema: one node-typed issue list. Carries no verdict, verification | ||
| * tree, or counts — those are the verifier's own presentation, built from the | ||
| * same underlying comparison. | ||
| * | ||
| * `TNode` is the concrete schema-IR node the issues carry; it defaults to | ||
| * `DiffableNode`, so this is purely additive — a caller that wants the | ||
| * concrete node opts in (the Postgres planner uses the concrete node type), | ||
| * everyone else keeps the default unchanged. | ||
| */ | ||
| var SchemaDiff = class SchemaDiff { | ||
| issues; | ||
| constructor(issues) { | ||
| this.issues = issues; | ||
| } | ||
| /** Returns a new `SchemaDiff` narrowed to the issues `keep` returns true for. */ | ||
| filter(keep) { | ||
| return new SchemaDiff(this.issues.filter(keep)); | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region src/control/verifier-disposition.ts | ||
@@ -328,4 +457,4 @@ /** | ||
| //#endregion | ||
| export { APP_SPACE_ID, SchemaTreeNode, VERIFY_CODE_HASH_MISMATCH, VERIFY_CODE_MARKER_MISSING, VERIFY_CODE_SCHEMA_FAILURE, VERIFY_CODE_TARGET_MISMATCH, assembleAuthoringContributions, assembleControlMutationDefaults, assembleScalarTypeDescriptors, assertUniqueCodecOwner, buildExtensionLoadOrder, createControlStack, dispositionForCategory, extractCodecLookup, extractCodecTypeImports, extractComponentIds, extractQueryOperationTypeImports, hasMigrations, hasOperationPreview, hasPslContractInfer, hasSchemaView }; | ||
| export { APP_SPACE_ID, SchemaDiff, SchemaTreeNode, VERIFY_CODE_HASH_MISMATCH, VERIFY_CODE_MARKER_MISSING, VERIFY_CODE_SCHEMA_FAILURE, VERIFY_CODE_TARGET_MISMATCH, assembleAuthoringContributions, assembleControlMutationDefaults, assembleScalarTypeDescriptors, assertUniqueCodecOwner, buildExtensionLoadOrder, createControlStack, diffSchemas, dispositionForCategory, extractCodecLookup, extractCodecTypeImports, extractComponentIds, extractQueryOperationTypeImports, hasMigrations, hasOperationPreview, hasPslContractInfer, hasSchemaSubjectClassifier, hasSchemaView }; | ||
| //# sourceMappingURL=control.mjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"control.mjs","names":[],"sources":["../src/control/control-capabilities.ts","../src/control/control-result-types.ts","../src/control/control-schema-view.ts","../src/control/control-spaces.ts","../src/control/control-stack.ts","../src/control/verifier-disposition.ts"],"sourcesContent":["import type { ControlTargetDescriptor } from './control-descriptors';\nimport type { ControlFamilyInstance } from './control-instances';\nimport type { MigrationPlanOperation, TargetMigrationsCapability } from './control-migration-types';\nimport type { OperationPreview } from './control-operation-preview';\nimport type { CoreSchemaView } from './control-schema-view';\nimport type { PslDocumentAst } from './psl-ast';\n\nexport interface MigratableTargetDescriptor<\n TFamilyId extends string,\n TTargetId extends string,\n TFamilyInstance extends ControlFamilyInstance<TFamilyId, unknown> = ControlFamilyInstance<\n TFamilyId,\n unknown\n >,\n> extends ControlTargetDescriptor<TFamilyId, TTargetId> {\n readonly migrations: TargetMigrationsCapability<TFamilyId, TTargetId, TFamilyInstance>;\n}\n\nexport function hasMigrations<TFamilyId extends string, TTargetId extends string>(\n target: ControlTargetDescriptor<TFamilyId, TTargetId>,\n): target is MigratableTargetDescriptor<TFamilyId, TTargetId> {\n return 'migrations' in target && !!(target as Record<string, unknown>)['migrations'];\n}\n\nexport interface SchemaViewCapable<TSchemaIR = unknown> {\n toSchemaView(schema: TSchemaIR): CoreSchemaView;\n}\n\nexport function hasSchemaView<TFamilyId extends string, TSchemaIR>(\n instance: ControlFamilyInstance<TFamilyId, TSchemaIR>,\n): instance is ControlFamilyInstance<TFamilyId, TSchemaIR> & SchemaViewCapable<TSchemaIR> {\n return (\n 'toSchemaView' in instance &&\n typeof (instance as Record<string, unknown>)['toSchemaView'] === 'function'\n );\n}\n\n/**\n * Capability declaring that a family can infer a PSL contract AST from its\n * opaque introspected schema IR. Consumed by `prisma-next contract infer`.\n */\nexport interface PslContractInferCapable<TSchemaIR = unknown> {\n inferPslContract(schemaIR: TSchemaIR): PslDocumentAst;\n}\n\nexport function hasPslContractInfer<TFamilyId extends string, TSchemaIR>(\n instance: ControlFamilyInstance<TFamilyId, TSchemaIR>,\n): instance is ControlFamilyInstance<TFamilyId, TSchemaIR> & PslContractInferCapable<TSchemaIR> {\n return (\n 'inferPslContract' in instance &&\n typeof (instance as Record<string, unknown>)['inferPslContract'] === 'function'\n );\n}\n\n/**\n * Capability declaring that a family can render a textual preview of migration\n * operations for the CLI's \"DDL preview\" output. SQL families emit\n * `language: 'sql'` statements; Mongo families emit `language: 'mongodb-shell'`.\n */\nexport interface OperationPreviewCapable {\n toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview;\n}\n\nexport function hasOperationPreview<TFamilyId extends string, TSchemaIR>(\n instance: ControlFamilyInstance<TFamilyId, TSchemaIR>,\n): instance is ControlFamilyInstance<TFamilyId, TSchemaIR> & OperationPreviewCapable {\n return (\n 'toOperationPreview' in instance &&\n typeof (instance as Record<string, unknown>)['toOperationPreview'] === 'function'\n );\n}\n","export const VERIFY_CODE_MARKER_MISSING = 'PN-RUN-3001';\nexport const VERIFY_CODE_HASH_MISMATCH = 'PN-RUN-3002';\nexport const VERIFY_CODE_TARGET_MISMATCH = 'PN-RUN-3003';\nexport const VERIFY_CODE_SCHEMA_FAILURE = 'PN-RUN-3010';\n\nexport interface OperationContext {\n readonly contractPath?: string;\n readonly configPath?: string;\n readonly meta?: Readonly<Record<string, unknown>>;\n}\n\nexport interface VerifyDatabaseResult {\n readonly ok: boolean;\n readonly code?: string;\n readonly summary: string;\n readonly contract: {\n readonly storageHash: string;\n readonly profileHash?: string;\n };\n readonly marker?: {\n readonly storageHash?: string;\n readonly profileHash?: string;\n };\n readonly target: {\n readonly expected: string;\n readonly actual?: string;\n };\n readonly missingCodecs?: readonly string[];\n readonly codecCoverageSkipped?: boolean;\n readonly meta?: {\n readonly configPath?: string;\n readonly contractPath: string;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\nexport interface BaseSchemaIssue {\n readonly kind:\n | 'missing_schema'\n | 'missing_table'\n | 'missing_column'\n | 'extra_table'\n | 'extra_column'\n | 'extra_primary_key'\n | 'extra_foreign_key'\n | 'extra_unique_constraint'\n | 'extra_index'\n | 'extra_validator'\n | 'type_mismatch'\n | 'type_missing'\n | 'type_values_mismatch'\n | 'nullability_mismatch'\n | 'primary_key_mismatch'\n | 'foreign_key_mismatch'\n | 'unique_constraint_mismatch'\n | 'index_mismatch'\n | 'default_missing'\n | 'default_mismatch'\n | 'extra_default'\n | 'check_missing'\n | 'check_removed'\n | 'check_mismatch';\n readonly table?: string;\n /**\n * Namespace coordinate of the issue's subject (e.g. the schema a SQL\n * table lives in). Populated by family verifiers that have the\n * coordinate in scope when constructing the issue; absent for issues\n * whose family has no namespace concept (e.g. Mongo collections) or\n * whose subject isn't in any contract namespace (e.g. an extra-table\n * issue raised for a table that exists in the live DB but not in the\n * contract).\n *\n * Downstream planners trust this field as the authoritative subject\n * coordinate and do not re-derive it by name lookup. A finer-grained\n * structural split between framework-shared and family-specific issue\n * fields is tracked under a follow-up ticket.\n */\n readonly namespaceId?: string;\n readonly column?: string;\n readonly indexOrConstraint?: string;\n readonly typeName?: string;\n readonly expected?: string;\n readonly actual?: string;\n readonly message: string;\n}\n\nexport interface EnumValuesChangedIssue {\n readonly kind: 'enum_values_changed';\n /**\n * Namespace coordinate of the enum type that changed values. Populated by\n * family verifiers that have the coordinate in scope when constructing the\n * issue. Downstream planners trust this field as the authoritative subject\n * coordinate and do not re-derive it by name lookup.\n */\n readonly namespaceId: string;\n readonly typeName: string;\n readonly addedValues: readonly string[];\n readonly removedValues: readonly string[];\n readonly message: string;\n}\n\nexport type SchemaIssue = BaseSchemaIssue | EnumValuesChangedIssue;\n\nexport interface SchemaVerificationNode {\n readonly status: 'pass' | 'warn' | 'fail';\n readonly kind: string;\n readonly name: string;\n readonly contractPath: string;\n readonly code: string;\n readonly message: string;\n readonly expected: unknown;\n readonly actual: unknown;\n readonly children: readonly SchemaVerificationNode[];\n}\n\nexport interface VerifyDatabaseSchemaResult {\n readonly ok: boolean;\n readonly code?: string;\n readonly summary: string;\n readonly contract: {\n readonly storageHash: string;\n readonly profileHash?: string;\n };\n readonly target: {\n readonly expected: string;\n readonly actual?: string;\n };\n readonly schema: {\n readonly issues: readonly SchemaIssue[];\n readonly root: SchemaVerificationNode;\n readonly counts: {\n readonly pass: number;\n readonly warn: number;\n readonly fail: number;\n readonly totalNodes: number;\n };\n };\n readonly meta?: {\n readonly configPath?: string;\n readonly contractPath?: string;\n readonly strict: boolean;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\nexport interface EmitContractResult {\n readonly contractJson: string;\n readonly contractDts: string;\n readonly storageHash: string;\n readonly executionHash?: string;\n readonly profileHash: string;\n}\n\nexport interface IntrospectSchemaResult<TSchemaIR> {\n readonly ok: true;\n readonly summary: string;\n readonly target: {\n readonly familyId: string;\n readonly id: string;\n };\n readonly schema: TSchemaIR;\n readonly meta?: {\n readonly configPath?: string;\n readonly dbUrl?: string;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\nexport interface SignDatabaseResult {\n readonly ok: boolean;\n readonly summary: string;\n readonly contract: {\n readonly storageHash: string;\n readonly profileHash?: string;\n };\n readonly target: {\n readonly expected: string;\n readonly actual?: string;\n };\n readonly marker: {\n readonly created: boolean;\n readonly updated: boolean;\n readonly previous?: {\n readonly storageHash?: string;\n readonly profileHash?: string;\n };\n };\n readonly meta?: {\n readonly configPath?: string;\n readonly contractPath: string;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n","/**\n * Core schema view types for family-agnostic schema visualization.\n *\n * These types provide a minimal, generic, tree-shaped representation of schemas\n * across families, designed for CLI visualization and lightweight tooling.\n *\n * Families can optionally project their family-specific Schema IR into this\n * core view via the `toSchemaView` method on `FamilyInstance`.\n */\n\nexport type SchemaViewNodeKind =\n | 'root'\n | 'namespace'\n | 'collection'\n | 'entity'\n | 'field'\n | 'index'\n | 'dependency';\n\nexport interface SchemaTreeVisitor<R> {\n visit(node: SchemaTreeNode): R;\n}\n\nexport interface SchemaTreeNodeOptions {\n readonly kind: SchemaViewNodeKind;\n readonly id: string;\n readonly label: string;\n readonly meta?: Record<string, unknown>;\n readonly children?: readonly SchemaTreeNode[];\n}\n\nexport class SchemaTreeNode {\n readonly kind: SchemaViewNodeKind;\n readonly id: string;\n readonly label: string;\n readonly meta?: Record<string, unknown>;\n readonly children?: readonly SchemaTreeNode[];\n\n constructor(options: SchemaTreeNodeOptions) {\n this.kind = options.kind;\n this.id = options.id;\n this.label = options.label;\n if (options.meta !== undefined) this.meta = options.meta;\n if (options.children !== undefined) this.children = options.children;\n Object.freeze(this);\n }\n\n accept<R>(visitor: SchemaTreeVisitor<R>): R {\n return visitor.visit(this);\n }\n}\n\n/**\n * Core schema view providing a family-agnostic tree representation of a schema.\n * Used by CLI and cross-family tooling for visualization.\n */\nexport interface CoreSchemaView {\n readonly root: SchemaTreeNode;\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport type { MigrationMetadata, MigrationPlanOperation } from './control-migration-types';\n\n/**\n * Canonical control-plane identifiers for contract spaces.\n *\n * A contract space is the disjoint `(contract.json, migration-graph)` unit\n * the per-space planner / runner / verifier (project: extension contract\n * spaces, TML-2397) operates on. The application owns one well-known\n * space — the value below — and each loaded extension that contributes\n * schema owns a uniquely-named space.\n *\n * Lives in `framework-components/control` so every layer that has to\n * reason about space identity (the migration tooling, the SQL runtime's\n * marker reader, target-side statement builders, target-side adapters)\n * can import a single value rather than duplicating the literal. Raw\n * `'app'` string literals in framework / target / runtime / adapter\n * source code are forbidden and policed by\n * `scripts/lint-app-space-id.mjs` (wired into `pnpm lint:deps`).\n *\n * @see specs/framework-mechanism.spec.md § 3 — Layout convention (γ).\n */\nexport const APP_SPACE_ID = 'app' as const;\n\n/**\n * Head ref for a contract space — the `(hash, invariants)` tuple\n * a runner targets when applying that space's migration graph. Identical\n * in shape to the on-disk `migrations/<space-id>/refs/head.json` the\n * framework writes per loaded extension, and to the app-space\n * `<projectRoot>/refs/head.json`. Family-agnostic: SQL, Mongo, and any\n * future family share the same head-ref shape.\n *\n * @see specs/framework-mechanism.spec.md § 1.\n */\nexport interface ContractSpaceHeadRef {\n readonly hash: string;\n readonly invariants: readonly string[];\n}\n\n/**\n * Canonical structural shape of a migration package — the unit a planner\n * produces and a runner consumes: a directory name, the metadata\n * envelope, and the operation list.\n *\n * In-memory by default. Readers in `@prisma-next/migration-tools`\n * (`readMigrationPackage` / `readMigrationsDir`) return the augmented\n * {@link import('@prisma-next/migration-tools/package').OnDiskMigrationPackage}\n * variant which adds `dirPath`; everything else operates against the\n * canonical shape so the same value flows through pre-emission\n * authoring, on-disk loading, and runner execution without conversion.\n *\n * @see specs/framework-mechanism.spec.md § 1.\n */\nexport interface MigrationPackage {\n readonly dirName: string;\n readonly metadata: MigrationMetadata;\n readonly ops: readonly MigrationPlanOperation[];\n}\n\n/**\n * Canonical structural shape of a contract space — one disjoint\n * `(contractJson, migration-graph)` unit the per-space planner / runner\n * / verifier operates on. The application owns one well-known space\n * ({@link APP_SPACE_ID}); each loaded extension that contributes schema\n * owns a uniquely-named space. Whether a value is the app's space or an\n * extension's space is a control-plane concern; the type carries no\n * such distinction.\n *\n * Generic over the contract so each family pins a typed contract value\n * at consumption time. The SQL family specialises to\n * `ContractSpace<Contract<SqlStorage>>` at the descriptor surface;\n * Mongo's symmetrical `ContractSpace<Contract<MongoStorage>>` will land\n * with that family.\n *\n * @see specs/framework-mechanism.spec.md § 1.\n */\nexport interface ContractSpace<TContract extends Contract = Contract> {\n readonly contractJson: TContract;\n readonly migrations: readonly MigrationPackage[];\n readonly headRef: ContractSpaceHeadRef;\n}\n","import { blindCast } from '@prisma-next/utils/casts';\nimport type { Codec } from '../shared/codec';\nimport type { AnyCodecDescriptor } from '../shared/codec-descriptor';\nimport type { CodecLookup, CodecMeta, CodecRef, CodecRegistry } from '../shared/codec-types';\nimport type {\n AuthoringContributions,\n AuthoringEntityTypeNamespace,\n AuthoringFieldNamespace,\n AuthoringPslBlockDescriptorNamespace,\n AuthoringTypeNamespace,\n} from '../shared/framework-authoring';\nimport {\n assertNoCrossRegistryCollisions,\n isAuthoringEntityTypeDescriptor,\n isAuthoringFieldPresetDescriptor,\n isAuthoringPslBlockDescriptor,\n isAuthoringTypeConstructorDescriptor,\n mergeAuthoringNamespaces,\n} from '../shared/framework-authoring';\nimport type { ComponentMetadata } from '../shared/framework-components';\nimport type {\n ControlMutationDefaultEntry,\n ControlMutationDefaults,\n MutationDefaultGeneratorDescriptor,\n} from '../shared/mutation-default-types';\nimport {\n CONTRACT_CODEC_DESCRIPTOR_MISSING,\n materializeCodec,\n resolveCodecDescriptorOrThrow,\n} from '../shared/resolve-codec';\nimport type { TypesImportSpec } from '../shared/types-import-spec';\nimport type {\n ControlAdapterDescriptor,\n ControlDriverDescriptor,\n ControlExtensionDescriptor,\n ControlFamilyDescriptor,\n ControlTargetDescriptor,\n} from './control-descriptors';\n\nexport interface AssembledAuthoringContributions {\n readonly field: AuthoringFieldNamespace;\n readonly type: AuthoringTypeNamespace;\n readonly entityTypes: AuthoringEntityTypeNamespace;\n readonly pslBlockDescriptors: AuthoringPslBlockDescriptorNamespace;\n}\n\nexport interface ControlStack<\n TFamilyId extends string = string,\n TTargetId extends string = string,\n> {\n readonly family: ControlFamilyDescriptor<TFamilyId>;\n readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;\n readonly adapter?: ControlAdapterDescriptor<TFamilyId, TTargetId> | undefined;\n readonly driver?: ControlDriverDescriptor<TFamilyId, TTargetId> | undefined;\n readonly extensionPacks: readonly ControlExtensionDescriptor<TFamilyId, TTargetId>[];\n\n readonly codecTypeImports: ReadonlyArray<TypesImportSpec>;\n readonly queryOperationTypeImports: ReadonlyArray<TypesImportSpec>;\n readonly extensionIds: ReadonlyArray<string>;\n readonly codecLookup: CodecRegistry;\n readonly authoringContributions: AssembledAuthoringContributions;\n readonly scalarTypeDescriptors: ReadonlyMap<string, string>;\n readonly controlMutationDefaults: ControlMutationDefaults;\n}\n\nexport interface CreateControlStackInput<\n TFamilyId extends string = string,\n TTargetId extends string = string,\n> {\n readonly family: ControlFamilyDescriptor<TFamilyId>;\n readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;\n readonly adapter?: ControlAdapterDescriptor<TFamilyId, TTargetId> | undefined;\n readonly driver?: ControlDriverDescriptor<TFamilyId, TTargetId> | undefined;\n readonly extensionPacks?:\n | ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>\n | undefined;\n}\n\nfunction addUniqueId(ids: string[], seen: Set<string>, id: string): void {\n if (!seen.has(id)) {\n ids.push(id);\n seen.add(id);\n }\n}\n\nexport function assertUniqueCodecOwner(options: {\n readonly codecId: string;\n readonly owners: Map<string, string>;\n readonly descriptorId: string;\n readonly entityLabel: string;\n readonly entityOwnershipLabel: string;\n}): void {\n const existingOwner = options.owners.get(options.codecId);\n if (existingOwner !== undefined) {\n throw new Error(\n `Duplicate ${options.entityLabel} for codecId \"${options.codecId}\". ` +\n `Descriptor \"${options.descriptorId}\" conflicts with \"${existingOwner}\". ` +\n `Each codecId can only have one ${options.entityOwnershipLabel}.`,\n );\n }\n}\n\nexport function extractCodecTypeImports(\n descriptors: ReadonlyArray<Pick<ComponentMetadata, 'types'>>,\n): ReadonlyArray<TypesImportSpec> {\n const imports: TypesImportSpec[] = [];\n\n for (const descriptor of descriptors) {\n const codecTypes = descriptor.types?.codecTypes;\n if (codecTypes?.import) {\n imports.push(codecTypes.import);\n }\n if (codecTypes?.typeImports) {\n imports.push(...codecTypes.typeImports);\n }\n }\n\n return imports;\n}\n\nexport function extractQueryOperationTypeImports(\n descriptors: ReadonlyArray<Pick<ComponentMetadata, 'types'>>,\n): ReadonlyArray<TypesImportSpec> {\n const imports: TypesImportSpec[] = [];\n\n for (const descriptor of descriptors) {\n const queryOperationTypes = descriptor.types?.queryOperationTypes;\n if (queryOperationTypes?.import) {\n imports.push(queryOperationTypes.import);\n }\n }\n\n return imports;\n}\n\nexport function extractComponentIds(\n family: { readonly id: string },\n target: { readonly id: string },\n adapter: { readonly id: string } | undefined,\n extensions: ReadonlyArray<{ readonly id: string }>,\n): ReadonlyArray<string> {\n const ids: string[] = [];\n const seen = new Set<string>();\n\n addUniqueId(ids, seen, family.id);\n addUniqueId(ids, seen, target.id);\n if (adapter) {\n addUniqueId(ids, seen, adapter.id);\n }\n\n for (const ext of extensions) {\n addUniqueId(ids, seen, ext.id);\n }\n\n return ids;\n}\n\nexport function assembleAuthoringContributions(\n descriptors: ReadonlyArray<{ readonly authoring?: AuthoringContributions }>,\n): AssembledAuthoringContributions {\n const field = {} as Record<string, unknown>;\n const type = {} as Record<string, unknown>;\n const entityTypes = {} as Record<string, unknown>;\n const pslBlockDescriptors: Record<string, unknown> = {};\n\n for (const descriptor of descriptors) {\n if (descriptor.authoring?.field) {\n mergeAuthoringNamespaces(\n field,\n descriptor.authoring.field,\n [],\n isAuthoringFieldPresetDescriptor,\n 'field',\n );\n }\n if (descriptor.authoring?.type) {\n mergeAuthoringNamespaces(\n type,\n descriptor.authoring.type,\n [],\n isAuthoringTypeConstructorDescriptor,\n 'type',\n );\n }\n if (descriptor.authoring?.entityTypes) {\n mergeAuthoringNamespaces(\n entityTypes,\n descriptor.authoring.entityTypes,\n [],\n isAuthoringEntityTypeDescriptor,\n 'entity',\n );\n }\n if (descriptor.authoring?.pslBlockDescriptors) {\n mergeAuthoringNamespaces(\n pslBlockDescriptors,\n descriptor.authoring.pslBlockDescriptors,\n [],\n isAuthoringPslBlockDescriptor,\n 'pslBlock',\n );\n }\n }\n\n const fieldNamespace = field as AuthoringFieldNamespace;\n const typeNamespace = type as AuthoringTypeNamespace;\n const entityTypeNamespace = entityTypes as AuthoringEntityTypeNamespace;\n const pslBlockDescriptorNamespace = blindCast<\n AuthoringPslBlockDescriptorNamespace,\n 'merge target accumulator narrows to typed namespace post-merge'\n >(pslBlockDescriptors);\n assertNoCrossRegistryCollisions(\n typeNamespace,\n fieldNamespace,\n entityTypeNamespace,\n pslBlockDescriptorNamespace,\n );\n\n return {\n field: fieldNamespace,\n type: typeNamespace,\n entityTypes: entityTypeNamespace,\n pslBlockDescriptors: pslBlockDescriptorNamespace,\n };\n}\n\nexport function assembleScalarTypeDescriptors(\n descriptors: ReadonlyArray<\n Pick<ComponentMetadata, 'scalarTypeDescriptors'> & { readonly id?: string }\n >,\n): ReadonlyMap<string, string> {\n const result = new Map<string, string>();\n const owners = new Map<string, string>();\n\n for (const descriptor of descriptors) {\n const descriptorMap = descriptor.scalarTypeDescriptors;\n if (!descriptorMap) continue;\n const descriptorId = descriptor.id ?? '<unknown>';\n for (const [typeName, codecId] of descriptorMap) {\n const existingOwner = owners.get(typeName);\n if (existingOwner !== undefined) {\n throw new Error(\n `Duplicate scalar type descriptor \"${typeName}\". ` +\n `Descriptor \"${descriptorId}\" conflicts with \"${existingOwner}\".`,\n );\n }\n result.set(typeName, codecId);\n owners.set(typeName, descriptorId);\n }\n }\n\n return result;\n}\n\nexport function assembleControlMutationDefaults(\n descriptors: ReadonlyArray<\n Pick<ComponentMetadata, 'controlMutationDefaults'> & { readonly id?: string }\n >,\n): ControlMutationDefaults {\n const defaultFunctionRegistry = new Map<string, ControlMutationDefaultEntry>();\n const functionOwners = new Map<string, string>();\n const generatorMap = new Map<string, MutationDefaultGeneratorDescriptor>();\n const generatorOwners = new Map<string, string>();\n\n for (const descriptor of descriptors) {\n const contributions = descriptor.controlMutationDefaults;\n if (!contributions) continue;\n const descriptorId = descriptor.id ?? '<unknown>';\n\n for (const generatorDescriptor of contributions.generatorDescriptors) {\n const existingOwner = generatorOwners.get(generatorDescriptor.id);\n if (existingOwner !== undefined) {\n throw new Error(\n `Duplicate mutation default generator id \"${generatorDescriptor.id}\". ` +\n `Descriptor \"${descriptorId}\" conflicts with \"${existingOwner}\".`,\n );\n }\n generatorMap.set(generatorDescriptor.id, generatorDescriptor);\n generatorOwners.set(generatorDescriptor.id, descriptorId);\n }\n\n for (const [functionName, handler] of contributions.defaultFunctionRegistry) {\n const existingOwner = functionOwners.get(functionName);\n if (existingOwner !== undefined) {\n throw new Error(\n `Duplicate mutation default function \"${functionName}\". ` +\n `Descriptor \"${descriptorId}\" conflicts with \"${existingOwner}\".`,\n );\n }\n defaultFunctionRegistry.set(functionName, handler);\n functionOwners.set(functionName, descriptorId);\n }\n }\n\n return {\n defaultFunctionRegistry,\n generatorDescriptors: Array.from(generatorMap.values()),\n };\n}\n\nexport function extractCodecLookup(\n descriptors: ReadonlyArray<Pick<ComponentMetadata & { id: string }, 'types' | 'id'>>,\n): CodecRegistry {\n const byId = new Map<string, Codec>();\n const descriptorsById = new Map<string, AnyCodecDescriptor>();\n const targetTypesById = new Map<string, readonly string[]>();\n const metaById = new Map<string, CodecMeta>();\n const renderersById = new Map<string, (params: Record<string, unknown>) => string | undefined>();\n const inputRenderersById = new Map<\n string,\n (params: Record<string, unknown>) => string | undefined\n >();\n const owners = new Map<string, string>();\n for (const descriptor of descriptors) {\n const codecTypes = descriptor.types?.codecTypes;\n const descriptorId = descriptor.id;\n // Descriptor-side metadata is the single source of truth for `targetTypes` / `meta` / `renderOutputType`. Every contributor ships a `codecDescriptors` list on `types.codecTypes`.\n for (const codecDescriptor of codecTypes?.codecDescriptors ?? []) {\n assertUniqueCodecOwner({\n codecId: codecDescriptor.codecId,\n owners,\n descriptorId,\n entityLabel: 'codec descriptor',\n entityOwnershipLabel: 'codec descriptor provider',\n });\n owners.set(codecDescriptor.codecId, descriptorId);\n descriptorsById.set(codecDescriptor.codecId, codecDescriptor);\n if (Array.isArray(codecDescriptor.targetTypes)) {\n targetTypesById.set(codecDescriptor.codecId, codecDescriptor.targetTypes);\n }\n if (codecDescriptor.meta !== undefined) {\n metaById.set(codecDescriptor.codecId, codecDescriptor.meta);\n }\n if (typeof codecDescriptor.renderOutputType === 'function') {\n renderersById.set(codecDescriptor.codecId, codecDescriptor.renderOutputType);\n }\n if (typeof codecDescriptor.renderInputType === 'function') {\n inputRenderersById.set(codecDescriptor.codecId, codecDescriptor.renderInputType);\n }\n // Materialize a representative `Codec` instance for `byId.get()` so consumers reading the lookup's instance side (e.g. SQL renderer's cast-policy lookup, or the contract emitter's literal-default `encodeJson` resolver) keep finding the codec.\n //\n // Two cohorts:\n // - Non-parameterized descriptors: factory must succeed; any throw is a real bug and we let it propagate (no silent try/catch).\n // - Parameterized descriptors: try with empty params. Many parameterized codecs treat params as advisory (e.g. `pg/timestamptz@1` whose precision is rendered into the `nativeType` only and never read by the runtime codec), so an empty-params construction yields a usable representative for id-keyed lookups (e.g. emit-time literal-default encoding). Codecs whose factory genuinely requires params (e.g. `pg/vector@1` threading `length` into the runtime codec) will throw; for those, per-column instances are materialized at runtime by `buildContractCodecRegistry` and the id-keyed lookup miss is correct (the column-aware path resolves them).\n if (!byId.has(codecDescriptor.codecId)) {\n if (codecDescriptor.isParameterized) {\n try {\n const representative = codecDescriptor.factory({} as never)({\n name: `<lookup:${codecDescriptor.codecId}>`,\n } as Parameters<ReturnType<typeof codecDescriptor.factory>>[0]);\n byId.set(codecDescriptor.codecId, representative);\n } catch {\n // Factory requires concrete params; skip representative materialization. Per-column instances are built at runtime; id-keyed lookup miss is the correct outcome here.\n }\n } else {\n const representative = codecDescriptor.factory(undefined as never)({\n name: `<lookup:${codecDescriptor.codecId}>`,\n } as Parameters<ReturnType<typeof codecDescriptor.factory>>[0]);\n byId.set(codecDescriptor.codecId, representative);\n }\n }\n }\n }\n return {\n get: (id) => byId.get(id),\n forCodecRef(ref: CodecRef) {\n const d = resolveCodecDescriptorOrThrow(\n (id) => descriptorsById.get(id),\n ref,\n CONTRACT_CODEC_DESCRIPTOR_MISSING,\n );\n return materializeCodec(d, ref, { name: `<ref:${ref.codecId}>` });\n },\n forColumn: () => undefined,\n targetTypesFor: (id) => targetTypesById.get(id),\n metaFor: (id) => metaById.get(id),\n renderOutputTypeFor: (id, params) => renderersById.get(id)?.(params),\n renderInputTypeFor: (id, params) => inputRenderersById.get(id)?.(params),\n };\n}\n\nexport function validateScalarTypeCodecIds(\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n codecLookup: CodecLookup,\n): string[] {\n const errors: string[] = [];\n for (const [typeName, codecId] of scalarTypeDescriptors) {\n if (!codecLookup.get(codecId)) {\n errors.push(\n `Scalar type \"${typeName}\" references codec \"${codecId}\" which is not registered by any component.`,\n );\n }\n }\n return errors;\n}\n\ninterface DependencyDeclaringDescriptor {\n readonly id: string;\n readonly contractSpace?: {\n readonly contractJson?: {\n readonly extensionPacks?: Readonly<Record<string, unknown>>;\n };\n };\n}\n\nfunction readDeclaredDependencyIds(descriptor: DependencyDeclaringDescriptor): readonly string[] {\n const packs = descriptor.contractSpace?.contractJson?.extensionPacks;\n if (packs === null || typeof packs !== 'object') return [];\n return Object.keys(packs);\n}\n\n/**\n * Builds a dependency-respecting load order for the given extension descriptors\n * using Kahn's topological sort algorithm. Dependencies (packs declared in\n * `contractSpace.contractJson.extensionPacks`) are placed before the extensions\n * that depend on them.\n *\n * Throws if the dependency graph contains a cycle, with an error message that\n * names every extension involved in the cycle.\n *\n * Throws if any extension declares a dependency on a pack ID that is not present\n * in the provided list — add the missing pack to the `extensionPacks` list to\n * resolve the error.\n */\n\nexport function buildExtensionLoadOrder(\n extensions: ReadonlyArray<DependencyDeclaringDescriptor>,\n): readonly string[] {\n if (extensions.length === 0) return [];\n\n const idSet = new Set(extensions.map((e) => e.id));\n const inDegree = new Map<string, number>();\n const dependents = new Map<string, string[]>();\n\n for (const ext of extensions) {\n if (!inDegree.has(ext.id)) inDegree.set(ext.id, 0);\n if (!dependents.has(ext.id)) dependents.set(ext.id, []);\n }\n\n for (const ext of extensions) {\n for (const depId of readDeclaredDependencyIds(ext)) {\n if (!idSet.has(depId)) {\n throw new Error(\n `Extension \"${ext.id}\" declares a dependency on \"${depId}\", but \"${depId}\" is not in the provided extension set. Add the missing space to extensionPacks.`,\n );\n }\n inDegree.set(ext.id, (inDegree.get(ext.id) ?? 0) + 1);\n const list = dependents.get(depId);\n if (list !== undefined) list.push(ext.id);\n }\n }\n\n const queue: string[] = [];\n for (const [id, deg] of inDegree) {\n if (deg === 0) queue.push(id);\n }\n queue.sort();\n\n const result: string[] = [];\n while (queue.length > 0) {\n const id = queue.shift();\n if (id === undefined) break;\n result.push(id);\n const children = dependents.get(id) ?? [];\n children.sort();\n for (const childId of children) {\n const newDeg = (inDegree.get(childId) ?? 1) - 1;\n inDegree.set(childId, newDeg);\n if (newDeg === 0) queue.push(childId);\n }\n }\n\n if (result.length < extensions.length) {\n const cycleMembers = extensions\n .map((e) => e.id)\n .filter((id) => !result.includes(id))\n .sort();\n throw new Error(\n `Extension dependency cycle detected. Cycle members: ${cycleMembers.map((id) => `\"${id}\"`).join(', ')}.`,\n );\n }\n\n return result;\n}\n\nexport function createControlStack<TFamilyId extends string, TTargetId extends string>(\n input: CreateControlStackInput<TFamilyId, TTargetId>,\n): ControlStack<TFamilyId, TTargetId> {\n const { family, target, adapter, driver, extensionPacks = [] } = input;\n\n const orderedIds = buildExtensionLoadOrder(extensionPacks);\n const extensionById = new Map(extensionPacks.map((ext) => [ext.id, ext]));\n const orderedExtensionPacks = orderedIds\n .map((id) => extensionById.get(id))\n .filter((ext): ext is ControlExtensionDescriptor<TFamilyId, TTargetId> => ext !== undefined);\n\n const allDescriptors = [family, target, ...(adapter ? [adapter] : []), ...orderedExtensionPacks];\n\n const codecLookup = extractCodecLookup(allDescriptors);\n const scalarTypeDescriptors = assembleScalarTypeDescriptors(allDescriptors);\n\n return {\n family,\n target,\n adapter,\n driver,\n extensionPacks: orderedExtensionPacks,\n\n codecTypeImports: extractCodecTypeImports(allDescriptors),\n queryOperationTypeImports: extractQueryOperationTypeImports(allDescriptors),\n extensionIds: extractComponentIds(family, target, adapter, orderedExtensionPacks),\n codecLookup,\n authoringContributions: assembleAuthoringContributions(allDescriptors),\n scalarTypeDescriptors,\n controlMutationDefaults: assembleControlMutationDefaults(allDescriptors),\n };\n}\n","import type { ControlPolicy } from '@prisma-next/contract/types';\nimport type { SchemaVerificationNode } from './control-result-types';\n\nexport type VerificationStatus = SchemaVerificationNode['status'];\n\nexport type VerifierOutcome = VerificationStatus | 'suppress';\n\n/**\n * Target-neutral classification of a verifier finding, abstracted away from any\n * one storage model's vocabulary. Each family classifies its own concrete issue\n * kinds into these categories; the framework only grades the category against a\n * control policy.\n *\n * - `declaredMissing` — a declared object/element is absent from the database.\n * - `declaredIncompatible` — a declared object/element exists but its shape diverges.\n * - `valueDrift` — the value set of an existing type drifted (e.g. enum values).\n * - `extraNestedElement` — an undeclared element nested inside a declared object\n * (a SQL column, a document field).\n * - `extraAuxiliary` — an undeclared auxiliary attached to a declared object\n * (a SQL constraint/index, a Mongo index/validator).\n * - `extraTopLevelObject` — an undeclared top-level object (a SQL table, a\n * Mongo collection).\n */\nexport type VerifierIssueCategory =\n | 'declaredMissing'\n | 'declaredIncompatible'\n | 'valueDrift'\n | 'extraNestedElement'\n | 'extraAuxiliary'\n | 'extraTopLevelObject';\n\n/**\n * Grades a target-neutral issue category against a control policy.\n *\n * - `observed` warns on everything.\n * - `tolerated` suppresses only an extra nested element (everything else fails).\n * - `external` suppresses every extra category and value drift (existence and\n * declared-shape divergences still fail).\n * - `managed` (and any other) fails.\n */\nexport function dispositionForCategory(\n controlPolicy: ControlPolicy,\n category: VerifierIssueCategory,\n): VerifierOutcome {\n if (controlPolicy === 'observed') {\n return 'warn';\n }\n if (controlPolicy === 'tolerated' && category === 'extraNestedElement') {\n return 'suppress';\n }\n if (controlPolicy === 'external') {\n if (\n category === 'extraNestedElement' ||\n category === 'extraAuxiliary' ||\n category === 'extraTopLevelObject' ||\n category === 'valueDrift'\n ) {\n return 'suppress';\n }\n }\n return 'fail';\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"control.mjs","names":[],"sources":["../src/control/control-capabilities.ts","../src/control/control-operation-results.ts","../src/control/control-schema-view.ts","../src/control/control-spaces.ts","../src/control/control-stack.ts","../src/control/schema-diff.ts","../src/control/verifier-disposition.ts"],"sourcesContent":["import type { ControlTargetDescriptor } from './control-descriptors';\nimport type { ControlFamilyInstance } from './control-instances';\nimport type { MigrationPlanOperation, TargetMigrationsCapability } from './control-migration-types';\nimport type { OperationPreview } from './control-operation-preview';\nimport type { CoreSchemaView } from './control-schema-view';\nimport type { PslDocumentAst } from './psl-ast';\nimport type { SchemaDiffIssue } from './schema-diff';\n\nexport interface MigratableTargetDescriptor<\n TFamilyId extends string,\n TTargetId extends string,\n TFamilyInstance extends ControlFamilyInstance<TFamilyId, unknown> = ControlFamilyInstance<\n TFamilyId,\n unknown\n >,\n> extends ControlTargetDescriptor<TFamilyId, TTargetId> {\n readonly migrations: TargetMigrationsCapability<TFamilyId, TTargetId, TFamilyInstance>;\n}\n\nexport function hasMigrations<TFamilyId extends string, TTargetId extends string>(\n target: ControlTargetDescriptor<TFamilyId, TTargetId>,\n): target is MigratableTargetDescriptor<TFamilyId, TTargetId> {\n return 'migrations' in target && !!(target as Record<string, unknown>)['migrations'];\n}\n\nexport interface SchemaViewCapable<TSchemaIR = unknown> {\n toSchemaView(schema: TSchemaIR): CoreSchemaView;\n}\n\nexport function hasSchemaView<TFamilyId extends string, TSchemaIR>(\n instance: ControlFamilyInstance<TFamilyId, TSchemaIR>,\n): instance is ControlFamilyInstance<TFamilyId, TSchemaIR> & SchemaViewCapable<TSchemaIR> {\n return (\n 'toSchemaView' in instance &&\n typeof (instance as Record<string, unknown>)['toSchemaView'] === 'function'\n );\n}\n\n/**\n * Capability declaring that a family can infer a PSL contract AST from its\n * opaque introspected schema IR. Consumed by `prisma-next contract infer`.\n */\nexport interface PslContractInferCapable<TSchemaIR = unknown> {\n inferPslContract(schemaIR: TSchemaIR): PslDocumentAst;\n}\n\nexport function hasPslContractInfer<TFamilyId extends string, TSchemaIR>(\n instance: ControlFamilyInstance<TFamilyId, TSchemaIR>,\n): instance is ControlFamilyInstance<TFamilyId, TSchemaIR> & PslContractInferCapable<TSchemaIR> {\n return (\n 'inferPslContract' in instance &&\n typeof (instance as Record<string, unknown>)['inferPslContract'] === 'function'\n );\n}\n\n/**\n * Capability declaring that a family can render a textual preview of migration\n * operations for the CLI's \"DDL preview\" output. SQL families emit\n * `language: 'sql'` statements; Mongo families emit `language: 'mongodb-shell'`.\n */\nexport interface OperationPreviewCapable {\n toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview;\n}\n\nexport function hasOperationPreview<TFamilyId extends string, TSchemaIR>(\n instance: ControlFamilyInstance<TFamilyId, TSchemaIR>,\n): instance is ControlFamilyInstance<TFamilyId, TSchemaIR> & OperationPreviewCapable {\n return (\n 'toOperationPreview' in instance &&\n typeof (instance as Record<string, unknown>)['toOperationPreview'] === 'function'\n );\n}\n\n/**\n * The granularity of a {@link SchemaDiffIssue}'s subject, resolved on demand\n * from the issue's node `nodeKind` — never stamped on the issue or the node.\n *\n * - `namespace`: a whole namespace.\n * - `entity`: a whole top-level entity (the thing a namespace contains).\n * - `field`: a field of an entity.\n * - `auxiliary`: a secondary part of an entity (an index, a default, a key).\n * - `structural`: a cross-cutting object (an access policy, a tree root) that\n * is the owning space's own concern, never a sibling's unclaimed entity —\n * its extras fail verify in both modes.\n */\nexport type DiffSubjectGranularity = 'namespace' | 'entity' | 'field' | 'auxiliary' | 'structural';\n\n/**\n * Capability declaring that a family can classify a {@link SchemaDiffIssue}'s\n * subject granularity, and separately its storage `entityKind`, on demand —\n * both resolved from its node's `nodeKind` through the family/target\n * vocabulary it owns. Consumed by framework code that spans contract spaces\n * (the migration aggregate's unclaimed-elements sweep) and cannot itself read\n * family/target node vocabulary, so it asks this capability instead of\n * hardcoding a family entity kind. `undefined` when the issue's node kind is\n * unrecognized, or when the family injects no classifier at all — callers\n * fall back to path shape in that case.\n *\n * `classifyEntityKind` returns the same per-family vocabulary as the contract\n * storage's `entries` dictionary keys (the vocabulary\n * {@link import('../ir/storage').elementCoordinates} walks) — never a\n * granularity word, and never a word this framework layer names itself.\n */\nexport interface SchemaSubjectClassifierCapable {\n classifySubjectGranularity(issue: SchemaDiffIssue): DiffSubjectGranularity | undefined;\n classifyEntityKind(issue: SchemaDiffIssue): string | undefined;\n}\n\nexport function hasSchemaSubjectClassifier<TFamilyId extends string, TSchemaIR>(\n instance: ControlFamilyInstance<TFamilyId, TSchemaIR>,\n): instance is ControlFamilyInstance<TFamilyId, TSchemaIR> & SchemaSubjectClassifierCapable {\n return (\n 'classifySubjectGranularity' in instance &&\n typeof (instance as Record<string, unknown>)['classifySubjectGranularity'] === 'function' &&\n 'classifyEntityKind' in instance &&\n typeof (instance as Record<string, unknown>)['classifyEntityKind'] === 'function'\n );\n}\n","import type { SchemaDiffIssue } from './schema-diff';\n\nexport const VERIFY_CODE_MARKER_MISSING = 'PN-RUN-3001';\nexport const VERIFY_CODE_HASH_MISMATCH = 'PN-RUN-3002';\nexport const VERIFY_CODE_TARGET_MISMATCH = 'PN-RUN-3003';\nexport const VERIFY_CODE_SCHEMA_FAILURE = 'PN-RUN-3010';\n\nexport interface OperationContext {\n readonly contractPath?: string;\n readonly configPath?: string;\n readonly meta?: Readonly<Record<string, unknown>>;\n}\n\nexport interface VerifyDatabaseResult {\n readonly ok: boolean;\n readonly code?: string;\n readonly summary: string;\n readonly contract: {\n readonly storageHash: string;\n readonly profileHash?: string;\n };\n readonly marker?: {\n readonly storageHash?: string;\n readonly profileHash?: string;\n };\n readonly target: {\n readonly expected: string;\n readonly actual?: string;\n };\n readonly missingCodecs?: readonly string[];\n readonly codecCoverageSkipped?: boolean;\n readonly meta?: {\n readonly configPath?: string;\n readonly contractPath: string;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\n/**\n * The three ways an actual state can fail an expectation: it contains a node\n * that was not expected, lacks a node that was expected, or holds a node that\n * is not equal to the expected one. Expected is the desired side and actual the\n * current side of whatever comparison produced the issue — contract-vs-database,\n * or contract-vs-contract in an offline plan — so the vocabulary is\n * comparison-relative and never ambiguous about a base.\n *\n * The failure reason is a structural characteristic carried as a declared\n * field: consumers filter on `reason`, never by enumerating kind strings or\n * family-invented node codes.\n */\nexport type ExpectationFailureReason = 'not-expected' | 'not-found' | 'not-equal';\n\n/**\n * The issue-based schema-verify result. `ok` derives from the FAILURE list\n * only: a verify passes exactly when `schema.issues` is empty, post\n * strict-gating and control-policy disposition.\n *\n * `schema.warnings` carries warn-graded issues (an `observed`-policy\n * subject's drift, and any other `warn` disposition) in the same shape.\n * Warnings are informational — they never affect `ok` — but they MUST be\n * surfaced: an `observed` table that drifted yields `ok: true` with a\n * non-empty warnings channel, which is what distinguishes \"watch without\n * failing\" from full suppression.\n */\nexport interface VerifyDatabaseSchemaResult {\n readonly ok: boolean;\n readonly code?: string;\n readonly summary: string;\n readonly contract: {\n readonly storageHash: string;\n readonly profileHash?: string;\n };\n readonly target: {\n readonly expected: string;\n readonly actual?: string;\n };\n readonly schema: {\n readonly issues: readonly SchemaDiffIssue[];\n readonly warnings?: {\n readonly issues: readonly SchemaDiffIssue[];\n };\n };\n readonly meta?: {\n readonly configPath?: string;\n readonly contractPath?: string;\n readonly strict: boolean;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\nexport interface EmitContractResult {\n readonly contractJson: string;\n readonly contractDts: string;\n readonly storageHash: string;\n readonly executionHash?: string;\n readonly profileHash: string;\n}\n\nexport interface IntrospectSchemaResult<TSchemaIR> {\n readonly ok: true;\n readonly summary: string;\n readonly target: {\n readonly familyId: string;\n readonly id: string;\n };\n readonly schema: TSchemaIR;\n readonly meta?: {\n readonly configPath?: string;\n readonly dbUrl?: string;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\nexport interface SignDatabaseResult {\n readonly ok: boolean;\n readonly summary: string;\n readonly contract: {\n readonly storageHash: string;\n readonly profileHash?: string;\n };\n readonly target: {\n readonly expected: string;\n readonly actual?: string;\n };\n readonly marker: {\n readonly created: boolean;\n readonly updated: boolean;\n readonly previous?: {\n readonly storageHash?: string;\n readonly profileHash?: string;\n };\n };\n readonly meta?: {\n readonly configPath?: string;\n readonly contractPath: string;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n","/**\n * Core schema view types for family-agnostic schema visualization.\n *\n * These types provide a minimal, generic, tree-shaped representation of schemas\n * across families, designed for CLI visualization and lightweight tooling.\n *\n * Families can optionally project their family-specific Schema IR into this\n * core view via the `toSchemaView` method on `FamilyInstance`.\n */\n\nexport type SchemaViewNodeKind =\n | 'root'\n | 'namespace'\n | 'collection'\n | 'entity'\n | 'field'\n | 'index'\n | 'dependency';\n\nexport interface SchemaTreeVisitor<R> {\n visit(node: SchemaTreeNode): R;\n}\n\nexport interface SchemaTreeNodeOptions {\n readonly kind: SchemaViewNodeKind;\n readonly id: string;\n readonly label: string;\n readonly meta?: Record<string, unknown>;\n readonly children?: readonly SchemaTreeNode[];\n}\n\nexport class SchemaTreeNode {\n readonly kind: SchemaViewNodeKind;\n readonly id: string;\n readonly label: string;\n readonly meta?: Record<string, unknown>;\n readonly children?: readonly SchemaTreeNode[];\n\n constructor(options: SchemaTreeNodeOptions) {\n this.kind = options.kind;\n this.id = options.id;\n this.label = options.label;\n if (options.meta !== undefined) this.meta = options.meta;\n if (options.children !== undefined) this.children = options.children;\n Object.freeze(this);\n }\n\n accept<R>(visitor: SchemaTreeVisitor<R>): R {\n return visitor.visit(this);\n }\n}\n\n/**\n * Core schema view providing a family-agnostic tree representation of a schema.\n * Used by CLI and cross-family tooling for visualization.\n */\nexport interface CoreSchemaView {\n readonly root: SchemaTreeNode;\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport type { MigrationMetadata, MigrationPlanOperation } from './control-migration-types';\n\n/**\n * Canonical control-plane identifiers for contract spaces.\n *\n * A contract space is the disjoint `(contract.json, migration-graph)` unit\n * the per-space planner / runner / verifier (project: extension contract\n * spaces, TML-2397) operates on. The application owns one well-known\n * space — the value below — and each loaded extension that contributes\n * schema owns a uniquely-named space.\n *\n * Lives in `framework-components/control` so every layer that has to\n * reason about space identity (the migration tooling, the SQL runtime's\n * marker reader, target-side statement builders, target-side adapters)\n * can import a single value rather than duplicating the literal. Raw\n * `'app'` string literals in framework / target / runtime / adapter\n * source code are forbidden and policed by\n * `scripts/lint-app-space-id.mjs` (wired into `pnpm lint:deps`).\n *\n * @see specs/framework-mechanism.spec.md § 3 — Layout convention (γ).\n */\nexport const APP_SPACE_ID = 'app' as const;\n\n/**\n * Head ref for a contract space — the `(hash, invariants)` tuple\n * a runner targets when applying that space's migration graph. Identical\n * in shape to the on-disk `migrations/<space-id>/refs/head.json` the\n * framework writes per loaded extension, and to the app-space\n * `<projectRoot>/refs/head.json`. Family-agnostic: SQL, Mongo, and any\n * future family share the same head-ref shape.\n *\n * @see specs/framework-mechanism.spec.md § 1.\n */\nexport interface ContractSpaceHeadRef {\n readonly hash: string;\n readonly invariants: readonly string[];\n}\n\n/**\n * Canonical structural shape of a migration package — the unit a planner\n * produces and a runner consumes: a directory name, the metadata\n * envelope, and the operation list.\n *\n * In-memory by default. Readers in `@prisma-next/migration-tools`\n * (`readMigrationPackage` / `readMigrationsDir`) return the augmented\n * {@link import('@prisma-next/migration-tools/package').OnDiskMigrationPackage}\n * variant which adds `dirPath`; everything else operates against the\n * canonical shape so the same value flows through pre-emission\n * authoring, on-disk loading, and runner execution without conversion.\n *\n * @see specs/framework-mechanism.spec.md § 1.\n */\nexport interface MigrationPackage {\n readonly dirName: string;\n readonly metadata: MigrationMetadata;\n readonly ops: readonly MigrationPlanOperation[];\n /**\n * Contract IR JSON of this migration's destination state, populated by\n * the on-disk readers from the sibling `end-contract.json` file when\n * present (raw parsed JSON). Absent for packages loaded without the\n * snapshot file — the runner never requires it (see ADR 199: identity\n * is anchored on the storage-hash bookends). The edge's *start* state\n * is deliberately not carried: it is by construction the end state of\n * the predecessor edge, so consumers derive it from the previous row.\n */\n readonly endContractJson?: unknown;\n}\n\n/**\n * Canonical structural shape of a contract space — one disjoint\n * `(contractJson, migration-graph)` unit the per-space planner / runner\n * / verifier operates on. The application owns one well-known space\n * ({@link APP_SPACE_ID}); each loaded extension that contributes schema\n * owns a uniquely-named space. Whether a value is the app's space or an\n * extension's space is a control-plane concern; the type carries no\n * such distinction.\n *\n * Generic over the contract so each family pins a typed contract value\n * at consumption time. The SQL family specialises to\n * `ContractSpace<Contract<SqlStorage>>` at the descriptor surface;\n * Mongo's symmetrical `ContractSpace<Contract<MongoStorage>>` will land\n * with that family.\n *\n * @see specs/framework-mechanism.spec.md § 1.\n */\nexport interface ContractSpace<TContract extends Contract = Contract> {\n readonly contractJson: TContract;\n readonly migrations: readonly MigrationPackage[];\n readonly headRef: ContractSpaceHeadRef;\n}\n","import type { Contract, JsonValue } from '@prisma-next/contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { CapabilityMatrix } from '../shared/capabilities';\nimport { mergeCapabilityMatrices } from '../shared/capabilities';\nimport type { Codec } from '../shared/codec';\nimport type { AnyCodecDescriptor } from '../shared/codec-descriptor';\nimport type { CodecLookup, CodecMeta, CodecRef, CodecRegistry } from '../shared/codec-types';\nimport type {\n AuthoringContributions,\n AuthoringEntityTypeNamespace,\n AuthoringFieldNamespace,\n AuthoringModelAttributeDescriptorNamespace,\n AuthoringPslBlockDescriptorNamespace,\n AuthoringTypeNamespace,\n} from '../shared/framework-authoring';\nimport {\n assertNoCrossRegistryCollisions,\n mergeAuthoringNamespaces,\n} from '../shared/framework-authoring';\nimport type { ComponentMetadata } from '../shared/framework-components';\nimport type {\n ControlMutationDefaultEntry,\n ControlMutationDefaults,\n MutationDefaultGeneratorDescriptor,\n} from '../shared/mutation-default-types';\nimport {\n CONTRACT_CODEC_DESCRIPTOR_MISSING,\n materializeCodec,\n resolveCodecDescriptorOrThrow,\n} from '../shared/resolve-codec';\nimport type { TypesImportSpec } from '../shared/types-import-spec';\nimport type {\n ControlAdapterDescriptor,\n ControlDriverDescriptor,\n ControlExtensionDescriptor,\n ControlFamilyDescriptor,\n ControlTargetDescriptor,\n} from './control-descriptors';\n\nexport interface AssembledAuthoringContributions {\n readonly field: AuthoringFieldNamespace;\n readonly type: AuthoringTypeNamespace;\n readonly entityTypes: AuthoringEntityTypeNamespace;\n readonly pslBlockDescriptors: AuthoringPslBlockDescriptorNamespace;\n readonly modelAttributes: AuthoringModelAttributeDescriptorNamespace;\n}\n\nexport interface ControlStack<\n TFamilyId extends string = string,\n TTargetId extends string = string,\n> {\n readonly family: ControlFamilyDescriptor<TFamilyId>;\n readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;\n readonly adapter?: ControlAdapterDescriptor<TFamilyId, TTargetId> | undefined;\n readonly driver?: ControlDriverDescriptor<TFamilyId, TTargetId> | undefined;\n readonly extensionPacks: readonly ControlExtensionDescriptor<TFamilyId, TTargetId>[];\n\n readonly extensionContracts: ReadonlyMap<string, Contract>;\n\n readonly codecTypeImports: ReadonlyArray<TypesImportSpec>;\n readonly queryOperationTypeImports: ReadonlyArray<TypesImportSpec>;\n readonly extensionIds: ReadonlyArray<string>;\n readonly codecLookup: CodecRegistry;\n readonly authoringContributions: AssembledAuthoringContributions;\n readonly scalarTypeDescriptors: ReadonlyMap<string, string>;\n readonly controlMutationDefaults: ControlMutationDefaults;\n readonly capabilities: CapabilityMatrix;\n}\n\nexport interface CreateControlStackInput<\n TFamilyId extends string = string,\n TTargetId extends string = string,\n> {\n readonly family: ControlFamilyDescriptor<TFamilyId>;\n readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;\n readonly adapter?: ControlAdapterDescriptor<TFamilyId, TTargetId> | undefined;\n readonly driver?: ControlDriverDescriptor<TFamilyId, TTargetId> | undefined;\n readonly extensionPacks?:\n | ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>\n | undefined;\n}\n\nfunction addUniqueId(ids: string[], seen: Set<string>, id: string): void {\n if (!seen.has(id)) {\n ids.push(id);\n seen.add(id);\n }\n}\n\nexport function assertUniqueCodecOwner(options: {\n readonly codecId: string;\n readonly owners: Map<string, string>;\n readonly descriptorId: string;\n readonly entityLabel: string;\n readonly entityOwnershipLabel: string;\n}): void {\n const existingOwner = options.owners.get(options.codecId);\n if (existingOwner !== undefined) {\n throw new Error(\n `Duplicate ${options.entityLabel} for codecId \"${options.codecId}\". ` +\n `Descriptor \"${options.descriptorId}\" conflicts with \"${existingOwner}\". ` +\n `Each codecId can only have one ${options.entityOwnershipLabel}.`,\n );\n }\n}\n\nexport function extractCodecTypeImports(\n descriptors: ReadonlyArray<Pick<ComponentMetadata, 'types'>>,\n): ReadonlyArray<TypesImportSpec> {\n const imports: TypesImportSpec[] = [];\n\n for (const descriptor of descriptors) {\n const codecTypes = descriptor.types?.codecTypes;\n if (codecTypes?.import) {\n imports.push(codecTypes.import);\n }\n if (codecTypes?.typeImports) {\n imports.push(...codecTypes.typeImports);\n }\n }\n\n return imports;\n}\n\nexport function extractQueryOperationTypeImports(\n descriptors: ReadonlyArray<Pick<ComponentMetadata, 'types'>>,\n): ReadonlyArray<TypesImportSpec> {\n const imports: TypesImportSpec[] = [];\n\n for (const descriptor of descriptors) {\n const queryOperationTypes = descriptor.types?.queryOperationTypes;\n if (queryOperationTypes?.import) {\n imports.push(queryOperationTypes.import);\n }\n }\n\n return imports;\n}\n\nexport function extractComponentIds(\n family: { readonly id: string },\n target: { readonly id: string },\n adapter: { readonly id: string } | undefined,\n extensions: ReadonlyArray<{ readonly id: string }>,\n): ReadonlyArray<string> {\n const ids: string[] = [];\n const seen = new Set<string>();\n\n addUniqueId(ids, seen, family.id);\n addUniqueId(ids, seen, target.id);\n if (adapter) {\n addUniqueId(ids, seen, adapter.id);\n }\n\n for (const ext of extensions) {\n addUniqueId(ids, seen, ext.id);\n }\n\n return ids;\n}\n\nexport function assembleAuthoringContributions(\n descriptors: ReadonlyArray<{ readonly authoring?: AuthoringContributions }>,\n): AssembledAuthoringContributions {\n const field = {} as Record<string, unknown>;\n const type = {} as Record<string, unknown>;\n const entityTypes = {} as Record<string, unknown>;\n const pslBlockDescriptors: Record<string, unknown> = {};\n const modelAttributes: Record<string, unknown> = {};\n\n for (const descriptor of descriptors) {\n if (descriptor.authoring?.field) {\n mergeAuthoringNamespaces(field, descriptor.authoring.field, [], 'fieldPreset', 'field');\n }\n if (descriptor.authoring?.type) {\n mergeAuthoringNamespaces(type, descriptor.authoring.type, [], 'typeConstructor', 'type');\n }\n if (descriptor.authoring?.entityTypes) {\n mergeAuthoringNamespaces(\n entityTypes,\n descriptor.authoring.entityTypes,\n [],\n 'entity',\n 'entity',\n );\n }\n if (descriptor.authoring?.pslBlockDescriptors) {\n mergeAuthoringNamespaces(\n pslBlockDescriptors,\n descriptor.authoring.pslBlockDescriptors,\n [],\n 'pslBlock',\n 'pslBlock',\n );\n }\n if (descriptor.authoring?.modelAttributes) {\n mergeAuthoringNamespaces(\n modelAttributes,\n descriptor.authoring.modelAttributes,\n [],\n 'modelAttribute',\n 'modelAttribute',\n );\n }\n }\n\n const fieldNamespace = field as AuthoringFieldNamespace;\n const typeNamespace = type as AuthoringTypeNamespace;\n const entityTypeNamespace = entityTypes as AuthoringEntityTypeNamespace;\n const pslBlockDescriptorNamespace = blindCast<\n AuthoringPslBlockDescriptorNamespace,\n 'merge target accumulator narrows to typed namespace post-merge'\n >(pslBlockDescriptors);\n const modelAttributeNamespace = blindCast<\n AuthoringModelAttributeDescriptorNamespace,\n 'merge target accumulator narrows to typed namespace post-merge'\n >(modelAttributes);\n assertNoCrossRegistryCollisions(\n typeNamespace,\n fieldNamespace,\n entityTypeNamespace,\n pslBlockDescriptorNamespace,\n modelAttributeNamespace,\n );\n\n return {\n field: fieldNamespace,\n type: typeNamespace,\n entityTypes: entityTypeNamespace,\n pslBlockDescriptors: pslBlockDescriptorNamespace,\n modelAttributes: modelAttributeNamespace,\n };\n}\n\nexport function assembleScalarTypeDescriptors(\n descriptors: ReadonlyArray<\n Pick<ComponentMetadata, 'scalarTypeDescriptors'> & { readonly id?: string }\n >,\n): ReadonlyMap<string, string> {\n const result = new Map<string, string>();\n const owners = new Map<string, string>();\n\n for (const descriptor of descriptors) {\n const descriptorMap = descriptor.scalarTypeDescriptors;\n if (!descriptorMap) continue;\n const descriptorId = descriptor.id ?? '<unknown>';\n for (const [typeName, codecId] of descriptorMap) {\n const existingOwner = owners.get(typeName);\n if (existingOwner !== undefined) {\n throw new Error(\n `Duplicate scalar type descriptor \"${typeName}\". ` +\n `Descriptor \"${descriptorId}\" conflicts with \"${existingOwner}\".`,\n );\n }\n result.set(typeName, codecId);\n owners.set(typeName, descriptorId);\n }\n }\n\n return result;\n}\n\nexport function assembleControlMutationDefaults(\n descriptors: ReadonlyArray<\n Pick<ComponentMetadata, 'controlMutationDefaults'> & { readonly id?: string }\n >,\n): ControlMutationDefaults {\n const defaultFunctionRegistry = new Map<string, ControlMutationDefaultEntry>();\n const functionOwners = new Map<string, string>();\n const generatorMap = new Map<string, MutationDefaultGeneratorDescriptor>();\n const generatorOwners = new Map<string, string>();\n\n for (const descriptor of descriptors) {\n const contributions = descriptor.controlMutationDefaults;\n if (!contributions) continue;\n const descriptorId = descriptor.id ?? '<unknown>';\n\n for (const generatorDescriptor of contributions.generatorDescriptors) {\n const existingOwner = generatorOwners.get(generatorDescriptor.id);\n if (existingOwner !== undefined) {\n throw new Error(\n `Duplicate mutation default generator id \"${generatorDescriptor.id}\". ` +\n `Descriptor \"${descriptorId}\" conflicts with \"${existingOwner}\".`,\n );\n }\n generatorMap.set(generatorDescriptor.id, generatorDescriptor);\n generatorOwners.set(generatorDescriptor.id, descriptorId);\n }\n\n for (const [functionName, handler] of contributions.defaultFunctionRegistry) {\n const existingOwner = functionOwners.get(functionName);\n if (existingOwner !== undefined) {\n throw new Error(\n `Duplicate mutation default function \"${functionName}\". ` +\n `Descriptor \"${descriptorId}\" conflicts with \"${existingOwner}\".`,\n );\n }\n defaultFunctionRegistry.set(functionName, handler);\n functionOwners.set(functionName, descriptorId);\n }\n }\n\n return {\n defaultFunctionRegistry,\n generatorDescriptors: Array.from(generatorMap.values()),\n };\n}\n\nexport function extractCodecLookup(\n descriptors: ReadonlyArray<Pick<ComponentMetadata & { id: string }, 'types' | 'id'>>,\n): CodecRegistry {\n const byId = new Map<string, Codec>();\n const descriptorsById = new Map<string, AnyCodecDescriptor>();\n const targetTypesById = new Map<string, readonly string[]>();\n const metaById = new Map<string, CodecMeta>();\n const metaRenderersById = new Map<\n string,\n (params: Record<string, unknown> | JsonValue) => CodecMeta | undefined\n >();\n const renderersById = new Map<string, (params: Record<string, unknown>) => string | undefined>();\n const inputRenderersById = new Map<\n string,\n (params: Record<string, unknown>) => string | undefined\n >();\n const valueLiteralRenderersById = new Map<\n string,\n (value: JsonValue, side: 'output' | 'input') => string | undefined\n >();\n const owners = new Map<string, string>();\n for (const descriptor of descriptors) {\n const codecTypes = descriptor.types?.codecTypes;\n const descriptorId = descriptor.id;\n // Descriptor-side metadata is the single source of truth for `targetTypes` / `meta` / `renderOutputType`. A component contributes its codecs by listing `codecDescriptors` on `types.codecTypes`; each codecId has exactly one contributor across the stack.\n for (const codecDescriptor of codecTypes?.codecDescriptors ?? []) {\n assertUniqueCodecOwner({\n codecId: codecDescriptor.codecId,\n owners,\n descriptorId,\n entityLabel: 'codec descriptor',\n entityOwnershipLabel: 'codec descriptor provider',\n });\n owners.set(codecDescriptor.codecId, descriptorId);\n descriptorsById.set(codecDescriptor.codecId, codecDescriptor);\n if (Array.isArray(codecDescriptor.targetTypes)) {\n targetTypesById.set(codecDescriptor.codecId, codecDescriptor.targetTypes);\n }\n if (codecDescriptor.meta !== undefined) {\n metaById.set(codecDescriptor.codecId, codecDescriptor.meta);\n }\n if (typeof codecDescriptor.metaFor === 'function') {\n metaRenderersById.set(codecDescriptor.codecId, codecDescriptor.metaFor);\n }\n if (typeof codecDescriptor.renderOutputType === 'function') {\n renderersById.set(codecDescriptor.codecId, codecDescriptor.renderOutputType);\n }\n if (typeof codecDescriptor.renderInputType === 'function') {\n inputRenderersById.set(codecDescriptor.codecId, codecDescriptor.renderInputType);\n }\n if (typeof codecDescriptor.renderValueLiteral === 'function') {\n valueLiteralRenderersById.set(codecDescriptor.codecId, codecDescriptor.renderValueLiteral);\n }\n // Materialize a representative `Codec` instance for `byId.get()` so consumers reading the lookup's instance side (e.g. SQL renderer's cast-policy lookup, or the contract emitter's literal-default `encodeJson` resolver) keep finding the codec.\n //\n // Two cohorts:\n // - Non-parameterized descriptors: factory must succeed; any throw is a real bug and we let it propagate (no silent try/catch).\n // - Parameterized descriptors: try with empty params. Many parameterized codecs treat params as advisory (e.g. `pg/timestamptz@1` whose precision is rendered into the `nativeType` only and never read by the runtime codec), so an empty-params construction yields a usable representative for id-keyed lookups (e.g. emit-time literal-default encoding). Codecs whose factory genuinely requires params (e.g. `pg/vector@1` threading `length` into the runtime codec) will throw; for those, per-column instances are materialized at runtime by `buildContractCodecRegistry` and the id-keyed lookup miss is correct (the column-aware path resolves them).\n if (!byId.has(codecDescriptor.codecId)) {\n if (codecDescriptor.isParameterized) {\n try {\n const representative = codecDescriptor.factory({} as never)({\n name: `<lookup:${codecDescriptor.codecId}>`,\n } as Parameters<ReturnType<typeof codecDescriptor.factory>>[0]);\n byId.set(codecDescriptor.codecId, representative);\n } catch {\n // Factory requires concrete params; skip representative materialization. Per-column instances are built at runtime; id-keyed lookup miss is the correct outcome here.\n }\n } else {\n const representative = codecDescriptor.factory(undefined as never)({\n name: `<lookup:${codecDescriptor.codecId}>`,\n } as Parameters<ReturnType<typeof codecDescriptor.factory>>[0]);\n byId.set(codecDescriptor.codecId, representative);\n }\n }\n }\n }\n return {\n get: (id) => byId.get(id),\n forCodecRef(ref: CodecRef) {\n const d = resolveCodecDescriptorOrThrow(\n (id) => descriptorsById.get(id),\n ref,\n CONTRACT_CODEC_DESCRIPTOR_MISSING,\n );\n return materializeCodec(d, ref, { name: `<ref:${ref.codecId}>` });\n },\n forColumn: () => undefined,\n targetTypesFor: (id) => targetTypesById.get(id),\n metaFor: (id, typeParams) => {\n if (typeParams !== undefined) {\n const paramsAware = metaRenderersById.get(id)?.(typeParams);\n if (paramsAware !== undefined) return paramsAware;\n }\n return metaById.get(id);\n },\n renderOutputTypeFor: (id, params) => renderersById.get(id)?.(params),\n renderInputTypeFor: (id, params) => inputRenderersById.get(id)?.(params),\n renderValueLiteralFor: (id, value, side) => valueLiteralRenderersById.get(id)?.(value, side),\n descriptorFor: (id) => descriptorsById.get(id),\n };\n}\n\nexport function validateScalarTypeCodecIds(\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n codecLookup: CodecLookup,\n): string[] {\n const errors: string[] = [];\n for (const [typeName, codecId] of scalarTypeDescriptors) {\n if (!codecLookup.get(codecId)) {\n errors.push(\n `Scalar type \"${typeName}\" references codec \"${codecId}\" which is not registered by any component.`,\n );\n }\n }\n return errors;\n}\n\ninterface DependencyDeclaringDescriptor {\n readonly id: string;\n readonly contractSpace?: {\n readonly contractJson?: {\n readonly extensionPacks?: Readonly<Record<string, unknown>>;\n };\n };\n}\n\nfunction assembleExtensionContracts(\n extensions: ReadonlyArray<\n Pick<ControlExtensionDescriptor<string, string>, 'id' | 'contractSpace'>\n >,\n): ReadonlyMap<string, Contract> {\n const result = new Map<string, Contract>();\n for (const ext of extensions) {\n if (ext.contractSpace === undefined) continue;\n result.set(ext.id, ext.contractSpace.contractJson);\n }\n return result;\n}\n\nfunction readDeclaredDependencyIds(descriptor: DependencyDeclaringDescriptor): readonly string[] {\n const packs = descriptor.contractSpace?.contractJson?.extensionPacks;\n if (packs === null || typeof packs !== 'object') return [];\n return Object.keys(packs);\n}\n\n/**\n * Builds a dependency-respecting load order for the given extension descriptors\n * using Kahn's topological sort algorithm. Dependencies (packs declared in\n * `contractSpace.contractJson.extensionPacks`) are placed before the extensions\n * that depend on them.\n *\n * Throws if the dependency graph contains a cycle, with an error message that\n * names every extension involved in the cycle.\n *\n * Throws if any extension declares a dependency on a pack ID that is not present\n * in the provided list — add the missing pack to the `extensionPacks` list to\n * resolve the error.\n */\n\nexport function buildExtensionLoadOrder(\n extensions: ReadonlyArray<DependencyDeclaringDescriptor>,\n): readonly string[] {\n if (extensions.length === 0) return [];\n\n const idSet = new Set(extensions.map((e) => e.id));\n const inDegree = new Map<string, number>();\n const dependents = new Map<string, string[]>();\n\n for (const ext of extensions) {\n if (!inDegree.has(ext.id)) inDegree.set(ext.id, 0);\n if (!dependents.has(ext.id)) dependents.set(ext.id, []);\n }\n\n for (const ext of extensions) {\n for (const depId of readDeclaredDependencyIds(ext)) {\n if (!idSet.has(depId)) {\n throw new Error(\n `Extension \"${ext.id}\" declares a dependency on \"${depId}\", but \"${depId}\" is not in the provided extension set. Add the missing space to extensionPacks.`,\n );\n }\n inDegree.set(ext.id, (inDegree.get(ext.id) ?? 0) + 1);\n const list = dependents.get(depId);\n if (list !== undefined) list.push(ext.id);\n }\n }\n\n const queue: string[] = [];\n for (const [id, deg] of inDegree) {\n if (deg === 0) queue.push(id);\n }\n queue.sort();\n\n const result: string[] = [];\n while (queue.length > 0) {\n const id = queue.shift();\n if (id === undefined) break;\n result.push(id);\n const children = dependents.get(id) ?? [];\n children.sort();\n for (const childId of children) {\n const newDeg = (inDegree.get(childId) ?? 1) - 1;\n inDegree.set(childId, newDeg);\n if (newDeg === 0) queue.push(childId);\n }\n }\n\n if (result.length < extensions.length) {\n const cycleMembers = extensions\n .map((e) => e.id)\n .filter((id) => !result.includes(id))\n .sort();\n throw new Error(\n `Extension dependency cycle detected. Cycle members: ${cycleMembers.map((id) => `\"${id}\"`).join(', ')}.`,\n );\n }\n\n return result;\n}\n\nexport function createControlStack<TFamilyId extends string, TTargetId extends string>(\n input: CreateControlStackInput<TFamilyId, TTargetId>,\n): ControlStack<TFamilyId, TTargetId> {\n const { family, target, adapter, driver, extensionPacks = [] } = input;\n\n const orderedIds = buildExtensionLoadOrder(extensionPacks);\n const extensionById = new Map(extensionPacks.map((ext) => [ext.id, ext]));\n const orderedExtensionPacks = orderedIds\n .map((id) => extensionById.get(id))\n .filter((ext): ext is ControlExtensionDescriptor<TFamilyId, TTargetId> => ext !== undefined);\n\n const allDescriptors = [family, target, ...(adapter ? [adapter] : []), ...orderedExtensionPacks];\n\n const codecLookup = extractCodecLookup(allDescriptors);\n const scalarTypeDescriptors = assembleScalarTypeDescriptors(allDescriptors);\n\n return {\n family,\n target,\n adapter,\n driver,\n extensionPacks: orderedExtensionPacks,\n extensionContracts: assembleExtensionContracts(orderedExtensionPacks),\n\n codecTypeImports: extractCodecTypeImports(allDescriptors),\n queryOperationTypeImports: extractQueryOperationTypeImports(allDescriptors),\n extensionIds: extractComponentIds(family, target, adapter, orderedExtensionPacks),\n codecLookup,\n authoringContributions: assembleAuthoringContributions(allDescriptors),\n scalarTypeDescriptors,\n controlMutationDefaults: assembleControlMutationDefaults(allDescriptors),\n capabilities: mergeCapabilityMatrices({}, [\n target,\n ...(adapter ? [adapter] : []),\n ...orderedExtensionPacks,\n ]),\n };\n}\n","import type { ExpectationFailureReason } from './control-operation-results';\n\nexport interface SchemaDiffIssue<TNode extends DiffableNode = DiffableNode> {\n /** Path from the root node down to the diffed node, as a sequence of local keys. */\n readonly path: readonly string[];\n /** Why the actual state fails the expectation. Consumers filter on this field. */\n readonly reason: ExpectationFailureReason;\n /** The expected (desired-side) node, when available. Absent for `not-expected` issues. */\n readonly expected?: TNode;\n /** The actual (current-side) node, when available. Absent for `not-found` issues. */\n readonly actual?: TNode;\n}\n\n/**\n * A node in the schema tree. Every node in the tree implements this interface.\n *\n * The differ pairs siblings by the combination of `nodeKind` and `id`, not by\n * `id` alone: `id` needs only be unique among siblings of the same\n * `nodeKind` at the same level, not globally unique at that level. Two\n * distinct kinds of child in distinct slots (e.g. a role and a namespace) may\n * legitimately share a name — they are never paired against each other, so\n * the collision is harmless. A node never folds its kind into its id string\n * to route around this; `nodeKind` is the discriminant that does that job.\n * A same-`nodeKind`/same-`id` collision among siblings is a genuine\n * duplicate and is enforced by a throw. The differ accumulates ids (not\n * nodeKind) into a path that stamps every emitted issue.\n */\nexport interface DiffableNode {\n readonly id: string;\n readonly nodeKind: string;\n isEqualTo(other: DiffableNode): boolean;\n children(): readonly DiffableNode[];\n}\n\n/** Delimiter joining `nodeKind` and `id` into one sibling-map key. Every `nodeKind` is a code-defined literal (kebab-case-style), so a null character can never appear in one. */\nconst SIBLING_KEY_DELIMITER = '\\u0000';\n\nfunction siblingKey(node: DiffableNode): string {\n return `${node.nodeKind}${SIBLING_KEY_DELIMITER}${node.id}`;\n}\n\nfunction insertNode(map: Map<string, DiffableNode>, node: DiffableNode): void {\n const key = siblingKey(node);\n if (map.has(key)) {\n throw new Error(`diffSchemas: duplicate id among siblings: ${node.nodeKind}/${node.id}`);\n }\n map.set(key, node);\n}\n\nfunction emitMissingSubtree(node: DiffableNode, parentPath: readonly string[]): SchemaDiffIssue[] {\n const path = [...parentPath, node.id];\n return [\n {\n path,\n reason: 'not-found',\n expected: node,\n },\n ...node.children().flatMap((c) => emitMissingSubtree(c, path)),\n ];\n}\n\nfunction emitExtraSubtree(node: DiffableNode, parentPath: readonly string[]): SchemaDiffIssue[] {\n const path = [...parentPath, node.id];\n return [\n {\n path,\n reason: 'not-expected',\n actual: node,\n },\n ...node.children().flatMap((c) => emitExtraSubtree(c, path)),\n ];\n}\n\n/**\n * Diff two schema trees starting from their roots.\n *\n * The differ is **total**: every node-level difference is reported. An unmatched\n * non-leaf node emits its own issue and descends, emitting an issue for every\n * node in the missing/extra subtree. Coalescing a parent change over its\n * children is the planner's responsibility. Ownership filtering (dropping `extra`\n * issues in namespaces a contract doesn't own) is the caller's responsibility.\n */\nexport function diffSchemas(\n expected: DiffableNode,\n actual: DiffableNode,\n): readonly SchemaDiffIssue[] {\n return diffPair(expected, actual, []);\n}\n\nfunction diffPair(\n expected: DiffableNode,\n actual: DiffableNode,\n parentPath: readonly string[],\n): readonly SchemaDiffIssue[] {\n const path = [...parentPath, expected.id];\n const issues: SchemaDiffIssue[] = [];\n if (!expected.isEqualTo(actual)) {\n issues.push({\n path,\n reason: 'not-equal',\n expected,\n actual,\n });\n }\n issues.push(...diffChildren(expected.children(), actual.children(), path));\n return issues;\n}\n\n/**\n * Align one level of nodes by `(nodeKind, id)`; emit issues in input order\n * and recurse.\n *\n * A missing node emits one issue for itself and one for every node in its\n * subtree (total descent). Same for extra nodes. A matched pair recurses via\n * `diffPair`.\n */\nfunction diffChildren(\n expected: readonly DiffableNode[],\n actual: readonly DiffableNode[],\n parentPath: readonly string[],\n): readonly SchemaDiffIssue[] {\n const expectedMap = new Map<string, DiffableNode>();\n for (const node of expected) {\n insertNode(expectedMap, node);\n }\n\n const actualMap = new Map<string, DiffableNode>();\n for (const node of actual) {\n insertNode(actualMap, node);\n }\n\n const issues: SchemaDiffIssue[] = [];\n\n for (const [key, expectedNode] of expectedMap) {\n const actualNode = actualMap.get(key);\n if (actualNode === undefined) {\n issues.push(...emitMissingSubtree(expectedNode, parentPath));\n } else {\n issues.push(...diffPair(expectedNode, actualNode, parentPath));\n }\n }\n\n for (const [key, actualNode] of actualMap) {\n if (!expectedMap.has(key)) {\n issues.push(...emitExtraSubtree(actualNode, parentPath));\n }\n }\n\n return issues;\n}\n\n/**\n * The result of diffing a contract's expected schema against the introspected\n * actual schema: one node-typed issue list. Carries no verdict, verification\n * tree, or counts — those are the verifier's own presentation, built from the\n * same underlying comparison.\n *\n * `TNode` is the concrete schema-IR node the issues carry; it defaults to\n * `DiffableNode`, so this is purely additive — a caller that wants the\n * concrete node opts in (the Postgres planner uses the concrete node type),\n * everyone else keeps the default unchanged.\n */\nexport class SchemaDiff<TNode extends DiffableNode = DiffableNode> {\n readonly issues: readonly SchemaDiffIssue<TNode>[];\n\n constructor(issues: readonly SchemaDiffIssue<TNode>[]) {\n this.issues = issues;\n }\n\n /** Returns a new `SchemaDiff` narrowed to the issues `keep` returns true for. */\n filter(keep: (issue: SchemaDiffIssue<TNode>) => boolean): SchemaDiff<TNode> {\n return new SchemaDiff(this.issues.filter(keep));\n }\n}\n","import type { ControlPolicy } from '@prisma-next/contract/types';\n\nexport type VerificationStatus = 'pass' | 'warn' | 'fail';\n\nexport type VerifierOutcome = VerificationStatus | 'suppress';\n\n/**\n * Target-neutral classification of a verifier finding, abstracted away from any\n * one storage model's vocabulary. Each family classifies its own concrete issue\n * kinds into these categories; the framework only grades the category against a\n * control policy.\n *\n * - `declaredMissing` — a declared object/element is absent from the database.\n * - `declaredIncompatible` — a declared object/element exists but its shape diverges.\n * - `valueDrift` — the value set of an existing type drifted (e.g. enum values).\n * - `extraNestedElement` — an undeclared element nested inside a declared object\n * (a SQL column, a document field).\n * - `extraAuxiliary` — an undeclared auxiliary attached to a declared object\n * (a SQL constraint/index, a Mongo index/validator).\n * - `extraTopLevelObject` — an undeclared top-level object (a SQL table, a\n * Mongo collection).\n */\nexport type VerifierIssueCategory =\n | 'declaredMissing'\n | 'declaredIncompatible'\n | 'valueDrift'\n | 'extraNestedElement'\n | 'extraAuxiliary'\n | 'extraTopLevelObject';\n\n/**\n * Grades a target-neutral issue category against a control policy.\n *\n * - `observed` warns on everything.\n * - `tolerated` suppresses only an extra nested element (everything else fails).\n * - `external` suppresses every extra category and value drift (existence and\n * declared-shape divergences still fail).\n * - `managed` (and any other) fails.\n */\nexport function dispositionForCategory(\n controlPolicy: ControlPolicy,\n category: VerifierIssueCategory,\n): VerifierOutcome {\n if (controlPolicy === 'observed') {\n return 'warn';\n }\n if (controlPolicy === 'tolerated' && category === 'extraNestedElement') {\n return 'suppress';\n }\n if (controlPolicy === 'external') {\n if (\n category === 'extraNestedElement' ||\n category === 'extraAuxiliary' ||\n category === 'extraTopLevelObject' ||\n category === 'valueDrift'\n ) {\n return 'suppress';\n }\n }\n return 'fail';\n}\n"],"mappings":"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"} |
| import { t as TypesImportSpec } from "./types-import-spec-DRKzrJ20.mjs"; | ||
| import { n as GenerateContractTypesOptions, r as ValidationContext, t as EmissionSpi } from "./emission-types-C561PwcN.mjs"; | ||
| import { n as GenerateContractTypesOptions, r as ValidationContext, t as EmissionSpi } from "./emission-types-BQMFUNQO.mjs"; | ||
| export type { EmissionSpi, GenerateContractTypesOptions, TypesImportSpec, ValidationContext }; |
@@ -1,2 +0,2 @@ | ||
| import { b as TargetInstance, c as DriverDescriptor, d as ExtensionDescriptor, f as ExtensionInstance, h as FamilyInstance, l as DriverInstance, m as FamilyDescriptor, n as AdapterInstance, t as AdapterDescriptor, y as TargetDescriptor } from "./framework-components-5hA9ij1v.mjs"; | ||
| import { b as TargetInstance, c as DriverDescriptor, d as ExtensionDescriptor, f as ExtensionInstance, h as FamilyInstance, l as DriverInstance, m as FamilyDescriptor, n as AdapterInstance, t as AdapterDescriptor, y as TargetDescriptor } from "./framework-components-D1rRo9Oa.mjs"; | ||
@@ -3,0 +3,0 @@ //#region src/execution/execution-instances.d.ts |
| import { t as checkContractComponentRequirements } from "./framework-components-DbCS57go.mjs"; | ||
| //#region src/execution/execution-requirements.ts | ||
| function assertRuntimeContractRequirementsSatisfied({ contract, family, target, adapter, extensionPacks }) { | ||
| const providedComponentIds = new Set([ | ||
| const providedComponentIds = /* @__PURE__ */ new Set([ | ||
| family.id, | ||
@@ -6,0 +6,0 @@ target.id, |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"execution.mjs","names":[],"sources":["../src/execution/execution-requirements.ts","../src/execution/execution-stack.ts"],"sourcesContent":["import { checkContractComponentRequirements } from '../shared/framework-components';\nimport type {\n RuntimeAdapterDescriptor,\n RuntimeExtensionDescriptor,\n RuntimeFamilyDescriptor,\n RuntimeTargetDescriptor,\n} from './execution-descriptors';\n\nexport function assertRuntimeContractRequirementsSatisfied<\n TFamilyId extends string,\n TTargetId extends string,\n>({\n contract,\n family,\n target,\n adapter,\n extensionPacks,\n}: {\n readonly contract: { readonly target: string; readonly extensionPacks?: Record<string, unknown> };\n readonly family: RuntimeFamilyDescriptor<TFamilyId>;\n readonly target: RuntimeTargetDescriptor<TFamilyId, TTargetId>;\n readonly adapter: RuntimeAdapterDescriptor<TFamilyId, TTargetId>;\n readonly extensionPacks: readonly RuntimeExtensionDescriptor<TFamilyId, TTargetId>[];\n}): void {\n const providedComponentIds = new Set<string>([family.id, target.id, adapter.id]);\n for (const extension of extensionPacks) {\n providedComponentIds.add(extension.id);\n }\n\n const result = checkContractComponentRequirements({\n contract,\n expectedTargetId: target.targetId,\n providedComponentIds,\n });\n\n if (result.targetMismatch) {\n throw new Error(\n `Contract target '${result.targetMismatch.actual}' does not match runtime target descriptor '${result.targetMismatch.expected}'.`,\n );\n }\n\n for (const packId of result.missingExtensionPackIds) {\n throw new Error(\n `Contract requires extension pack '${packId}', but runtime descriptors do not provide a matching component.`,\n );\n }\n}\n","import type {\n RuntimeAdapterDescriptor,\n RuntimeDriverDescriptor,\n RuntimeExtensionDescriptor,\n RuntimeTargetDescriptor,\n} from './execution-descriptors';\nimport type {\n RuntimeAdapterInstance,\n RuntimeDriverInstance,\n RuntimeExtensionInstance,\n RuntimeTargetInstance,\n} from './execution-instances';\n\nexport interface ExecutionStack<\n TFamilyId extends string,\n TTargetId extends string,\n TAdapterInstance extends RuntimeAdapterInstance<TFamilyId, TTargetId> = RuntimeAdapterInstance<\n TFamilyId,\n TTargetId\n >,\n TDriverInstance extends RuntimeDriverInstance<TFamilyId, TTargetId> = RuntimeDriverInstance<\n TFamilyId,\n TTargetId\n >,\n TExtensionInstance extends RuntimeExtensionInstance<\n TFamilyId,\n TTargetId\n > = RuntimeExtensionInstance<TFamilyId, TTargetId>,\n> {\n readonly target: RuntimeTargetDescriptor<TFamilyId, TTargetId>;\n readonly adapter: RuntimeAdapterDescriptor<TFamilyId, TTargetId, TAdapterInstance>;\n readonly driver:\n | RuntimeDriverDescriptor<TFamilyId, TTargetId, unknown, TDriverInstance>\n | undefined;\n readonly extensionPacks: readonly RuntimeExtensionDescriptor<\n TFamilyId,\n TTargetId,\n TExtensionInstance\n >[];\n}\n\nexport interface ExecutionStackInstance<\n TFamilyId extends string,\n TTargetId extends string,\n TAdapterInstance extends RuntimeAdapterInstance<TFamilyId, TTargetId> = RuntimeAdapterInstance<\n TFamilyId,\n TTargetId\n >,\n TDriverInstance extends RuntimeDriverInstance<TFamilyId, TTargetId> = RuntimeDriverInstance<\n TFamilyId,\n TTargetId\n >,\n TExtensionInstance extends RuntimeExtensionInstance<\n TFamilyId,\n TTargetId\n > = RuntimeExtensionInstance<TFamilyId, TTargetId>,\n> {\n readonly stack: ExecutionStack<\n TFamilyId,\n TTargetId,\n TAdapterInstance,\n TDriverInstance,\n TExtensionInstance\n >;\n readonly target: RuntimeTargetInstance<TFamilyId, TTargetId>;\n readonly adapter: TAdapterInstance;\n readonly driver: TDriverInstance | undefined;\n readonly extensionPacks: readonly TExtensionInstance[];\n}\n\nexport function createExecutionStack<\n TFamilyId extends string,\n TTargetId extends string,\n TTargetInstance extends RuntimeTargetInstance<TFamilyId, TTargetId>,\n TTargetDescriptor extends RuntimeTargetDescriptor<TFamilyId, TTargetId, TTargetInstance>,\n TAdapterInstance extends RuntimeAdapterInstance<TFamilyId, TTargetId>,\n TAdapterDescriptor extends RuntimeAdapterDescriptor<TFamilyId, TTargetId, TAdapterInstance>,\n TDriverInstance extends RuntimeDriverInstance<TFamilyId, TTargetId> = RuntimeDriverInstance<\n TFamilyId,\n TTargetId\n >,\n TDriverDescriptor extends\n | RuntimeDriverDescriptor<TFamilyId, TTargetId, unknown, TDriverInstance>\n | undefined = undefined,\n TExtensionInstance extends RuntimeExtensionInstance<\n TFamilyId,\n TTargetId\n > = RuntimeExtensionInstance<TFamilyId, TTargetId>,\n TExtensionDescriptor extends RuntimeExtensionDescriptor<\n TFamilyId,\n TTargetId,\n TExtensionInstance\n > = never,\n>(input: {\n readonly target: TTargetDescriptor;\n readonly adapter: TAdapterDescriptor;\n readonly driver?: TDriverDescriptor | undefined;\n readonly extensionPacks?: readonly TExtensionDescriptor[] | undefined;\n}): ExecutionStack<TFamilyId, TTargetId, TAdapterInstance, TDriverInstance, TExtensionInstance> & {\n readonly target: TTargetDescriptor;\n readonly adapter: TAdapterDescriptor;\n readonly driver: TDriverDescriptor | undefined;\n readonly extensionPacks: readonly TExtensionDescriptor[];\n} {\n return {\n target: input.target,\n adapter: input.adapter,\n driver: input.driver,\n extensionPacks: input.extensionPacks ?? [],\n };\n}\n\nexport function instantiateExecutionStack<\n TFamilyId extends string,\n TTargetId extends string,\n TAdapterInstance extends RuntimeAdapterInstance<TFamilyId, TTargetId>,\n TDriverInstance extends RuntimeDriverInstance<TFamilyId, TTargetId>,\n TExtensionInstance extends RuntimeExtensionInstance<TFamilyId, TTargetId>,\n>(\n stack: ExecutionStack<\n TFamilyId,\n TTargetId,\n TAdapterInstance,\n TDriverInstance,\n TExtensionInstance\n >,\n): ExecutionStackInstance<\n TFamilyId,\n TTargetId,\n TAdapterInstance,\n TDriverInstance,\n TExtensionInstance\n> {\n const driver = stack.driver ? stack.driver.create() : undefined;\n\n return {\n stack,\n target: stack.target.create(),\n adapter: stack.adapter.create(stack),\n driver,\n extensionPacks: stack.extensionPacks.map((descriptor) => descriptor.create()),\n };\n}\n"],"mappings":";;AAQA,SAAgB,2CAGd,EACA,UACA,QACA,QACA,SACA,kBAOO;CACP,MAAM,uBAAuB,IAAI,IAAY;EAAC,OAAO;EAAI,OAAO;EAAI,QAAQ;CAAE,CAAC;CAC/E,KAAK,MAAM,aAAa,gBACtB,qBAAqB,IAAI,UAAU,EAAE;CAGvC,MAAM,SAAS,mCAAmC;EAChD;EACA,kBAAkB,OAAO;EACzB;CACF,CAAC;CAED,IAAI,OAAO,gBACT,MAAM,IAAI,MACR,oBAAoB,OAAO,eAAe,OAAO,8CAA8C,OAAO,eAAe,SAAS,GAChI;CAGF,KAAK,MAAM,UAAU,OAAO,yBAC1B,MAAM,IAAI,MACR,qCAAqC,OAAO,gEAC9C;AAEJ;;;ACwBA,SAAgB,qBAuBd,OAUA;CACA,OAAO;EACL,QAAQ,MAAM;EACd,SAAS,MAAM;EACf,QAAQ,MAAM;EACd,gBAAgB,MAAM,kBAAkB,CAAC;CAC3C;AACF;AAEA,SAAgB,0BAOd,OAaA;CACA,MAAM,SAAS,MAAM,SAAS,MAAM,OAAO,OAAO,IAAI,KAAA;CAEtD,OAAO;EACL;EACA,QAAQ,MAAM,OAAO,OAAO;EAC5B,SAAS,MAAM,QAAQ,OAAO,KAAK;EACnC;EACA,gBAAgB,MAAM,eAAe,KAAK,eAAe,WAAW,OAAO,CAAC;CAC9E;AACF"} | ||
| {"version":3,"file":"execution.mjs","names":[],"sources":["../src/execution/execution-requirements.ts","../src/execution/execution-stack.ts"],"sourcesContent":["import { checkContractComponentRequirements } from '../shared/framework-components';\nimport type {\n RuntimeAdapterDescriptor,\n RuntimeExtensionDescriptor,\n RuntimeFamilyDescriptor,\n RuntimeTargetDescriptor,\n} from './execution-descriptors';\n\nexport function assertRuntimeContractRequirementsSatisfied<\n TFamilyId extends string,\n TTargetId extends string,\n>({\n contract,\n family,\n target,\n adapter,\n extensionPacks,\n}: {\n readonly contract: { readonly target: string; readonly extensionPacks?: Record<string, unknown> };\n readonly family: RuntimeFamilyDescriptor<TFamilyId>;\n readonly target: RuntimeTargetDescriptor<TFamilyId, TTargetId>;\n readonly adapter: RuntimeAdapterDescriptor<TFamilyId, TTargetId>;\n readonly extensionPacks: readonly RuntimeExtensionDescriptor<TFamilyId, TTargetId>[];\n}): void {\n const providedComponentIds = new Set<string>([family.id, target.id, adapter.id]);\n for (const extension of extensionPacks) {\n providedComponentIds.add(extension.id);\n }\n\n const result = checkContractComponentRequirements({\n contract,\n expectedTargetId: target.targetId,\n providedComponentIds,\n });\n\n if (result.targetMismatch) {\n throw new Error(\n `Contract target '${result.targetMismatch.actual}' does not match runtime target descriptor '${result.targetMismatch.expected}'.`,\n );\n }\n\n for (const packId of result.missingExtensionPackIds) {\n throw new Error(\n `Contract requires extension pack '${packId}', but runtime descriptors do not provide a matching component.`,\n );\n }\n}\n","import type {\n RuntimeAdapterDescriptor,\n RuntimeDriverDescriptor,\n RuntimeExtensionDescriptor,\n RuntimeTargetDescriptor,\n} from './execution-descriptors';\nimport type {\n RuntimeAdapterInstance,\n RuntimeDriverInstance,\n RuntimeExtensionInstance,\n RuntimeTargetInstance,\n} from './execution-instances';\n\nexport interface ExecutionStack<\n TFamilyId extends string,\n TTargetId extends string,\n TAdapterInstance extends RuntimeAdapterInstance<TFamilyId, TTargetId> = RuntimeAdapterInstance<\n TFamilyId,\n TTargetId\n >,\n TDriverInstance extends RuntimeDriverInstance<TFamilyId, TTargetId> = RuntimeDriverInstance<\n TFamilyId,\n TTargetId\n >,\n TExtensionInstance extends RuntimeExtensionInstance<\n TFamilyId,\n TTargetId\n > = RuntimeExtensionInstance<TFamilyId, TTargetId>,\n> {\n readonly target: RuntimeTargetDescriptor<TFamilyId, TTargetId>;\n readonly adapter: RuntimeAdapterDescriptor<TFamilyId, TTargetId, TAdapterInstance>;\n readonly driver:\n | RuntimeDriverDescriptor<TFamilyId, TTargetId, unknown, TDriverInstance>\n | undefined;\n readonly extensionPacks: readonly RuntimeExtensionDescriptor<\n TFamilyId,\n TTargetId,\n TExtensionInstance\n >[];\n}\n\nexport interface ExecutionStackInstance<\n TFamilyId extends string,\n TTargetId extends string,\n TAdapterInstance extends RuntimeAdapterInstance<TFamilyId, TTargetId> = RuntimeAdapterInstance<\n TFamilyId,\n TTargetId\n >,\n TDriverInstance extends RuntimeDriverInstance<TFamilyId, TTargetId> = RuntimeDriverInstance<\n TFamilyId,\n TTargetId\n >,\n TExtensionInstance extends RuntimeExtensionInstance<\n TFamilyId,\n TTargetId\n > = RuntimeExtensionInstance<TFamilyId, TTargetId>,\n> {\n readonly stack: ExecutionStack<\n TFamilyId,\n TTargetId,\n TAdapterInstance,\n TDriverInstance,\n TExtensionInstance\n >;\n readonly target: RuntimeTargetInstance<TFamilyId, TTargetId>;\n readonly adapter: TAdapterInstance;\n readonly driver: TDriverInstance | undefined;\n readonly extensionPacks: readonly TExtensionInstance[];\n}\n\nexport function createExecutionStack<\n TFamilyId extends string,\n TTargetId extends string,\n TTargetInstance extends RuntimeTargetInstance<TFamilyId, TTargetId>,\n TTargetDescriptor extends RuntimeTargetDescriptor<TFamilyId, TTargetId, TTargetInstance>,\n TAdapterInstance extends RuntimeAdapterInstance<TFamilyId, TTargetId>,\n TAdapterDescriptor extends RuntimeAdapterDescriptor<TFamilyId, TTargetId, TAdapterInstance>,\n TDriverInstance extends RuntimeDriverInstance<TFamilyId, TTargetId> = RuntimeDriverInstance<\n TFamilyId,\n TTargetId\n >,\n TDriverDescriptor extends\n | RuntimeDriverDescriptor<TFamilyId, TTargetId, unknown, TDriverInstance>\n | undefined = undefined,\n TExtensionInstance extends RuntimeExtensionInstance<\n TFamilyId,\n TTargetId\n > = RuntimeExtensionInstance<TFamilyId, TTargetId>,\n TExtensionDescriptor extends RuntimeExtensionDescriptor<\n TFamilyId,\n TTargetId,\n TExtensionInstance\n > = never,\n>(input: {\n readonly target: TTargetDescriptor;\n readonly adapter: TAdapterDescriptor;\n readonly driver?: TDriverDescriptor | undefined;\n readonly extensionPacks?: readonly TExtensionDescriptor[] | undefined;\n}): ExecutionStack<TFamilyId, TTargetId, TAdapterInstance, TDriverInstance, TExtensionInstance> & {\n readonly target: TTargetDescriptor;\n readonly adapter: TAdapterDescriptor;\n readonly driver: TDriverDescriptor | undefined;\n readonly extensionPacks: readonly TExtensionDescriptor[];\n} {\n return {\n target: input.target,\n adapter: input.adapter,\n driver: input.driver,\n extensionPacks: input.extensionPacks ?? [],\n };\n}\n\nexport function instantiateExecutionStack<\n TFamilyId extends string,\n TTargetId extends string,\n TAdapterInstance extends RuntimeAdapterInstance<TFamilyId, TTargetId>,\n TDriverInstance extends RuntimeDriverInstance<TFamilyId, TTargetId>,\n TExtensionInstance extends RuntimeExtensionInstance<TFamilyId, TTargetId>,\n>(\n stack: ExecutionStack<\n TFamilyId,\n TTargetId,\n TAdapterInstance,\n TDriverInstance,\n TExtensionInstance\n >,\n): ExecutionStackInstance<\n TFamilyId,\n TTargetId,\n TAdapterInstance,\n TDriverInstance,\n TExtensionInstance\n> {\n const driver = stack.driver ? stack.driver.create() : undefined;\n\n return {\n stack,\n target: stack.target.create(),\n adapter: stack.adapter.create(stack),\n driver,\n extensionPacks: stack.extensionPacks.map((descriptor) => descriptor.create()),\n };\n}\n"],"mappings":";;AAQA,SAAgB,2CAGd,EACA,UACA,QACA,QACA,SACA,kBAOO;CACP,MAAM,uCAAuB,IAAI,IAAY;EAAC,OAAO;EAAI,OAAO;EAAI,QAAQ;CAAE,CAAC;CAC/E,KAAK,MAAM,aAAa,gBACtB,qBAAqB,IAAI,UAAU,EAAE;CAGvC,MAAM,SAAS,mCAAmC;EAChD;EACA,kBAAkB,OAAO;EACzB;CACF,CAAC;CAED,IAAI,OAAO,gBACT,MAAM,IAAI,MACR,oBAAoB,OAAO,eAAe,OAAO,8CAA8C,OAAO,eAAe,SAAS,GAChI;CAGF,KAAK,MAAM,UAAU,OAAO,yBAC1B,MAAM,IAAI,MACR,qCAAqC,OAAO,gEAC9C;AAEJ;;;ACwBA,SAAgB,qBAuBd,OAUA;CACA,OAAO;EACL,QAAQ,MAAM;EACd,SAAS,MAAM;EACf,QAAQ,MAAM;EACd,gBAAgB,MAAM,kBAAkB,CAAC;CAC3C;AACF;AAEA,SAAgB,0BAOd,OAaA;CACA,MAAM,SAAS,MAAM,SAAS,MAAM,OAAO,OAAO,IAAI,KAAA;CAEtD,OAAO;EACL;EACA,QAAQ,MAAM,OAAO,OAAO;EAC5B,SAAS,MAAM,QAAQ,OAAO,KAAK;EACnC;EACA,gBAAgB,MAAM,eAAe,KAAK,eAAe,WAAW,OAAO,CAAC;CAC9E;AACF"} |
+95
-1
@@ -123,2 +123,9 @@ import { ApplicationDomain, StorageBase, StorageNamespace } from "@prisma-next/contract/types"; | ||
| readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>; | ||
| /** | ||
| * Whether this namespace is the late-bound unbound slot (see | ||
| * {@link UNBOUND_NAMESPACE_ID}). Optional so JSON-shaped structural | ||
| * satisfiers remain valid; every hydrated `NamespaceBase` concretion | ||
| * answers it. | ||
| */ | ||
| readonly isUnbound?: boolean; | ||
| } | ||
@@ -129,2 +136,8 @@ declare abstract class NamespaceBase extends IRNodeBase implements Namespace { | ||
| abstract readonly kind: string; | ||
| /** | ||
| * Answers "am I the unbound namespace" as node behavior, so consumers | ||
| * never compare ids against the sentinel. This getter is the single | ||
| * encapsulated place the {@link UNBOUND_NAMESPACE_ID} comparison lives. | ||
| */ | ||
| get isUnbound(): boolean; | ||
| } | ||
@@ -168,2 +181,16 @@ //#endregion | ||
| /** | ||
| * Canonical, collision-safe key for an {@link EntityCoordinate}. Encodes each | ||
| * axis individually with `JSON.stringify` before joining with `-`, so no | ||
| * namespace id, entity kind, or entity name can forge a collision by | ||
| * embedding the delimiter itself (e.g. a delimiter of `:` would let | ||
| * `('a', 'b:c', 'd')` collide with `('a:b', 'c', 'd')`) — each component is | ||
| * quoted, and any `-` or `"` inside it is escaped or safely inside those | ||
| * quotes. | ||
| * | ||
| * The single shared key every coordinate-driven ownership/omission/collision | ||
| * check should use — `contract infer`'s pack-described-element omission and | ||
| * the migration tools' cross-space disjointness check both key on this. | ||
| */ | ||
| declare function coordinateKey(coordinate: Pick<EntityCoordinate, 'namespaceId' | 'entityKind' | 'entityName'>): string; | ||
| /** | ||
| * Looks up a single entity in a `Storage`-shaped value by its full coordinate. | ||
@@ -214,2 +241,69 @@ * Returns `undefined` if the namespace, entity kind, or entity name is absent. | ||
| //#endregion | ||
| //#region src/ir/contract-view.d.ts | ||
| /** | ||
| * Extracts the entries map of a contract's single default namespace | ||
| * (`UNBOUND_NAMESPACE_ID`). Both single-namespace families (Mongo, SQLite) | ||
| * store all entities under this one namespace. | ||
| */ | ||
| type DefaultNamespaceEntries<TStorage extends { | ||
| readonly namespaces: object; | ||
| }> = TStorage['namespaces'] extends Record<typeof UNBOUND_NAMESPACE_ID, { | ||
| readonly entries: infer E; | ||
| }> ? E : never; | ||
| /** | ||
| * Generic single-namespace projection shape — one namespace's entity-kind slots. | ||
| * A family supplies: | ||
| * - `TEntries` — the family's `*NamespaceEntries` type for the namespace. | ||
| * - `TBuiltinKinds` — the union of the family's statically-named built-in kind | ||
| * keys (Mongo `'collection'`; SQL `'table' | 'valueSet'`). | ||
| * | ||
| * Each built-in kind becomes a top-level accessor; the remaining pack-contributed | ||
| * kinds stay under `.entries` (keyed by their registered singular kind string). | ||
| * | ||
| * A built-in kind that the emitted contract does not carry resolves to an empty | ||
| * map (`Record<string, never>`), matching the runtime which always materializes | ||
| * each built-in slot. The `& string` index-signature member of `TEntries` is | ||
| * excluded from `.entries` so only the literal pack-kind keys remain. | ||
| */ | ||
| type SingleNamespaceView<TEntries, TBuiltinKinds extends string> = { readonly [K in TBuiltinKinds]-?: K extends keyof TEntries ? NonNullable<TEntries[K]> : Record<string, never> } & { | ||
| readonly entries: { readonly [K in Exclude<keyof TEntries, TBuiltinKinds | number | symbol> as string extends K ? never : K]: TEntries[K] }; | ||
| }; | ||
| /** The `entries` shape of one namespace in a storage map. */ | ||
| type EntriesOf<TNamespace> = TNamespace extends { | ||
| readonly entries: infer E; | ||
| } ? E : never; | ||
| /** | ||
| * The namespace-keyed entity-view map — every storage namespace keyed by its raw | ||
| * id, each projected to its {@link SingleNamespaceView}. Mirrors | ||
| * `NamespacedEnums` from `@prisma-next/contract/enum-accessor`: the migration | ||
| * author's storage-side `view.namespace.<nsId>` is the twin of the runtime's | ||
| * `db.enums.<nsId>`. Nesting the schema map under one fixed `namespace` member | ||
| * makes it collision-proof — a schema named `storage` is `view.namespace.storage`, | ||
| * never a contract-root key. | ||
| */ | ||
| type NamespacedEntities<TStorage extends { | ||
| readonly namespaces: object; | ||
| }, TBuiltinKinds extends string> = { readonly [Ns in keyof TStorage['namespaces']]: SingleNamespaceView<EntriesOf<TStorage['namespaces'][Ns]>, TBuiltinKinds> }; | ||
| /** | ||
| * Projects one namespace's `entries` into the view shape: each built-in kind | ||
| * becomes a top-level slot (materialized empty if absent), and the remaining | ||
| * pack-contributed kinds sit under `.entries`. Shared by the single-namespace | ||
| * builder and the namespace-map builder. | ||
| */ | ||
| declare function promoteBuiltinKinds<TView>(entries: Readonly<Record<string, unknown>>, builtinKinds: readonly string[]): TView; | ||
| /** | ||
| * Builds one namespace's entity view: promotes the given built-in kind slots to | ||
| * top-level for the default (`UNBOUND_NAMESPACE_ID`) namespace. Single-namespace | ||
| * targets (Mongo, SQLite) use this to unwrap their sole namespace to the root. | ||
| * | ||
| * Throws if the contract has no default (`UNBOUND_NAMESPACE_ID`) namespace. | ||
| */ | ||
| declare function buildSingleNamespaceView<TView>(storage: Storage, builtinKinds: readonly string[]): TView; | ||
| /** | ||
| * Builds the namespace-keyed entity-view map (`{ <nsId>: SingleNamespaceView }`) | ||
| * for every namespace in the storage, keyed by raw namespace id. Mirrors | ||
| * `buildNamespacedEnums(domain)` — the storage-side twin. | ||
| */ | ||
| declare function buildNamespacedEntities<TMap>(storage: Storage, builtinKinds: readonly string[]): TMap; | ||
| //#endregion | ||
| //#region src/ir/domain.d.ts | ||
@@ -269,3 +363,3 @@ /** | ||
| //#endregion | ||
| export { type AnyEntityKindDescriptor, type EntityCoordinate, type EntityKindDescriptor, type IRNode, IRNodeBase, type Namespace, NamespaceBase, type Storage, type StorageType, UNBOUND_NAMESPACE_ID, domainElementCoordinates, elementCoordinates, entityAt, freezeNode, hydrateNamespaceEntities, isPlainRecord }; | ||
| export { type AnyEntityKindDescriptor, type DefaultNamespaceEntries, type EntityCoordinate, type EntityKindDescriptor, type IRNode, IRNodeBase, type Namespace, NamespaceBase, type NamespacedEntities, type SingleNamespaceView, type Storage, type StorageType, UNBOUND_NAMESPACE_ID, buildNamespacedEntities, buildSingleNamespaceView, coordinateKey, domainElementCoordinates, elementCoordinates, entityAt, freezeNode, hydrateNamespaceEntities, isPlainRecord, promoteBuiltinKinds }; | ||
| //# sourceMappingURL=ir.d.mts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"ir.d.mts","names":[],"sources":["../src/ir/ir-node.ts","../src/ir/namespace.ts","../src/ir/storage.ts","../src/ir/domain.ts","../src/ir/entity-kind.ts","../src/ir/storage-type.ts"],"mappings":";;;;;;;;;;AAyCA;;;;AACe;AAGf;;;;AACwB;AAYxB;;;;;;;;;;;;;;AAAwD;;;;AChCxD;;;;AAA0D;AAkC1D;;UDnBiB,MAAA;EAAA,SACN,IAAI;AAAA;AAAA,uBAGO,UAAA,YAAsB,MAAM;EAAA,kBAC9B,IAAI;AAAA;;;;;;;;;;iBAYR,UAAA,WAAqB,MAAA,EAAQ,IAAA,EAAM,CAAA,GAAI,CAAA;;;;;;AAjBvD;;;;AACe;AAGf;;;;AACwB;AAYxB;;;;;;;;;;cChCa,oBAAA;;;;ADgC2C;;;;AChCxD;;;;AAA0D;AAkC1D;;;;;;;;;;;;;;;;;;;;UAAiB,SAAA,SAAkB,MAAA,EAAQ,gBAAA;EAAA,SAChC,IAAA;EAAA,SACA,OAAA,EAAS,QAAA,CAAS,MAAA,SAAe,QAAA,CAAS,MAAA;AAAA;AAAA,uBAG/B,aAAA,SAAsB,UAAA,YAAsB,SAAA;EAAA,kBAC9C,EAAA;EAAA,kBACA,OAAA,EAAS,QAAA,CAAS,MAAA,SAAe,QAAA,CAAS,MAAA;EAAA,kBACjC,IAAA;AAAA;;;AD3B7B;;;;AACe;AAGf;;;;AACwB;AAYxB;;;;;;AAjBA,UEjBiB,gBAAA;EAAA,SACN,KAAA;EAAA,SACA,WAAA;EAAA,SACA,UAAA;EAAA,SACA,UAAA;AAAA;;;AF8B6C;;;;AChCxD;;;;AAA0D;iBCgBzC,kBAAA,CACf,OAAA,EAAS,IAAA,CAAK,WAAA,kBACb,SAAA,CAAU,gBAAA;;;;;;;iBAmBG,QAAA,cACd,OAAA,EAAS,IAAA,CAAK,WAAA,iBACd,KAAA,EAAO,IAAA,CAAK,gBAAA,iDACX,CAAA;;;;;;;;;;;;;ADJwD;AAG3D;;;;;;;;;;;;;;;;;;;;;AAGiC;UC8ChB,OAAA,SAAgB,MAAA;EAAA,SACtB,UAAA,EAAY,QAAA,CAAS,MAAA,SAAe,SAAA;AAAA;;;;;;AF1E/C;;;;iBG/BiB,wBAAA,CACf,MAAA,EAAQ,IAAA,CAAK,iBAAA,kBACZ,SAAA,CAAU,gBAAA;;;UCTI,oBAAA;EAAA,SACN,IAAA;EAAA,SAEA,MAAA,EAAQ,IAAA;EAAA,SACR,SAAA,GAAY,KAAA,EAAO,KAAA,KAAU,IAAA;AAAA;AAAA,KAG5B,uBAAA,GAA0B,oBAAoB;;;AJgC3C;AAGf;;;;AACwB;AAYxB;;;;iBIlCgB,wBAAA,CACd,OAAA,EAAS,QAAA,CAAS,MAAA,SAAe,QAAA,CAAS,MAAA,sBAC1C,KAAA,EAAO,WAAA,SAAoB,uBAAA,GAC3B,SAAA,oBACA,IAAA,YACC,MAAA,SAAe,QAAA,CAAS,MAAA;;;;;;;AJY3B;;;;AACe;AAGf;;;;AACwB;AAYxB;;;;UKtCiB,WAAA,SAAoB,MAAM;EAAA,SAChC,IAAI;AAAA"} | ||
| {"version":3,"file":"ir.d.mts","names":[],"sources":["../src/ir/ir-node.ts","../src/ir/namespace.ts","../src/ir/storage.ts","../src/ir/contract-view.ts","../src/ir/domain.ts","../src/ir/entity-kind.ts","../src/ir/storage-type.ts"],"mappings":"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"} |
+112
-44
| import { blindCast } from "@prisma-next/utils/casts"; | ||
| import { isPlainRecord } from "@prisma-next/contract/is-plain-record"; | ||
| //#region src/ir/ir-node.ts | ||
| var IRNodeBase = class {}; | ||
| /** | ||
| * Seal an IR class instance after its constructor has assigned all | ||
| * fields. The free-helper form (rather than a `protected freeze()` | ||
| * instance method) keeps the class type structurally narrow so emitted | ||
| * contract literal types remain assignable to their class types. | ||
| * | ||
| * The helper name stays `freezeNode` — it operates on IR nodes | ||
| * regardless of root naming. | ||
| */ | ||
| function freezeNode(node) { | ||
| Object.freeze(node); | ||
| return node; | ||
| } | ||
| //#endregion | ||
| //#region src/ir/namespace.ts | ||
| /** | ||
| * Reserved sentinel namespace id for the late-bound storage slot — | ||
| * the slot whose binding the target resolves at connection time | ||
| * rather than at authoring time. Postgres uses it for `search_path` | ||
| * late binding; SQLite uses it for the trivial singleton; Mongo uses | ||
| * it for the connection's `db` binding. | ||
| * | ||
| * Materialised target-side as a singleton subclass of the target's | ||
| * `NamespaceBase` concretion that overrides the namespace's | ||
| * qualifier-emission methods to elide the prefix entirely. Call sites | ||
| * stay polymorphic and never branch on `id === UNBOUND_NAMESPACE_ID` | ||
| * — the singleton's overrides drop the qualifier so emitted SQL / Mongo | ||
| * commands look unqualified. | ||
| * | ||
| * The double-underscore decoration marks the id as a framework-reserved | ||
| * coordinate when it appears in a JSON envelope (cold-read-as-reserved | ||
| * — no realistic collision with user-declared namespace names). | ||
| * | ||
| * Encoded as an exported const (rather than scattered string literals) | ||
| * so the sentinel-id invariant is single-sourced: any production-source | ||
| * site that constructs an unbound-namespace singleton imports this | ||
| * constant. | ||
| */ | ||
| const UNBOUND_NAMESPACE_ID = "__unbound__"; | ||
| var NamespaceBase = class extends IRNodeBase { | ||
| /** | ||
| * Answers "am I the unbound namespace" as node behavior, so consumers | ||
| * never compare ids against the sentinel. This getter is the single | ||
| * encapsulated place the {@link UNBOUND_NAMESPACE_ID} comparison lives. | ||
| */ | ||
| get isUnbound() { | ||
| return this.id === UNBOUND_NAMESPACE_ID; | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region src/ir/contract-view.ts | ||
| /** | ||
| * Projects one namespace's `entries` into the view shape: each built-in kind | ||
| * becomes a top-level slot (materialized empty if absent), and the remaining | ||
| * pack-contributed kinds sit under `.entries`. Shared by the single-namespace | ||
| * builder and the namespace-map builder. | ||
| */ | ||
| function promoteBuiltinKinds(entries, builtinKinds) { | ||
| const view = {}; | ||
| const rest = {}; | ||
| for (const [kind, kindMap] of Object.entries(entries)) if (builtinKinds.includes(kind)) view[kind] = kindMap; | ||
| else rest[kind] = kindMap; | ||
| for (const kind of builtinKinds) if (!(kind in view)) view[kind] = {}; | ||
| view["entries"] = rest; | ||
| return blindCast(view); | ||
| } | ||
| /** | ||
| * Builds one namespace's entity view: promotes the given built-in kind slots to | ||
| * top-level for the default (`UNBOUND_NAMESPACE_ID`) namespace. Single-namespace | ||
| * targets (Mongo, SQLite) use this to unwrap their sole namespace to the root. | ||
| * | ||
| * Throws if the contract has no default (`UNBOUND_NAMESPACE_ID`) namespace. | ||
| */ | ||
| function buildSingleNamespaceView(storage, builtinKinds) { | ||
| const defaultNs = storage.namespaces[UNBOUND_NAMESPACE_ID]; | ||
| if (defaultNs === void 0) throw new Error(`ContractView: contract has no default namespace (${UNBOUND_NAMESPACE_ID})`); | ||
| return promoteBuiltinKinds(blindCast(defaultNs.entries), builtinKinds); | ||
| } | ||
| /** | ||
| * Builds the namespace-keyed entity-view map (`{ <nsId>: SingleNamespaceView }`) | ||
| * for every namespace in the storage, keyed by raw namespace id. Mirrors | ||
| * `buildNamespacedEnums(domain)` — the storage-side twin. | ||
| */ | ||
| function buildNamespacedEntities(storage, builtinKinds) { | ||
| const out = {}; | ||
| for (const [nsId, ns] of Object.entries(storage.namespaces)) out[nsId] = promoteBuiltinKinds(blindCast(ns.entries), builtinKinds); | ||
| return blindCast(out); | ||
| } | ||
| //#endregion | ||
| //#region src/ir/domain.ts | ||
@@ -51,45 +142,2 @@ /** | ||
| //#endregion | ||
| //#region src/ir/ir-node.ts | ||
| var IRNodeBase = class {}; | ||
| /** | ||
| * Seal an IR class instance after its constructor has assigned all | ||
| * fields. The free-helper form (rather than a `protected freeze()` | ||
| * instance method) keeps the class type structurally narrow so emitted | ||
| * contract literal types remain assignable to their class types. | ||
| * | ||
| * The helper name stays `freezeNode` — it operates on IR nodes | ||
| * regardless of root naming. | ||
| */ | ||
| function freezeNode(node) { | ||
| Object.freeze(node); | ||
| return node; | ||
| } | ||
| //#endregion | ||
| //#region src/ir/namespace.ts | ||
| /** | ||
| * Reserved sentinel namespace id for the late-bound storage slot — | ||
| * the slot whose binding the target resolves at connection time | ||
| * rather than at authoring time. Postgres uses it for `search_path` | ||
| * late binding; SQLite uses it for the trivial singleton; Mongo uses | ||
| * it for the connection's `db` binding. | ||
| * | ||
| * Materialised target-side as a singleton subclass of the target's | ||
| * `NamespaceBase` concretion that overrides the namespace's | ||
| * qualifier-emission methods to elide the prefix entirely. Call sites | ||
| * stay polymorphic and never branch on `id === UNBOUND_NAMESPACE_ID` | ||
| * — the singleton's overrides drop the qualifier so emitted SQL / Mongo | ||
| * commands look unqualified. | ||
| * | ||
| * The double-underscore decoration marks the id as a framework-reserved | ||
| * coordinate when it appears in a JSON envelope (cold-read-as-reserved | ||
| * — no realistic collision with user-declared namespace names). | ||
| * | ||
| * Encoded as an exported const (rather than scattered string literals) | ||
| * so the sentinel-id invariant is single-sourced: any production-source | ||
| * site that constructs an unbound-namespace singleton imports this | ||
| * constant. | ||
| */ | ||
| const UNBOUND_NAMESPACE_ID = "__unbound__"; | ||
| var NamespaceBase = class extends IRNodeBase {}; | ||
| //#endregion | ||
| //#region src/ir/storage.ts | ||
@@ -123,2 +171,22 @@ /** | ||
| /** | ||
| * Canonical, collision-safe key for an {@link EntityCoordinate}. Encodes each | ||
| * axis individually with `JSON.stringify` before joining with `-`, so no | ||
| * namespace id, entity kind, or entity name can forge a collision by | ||
| * embedding the delimiter itself (e.g. a delimiter of `:` would let | ||
| * `('a', 'b:c', 'd')` collide with `('a:b', 'c', 'd')`) — each component is | ||
| * quoted, and any `-` or `"` inside it is escaped or safely inside those | ||
| * quotes. | ||
| * | ||
| * The single shared key every coordinate-driven ownership/omission/collision | ||
| * check should use — `contract infer`'s pack-described-element omission and | ||
| * the migration tools' cross-space disjointness check both key on this. | ||
| */ | ||
| function coordinateKey(coordinate) { | ||
| return [ | ||
| coordinate.namespaceId, | ||
| coordinate.entityKind, | ||
| coordinate.entityName | ||
| ].map((value) => JSON.stringify(value)).join("-"); | ||
| } | ||
| /** | ||
| * Looks up a single entity in a `Storage`-shaped value by its full coordinate. | ||
@@ -140,4 +208,4 @@ * Returns `undefined` if the namespace, entity kind, or entity name is absent. | ||
| //#endregion | ||
| export { IRNodeBase, NamespaceBase, UNBOUND_NAMESPACE_ID, domainElementCoordinates, elementCoordinates, entityAt, freezeNode, hydrateNamespaceEntities, isPlainRecord }; | ||
| export { IRNodeBase, NamespaceBase, UNBOUND_NAMESPACE_ID, buildNamespacedEntities, buildSingleNamespaceView, coordinateKey, domainElementCoordinates, elementCoordinates, entityAt, freezeNode, hydrateNamespaceEntities, isPlainRecord, promoteBuiltinKinds }; | ||
| //# sourceMappingURL=ir.mjs.map |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"ir.mjs","names":[],"sources":["../src/ir/domain.ts","../src/ir/entity-kind.ts","../src/ir/ir-node.ts","../src/ir/namespace.ts","../src/ir/storage.ts"],"sourcesContent":["import type { ApplicationDomain } from '@prisma-next/contract/types';\nimport type { EntityCoordinate } from './storage';\n\n/**\n * Lazy walk over every named domain entity in a {@link ApplicationDomain},\n * yielded as {@link EntityCoordinate} tuples with `plane: 'domain'`.\n *\n * Same structural rules as {@link elementCoordinates} over storage: skip\n * scalar `id`; each other object-valued property is an entity-kind slot.\n */\nexport function* domainElementCoordinates(\n domain: Pick<ApplicationDomain, 'namespaces'>,\n): Generator<EntityCoordinate> {\n for (const [namespaceId, ns] of Object.entries(domain.namespaces)) {\n for (const [entityKind, slot] of Object.entries(ns)) {\n if (entityKind === 'id') continue;\n if (slot === null || typeof slot !== 'object') continue;\n for (const entityName of Object.keys(slot)) {\n yield { plane: 'domain', namespaceId, entityKind, entityName };\n }\n }\n }\n}\n","import { blindCast } from '@prisma-next/utils/casts';\nimport type { Type } from 'arktype';\n\nexport interface EntityKindDescriptor<Input, Node> {\n readonly kind: string;\n // Type<unknown>, not Type<Input>: AnyEntityKindDescriptor widens Input to never, which would force an unusable Type<never>; concrete descriptors still carry their real schema.\n readonly schema: Type<unknown>;\n readonly construct: (input: Input) => Node;\n}\n\nexport type AnyEntityKindDescriptor = EntityKindDescriptor<never, unknown>;\n\n/**\n * Hydrates a namespace's entities from raw JSON maps into IR class instances.\n *\n * For each kind in `entries`: if the descriptor map has a descriptor,\n * construct each inner-map value; otherwise freeze-and-carry (`'carry'`)\n * or throw naming the kind and nsId (`'fail'`).\n *\n * The single boundary cast hands `value` to `descriptor.construct` as its\n * `Input`. The value satisfies the kind's `Input` either by the\n * entries-input contract at authoring time or by prior `validateStorage`\n * validation at hydration time.\n */\nexport function hydrateNamespaceEntities(\n entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>,\n kinds: ReadonlyMap<string, AnyEntityKindDescriptor>,\n onUnknown: 'carry' | 'fail',\n nsId?: string,\n): Record<string, Readonly<Record<string, unknown>>> {\n const result: Record<string, Readonly<Record<string, unknown>>> = {};\n for (const [kind, rawMap] of Object.entries(entries)) {\n const descriptor = kinds.get(kind);\n if (descriptor !== undefined) {\n const built: Record<string, unknown> = {};\n for (const [name, value] of Object.entries(rawMap)) {\n built[name] = descriptor.construct(\n blindCast<\n never,\n \"value is this kind's descriptor Input: when authoring, the typed entries-input contract produces it; when hydrating, it was validated against descriptor.schema before this loop. The never target is AnyEntityKindDescriptor's erased Input parameter.\"\n >(value),\n );\n }\n result[kind] = Object.freeze(built);\n } else if (onUnknown === 'carry') {\n result[kind] = Object.freeze(rawMap);\n } else {\n throw new Error(\n `Unknown entries key \"${kind}\" in namespace \"${nsId ?? '?'}\"; no hydration factory registered for this entity kind`,\n );\n }\n }\n return result;\n}\n","/**\n * Framework-level IR alphabet.\n *\n * The framework's contribution to Contract IR / Schema IR is a common\n * root for the IR class hierarchy and a freeze affordance. Family\n * abstract bases (e.g. `SqlNode`, `MongoSchemaIRNode`) refine the alphabet\n * for their family shape; targets ship the concrete classes.\n *\n * `kind` is an optional discriminator on the base. Families and leaves\n * that benefit from discriminated-union dispatch declare their own\n * literal `kind` at the level that earns it — Mongo leaves carry\n * per-class literals (`readonly kind = 'mongo-collection' as const`)\n * because Mongo IR has polymorphic walkers; SQL declares a single\n * family-level `kind = 'sql'` on `SqlNode` because SQL IR has no\n * polymorphic dispatch today. No framework consumer dispatches on\n * `IRNode.kind` at the BASE type — every dispatch site narrows\n * through a union of leaves where each leaf carries a literal kind, so\n * requiring `kind` at the base would be unearned. Future leaves that\n * earn polymorphic dispatch override with a required literal at that\n * leaf (e.g. `override readonly kind = 'pack-contributed-kind' as const`).\n *\n * `IRNodeBase` carries no methods: the freeze-and-assign affordance\n * lives in the free `freezeNode` helper below. Keeping `freezeNode` out\n * of the class type means an emitted contract literal type\n * (`{ readonly kind: 'mongo-collection', ... }` or an unkeyed literal\n * like `{ nativeType, codecId, nullable }`) is structurally assignable\n * to its class type — a `protected freeze()` instance method would\n * otherwise leak into the public type surface and require the literal\n * to carry it too.\n *\n * Subclasses construct fields then call `freezeNode(this)` to seal the\n * instance. Frozen instances + plain readonly fields keep IR nodes\n * JSON-clean by construction, so `JSON.stringify(node)` produces canonical\n * JSON without a `toJSON()` method. The `ContractSerializer` SPI handles\n * round-trip from canonical JSON back to typed class instances.\n *\n * The name (`IRNode` / `IRNodeBase`) reflects the dual-hierarchy reality:\n * this base is the common root for both Contract IR and Schema IR class\n * hierarchies, not a Schema-IR-specific alphabet.\n */\n\nexport interface IRNode {\n readonly kind?: string;\n}\n\nexport abstract class IRNodeBase implements IRNode {\n abstract readonly kind?: string;\n}\n\n/**\n * Seal an IR class instance after its constructor has assigned all\n * fields. The free-helper form (rather than a `protected freeze()`\n * instance method) keeps the class type structurally narrow so emitted\n * contract literal types remain assignable to their class types.\n *\n * The helper name stays `freezeNode` — it operates on IR nodes\n * regardless of root naming.\n */\nexport function freezeNode<T extends IRNode>(node: T): T {\n Object.freeze(node);\n return node;\n}\n","import type { StorageNamespace } from '@prisma-next/contract/types';\nimport { type IRNode, IRNodeBase } from './ir-node';\n\n/**\n * Reserved sentinel namespace id for the late-bound storage slot —\n * the slot whose binding the target resolves at connection time\n * rather than at authoring time. Postgres uses it for `search_path`\n * late binding; SQLite uses it for the trivial singleton; Mongo uses\n * it for the connection's `db` binding.\n *\n * Materialised target-side as a singleton subclass of the target's\n * `NamespaceBase` concretion that overrides the namespace's\n * qualifier-emission methods to elide the prefix entirely. Call sites\n * stay polymorphic and never branch on `id === UNBOUND_NAMESPACE_ID`\n * — the singleton's overrides drop the qualifier so emitted SQL / Mongo\n * commands look unqualified.\n *\n * The double-underscore decoration marks the id as a framework-reserved\n * coordinate when it appears in a JSON envelope (cold-read-as-reserved\n * — no realistic collision with user-declared namespace names).\n *\n * Encoded as an exported const (rather than scattered string literals)\n * so the sentinel-id invariant is single-sourced: any production-source\n * site that constructs an unbound-namespace singleton imports this\n * constant.\n */\nexport const UNBOUND_NAMESPACE_ID = '__unbound__' as const;\n\n/**\n * Framework-level building block for a \"namespace\" — the database-level\n * grouping under which storage objects (tables, collections, enums, …)\n * reside. Each target's namespace concretion maps the framework concept to\n * a target-native binding:\n *\n * - Postgres: a schema (`CREATE SCHEMA …`); rendered as `\"<schema>\"`.\n * - SQLite: the singleton `UNBOUND_NAMESPACE_ID`; emitted SQL has no qualifier.\n * - Mongo: the connection's `db` field; addressed as a database name.\n *\n * See `UNBOUND_NAMESPACE_ID` above for the sentinel id and the\n * singleton-subclass pattern that materialises it.\n *\n * The framework promises only the coordinate (`id`) — the named storage\n * entities a namespace contains are family-typed (SQL contributes\n * `table` / `type`, Mongo contributes `collection`, future families pick\n * their own native idiom under `entries`). Generic consumers walking \"all\n * named entries\" go through a family-typed namespace, not the framework\n * `Namespace`.\n *\n * Every namespace concretion (e.g. family-built SQL namespaces,\n * `MongoUnboundNamespace`, target-promoted namespaces like\n * `PostgresSchema`) carries exactly: `id` (enumerable string),\n * `entries` (frozen object holding entity-kind slot maps), and `kind`\n * (non-enumerable string discriminator set via `Object.defineProperty`).\n * Each slot map under `entries` uses a singular essence key (`table`,\n * `type`, `collection`, …) mapping entity names to IR classes. No other\n * own-enumerable data lives on a namespace; non-entity computed data lives\n * on the surrounding storage or contract IR. The framework's\n * `elementCoordinates(storage)` walk relies on this invariant to enumerate\n * entities structurally without family-specific knowledge.\n */\nexport interface Namespace extends IRNode, StorageNamespace {\n readonly kind: string;\n readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>;\n}\n\nexport abstract class NamespaceBase extends IRNodeBase implements Namespace {\n abstract readonly id: string;\n abstract readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>;\n abstract override readonly kind: string;\n}\n","import { isPlainRecord } from '@prisma-next/contract/is-plain-record';\nimport type { StorageBase } from '@prisma-next/contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { IRNode } from './ir-node';\nimport type { Namespace } from './namespace';\n\nexport { isPlainRecord };\n\n/**\n * Canonical address for a named entity in Contract IR / Schema IR.\n *\n * `plane` is `'domain' | 'storage'`: which top-level contract plane the\n * entity lives on. Domain-side walks yield `plane: 'domain'` via\n * {@link domainElementCoordinates}; {@link elementCoordinates} over storage\n * yields `plane: 'storage'`.\n *\n * Cross-plane references obey a directional invariant: domain → storage is\n * allowed; storage → domain is forbidden. That rule is enforced by a\n * separate validator, not by constraining this coordinate shape — the\n * coordinate carries the axis the validator checks.\n *\n * Iteration order over namespace properties follows `Object.entries` order;\n * consumers that depend on ordering must sort.\n */\nexport interface EntityCoordinate {\n readonly plane: 'domain' | 'storage';\n readonly namespaceId: string;\n readonly entityKind: string;\n readonly entityName: string;\n}\n\n/**\n * Lazy walk over every named storage entity in a `Storage`-shaped\n * value, yielded as {@link EntityCoordinate} tuples with\n * `plane: 'storage'` (the parameter type binds the plane).\n *\n * Iterates each namespace's `entries` kind maps structurally. Skips\n * non-object `entries`; `id` and `kind` are not walked (`kind` is\n * non-enumerable on concretions). For every entity-kind key under\n * `entries` whose value is a non-null object, yields one coordinate per\n * entity name in that map. No family-specific kind vocabulary is required.\n */\nexport function* elementCoordinates(\n storage: Pick<StorageBase, 'namespaces'>,\n): Generator<EntityCoordinate> {\n for (const [namespaceId, ns] of Object.entries(storage.namespaces)) {\n const entries = ns.entries;\n if (entries === null || typeof entries !== 'object') continue;\n for (const [entityKind, kindMap] of Object.entries(entries)) {\n if (kindMap === null || typeof kindMap !== 'object') continue;\n for (const entityName of Object.keys(kindMap)) {\n yield { plane: 'storage', namespaceId, entityKind, entityName };\n }\n }\n }\n}\n\n/**\n * Looks up a single entity in a `Storage`-shaped value by its full coordinate.\n * Returns `undefined` if the namespace, entity kind, or entity name is absent.\n * The type parameter is a caller assertion — the walk itself is structural\n * and cannot verify the entity's shape.\n */\nexport function entityAt<T = unknown>(\n storage: Pick<StorageBase, 'namespaces'>,\n coord: Pick<EntityCoordinate, 'namespaceId' | 'entityKind' | 'entityName'>,\n): T | undefined {\n const ns = storage.namespaces[coord.namespaceId];\n if (ns === undefined) return undefined;\n const entries = ns.entries;\n if (!isPlainRecord(entries)) return undefined;\n const kindMap = entries[coord.entityKind];\n if (!isPlainRecord(kindMap)) return undefined;\n if (!Object.hasOwn(kindMap, coord.entityName)) return undefined;\n return blindCast<T | undefined, 'caller asserts the entity type at this coordinate'>(\n kindMap[coord.entityName],\n );\n}\n\n/**\n * Framework-level promise that every Contract IR / Schema IR carries a\n * collection of namespaces keyed by namespace id. Family storage\n * concretions (`SqlStorage`, `MongoStorage`) refine the shape with\n * family-specific fields (tables, collections, enums, …); target\n * concretions add target fields where the family vocabulary doesn't\n * reach.\n *\n * Keeping `namespaces` at the framework layer enforces that every storage\n * object — across any target — is namespace-scoped. The framework can\n * therefore walk the namespace map without knowing the family alphabet, and\n * the `(namespace.id, name)` keying that the verifier and planner depend on\n * is honest at every layer.\n *\n * Extends `IRNode` so the framework's IR-walking surfaces (verifiers,\n * serializers) can dispatch on `Storage`-typed fields through the same\n * IR-node alphabet as every other node — the structural dual already\n * holds in code (every concrete storage class extends an IR-node base);\n * the interface promotion makes the typing honest.\n *\n * **Persisted envelope shape is target-owned, not framework-promised.**\n * Whether the `namespaces` map appears in the on-disk JSON envelope is\n * a per-target decision made by `ContractSerializer.serializeContract`.\n * Some targets emit a JSON-clean namespace shape that round-trips\n * through `JSON.stringify` cleanly (SQL today via the family-layer\n * identity serializer); others ship runtime-only fields on their\n * namespace concretions and override `serializeContract` to strip\n * them (Mongo). Future open (F16): extend the per-target\n * `ContractSerializer` integration-test surface with an explicit\n * envelope-shape assertion for each target, so the strip-vs-pass-through\n * choice is locked at test time rather than implied by the override\n * presence/absence. Earned by PR2's per-target namespace lift, when\n * `PostgresSchema` / `SqliteUnboundDatabase` start carrying\n * target-specific fields.\n */\nexport interface Storage extends IRNode {\n readonly namespaces: Readonly<Record<string, Namespace>>;\n}\n"],"mappings":";;;;;;;;;;AAUA,UAAiB,yBACf,QAC6B;CAC7B,KAAK,MAAM,CAAC,aAAa,OAAO,OAAO,QAAQ,OAAO,UAAU,GAC9D,KAAK,MAAM,CAAC,YAAY,SAAS,OAAO,QAAQ,EAAE,GAAG;EACnD,IAAI,eAAe,MAAM;EACzB,IAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;EAC/C,KAAK,MAAM,cAAc,OAAO,KAAK,IAAI,GACvC,MAAM;GAAE,OAAO;GAAU;GAAa;GAAY;EAAW;CAEjE;AAEJ;;;;;;;;;;;;;;;ACEA,SAAgB,yBACd,SACA,OACA,WACA,MACmD;CACnD,MAAM,SAA4D,CAAC;CACnE,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,OAAO,GAAG;EACpD,MAAM,aAAa,MAAM,IAAI,IAAI;EACjC,IAAI,eAAe,KAAA,GAAW;GAC5B,MAAM,QAAiC,CAAC;GACxC,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,GAC/C,MAAM,QAAQ,WAAW,UACvB,UAGE,KAAK,CACT;GAEF,OAAO,QAAQ,OAAO,OAAO,KAAK;EACpC,OAAO,IAAI,cAAc,SACvB,OAAO,QAAQ,OAAO,OAAO,MAAM;OAEnC,MAAM,IAAI,MACR,wBAAwB,KAAK,kBAAkB,QAAQ,IAAI,wDAC7D;CAEJ;CACA,OAAO;AACT;;;ACRA,IAAsB,aAAtB,MAAmD,CAEnD;;;;;;;;;;AAWA,SAAgB,WAA6B,MAAY;CACvD,OAAO,OAAO,IAAI;CAClB,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA,MAAa,uBAAuB;AAuCpC,IAAsB,gBAAtB,cAA4C,WAAgC,CAI5E;;;;;;;;;;;;;;AC3BA,UAAiB,mBACf,SAC6B;CAC7B,KAAK,MAAM,CAAC,aAAa,OAAO,OAAO,QAAQ,QAAQ,UAAU,GAAG;EAClE,MAAM,UAAU,GAAG;EACnB,IAAI,YAAY,QAAQ,OAAO,YAAY,UAAU;EACrD,KAAK,MAAM,CAAC,YAAY,YAAY,OAAO,QAAQ,OAAO,GAAG;GAC3D,IAAI,YAAY,QAAQ,OAAO,YAAY,UAAU;GACrD,KAAK,MAAM,cAAc,OAAO,KAAK,OAAO,GAC1C,MAAM;IAAE,OAAO;IAAW;IAAa;IAAY;GAAW;EAElE;CACF;AACF;;;;;;;AAQA,SAAgB,SACd,SACA,OACe;CACf,MAAM,KAAK,QAAQ,WAAW,MAAM;CACpC,IAAI,OAAO,KAAA,GAAW,OAAO,KAAA;CAC7B,MAAM,UAAU,GAAG;CACnB,IAAI,CAAC,cAAc,OAAO,GAAG,OAAO,KAAA;CACpC,MAAM,UAAU,QAAQ,MAAM;CAC9B,IAAI,CAAC,cAAc,OAAO,GAAG,OAAO,KAAA;CACpC,IAAI,CAAC,OAAO,OAAO,SAAS,MAAM,UAAU,GAAG,OAAO,KAAA;CACtD,OAAO,UACL,QAAQ,MAAM,WAChB;AACF"} | ||
| {"version":3,"file":"ir.mjs","names":[],"sources":["../src/ir/ir-node.ts","../src/ir/namespace.ts","../src/ir/contract-view.ts","../src/ir/domain.ts","../src/ir/entity-kind.ts","../src/ir/storage.ts"],"sourcesContent":["/**\n * Framework-level IR alphabet.\n *\n * The framework's contribution to Contract IR / Schema IR is a common\n * root for the IR class hierarchy and a freeze affordance. Family\n * abstract bases (e.g. `SqlNode`, `MongoSchemaIRNode`) refine the alphabet\n * for their family shape; targets ship the concrete classes.\n *\n * `kind` is an optional discriminator on the base. Families and leaves\n * that benefit from discriminated-union dispatch declare their own\n * literal `kind` at the level that earns it — Mongo leaves carry\n * per-class literals (`readonly kind = 'mongo-collection' as const`)\n * because Mongo IR has polymorphic walkers; SQL declares a single\n * family-level `kind = 'sql'` on `SqlNode` because SQL IR has no\n * polymorphic dispatch today. No framework consumer dispatches on\n * `IRNode.kind` at the BASE type — every dispatch site narrows\n * through a union of leaves where each leaf carries a literal kind, so\n * requiring `kind` at the base would be unearned. Future leaves that\n * earn polymorphic dispatch override with a required literal at that\n * leaf (e.g. `override readonly kind = 'pack-contributed-kind' as const`).\n *\n * `IRNodeBase` carries no methods: the freeze-and-assign affordance\n * lives in the free `freezeNode` helper below. Keeping `freezeNode` out\n * of the class type means an emitted contract literal type\n * (`{ readonly kind: 'mongo-collection', ... }` or an unkeyed literal\n * like `{ nativeType, codecId, nullable }`) is structurally assignable\n * to its class type — a `protected freeze()` instance method would\n * otherwise leak into the public type surface and require the literal\n * to carry it too.\n *\n * Subclasses construct fields then call `freezeNode(this)` to seal the\n * instance. Frozen instances + plain readonly fields keep IR nodes\n * JSON-clean by construction, so `JSON.stringify(node)` produces canonical\n * JSON without a `toJSON()` method. The `ContractSerializer` SPI handles\n * round-trip from canonical JSON back to typed class instances.\n *\n * The name (`IRNode` / `IRNodeBase`) reflects the dual-hierarchy reality:\n * this base is the common root for both Contract IR and Schema IR class\n * hierarchies, not a Schema-IR-specific alphabet.\n */\n\nexport interface IRNode {\n readonly kind?: string;\n}\n\nexport abstract class IRNodeBase implements IRNode {\n abstract readonly kind?: string;\n}\n\n/**\n * Seal an IR class instance after its constructor has assigned all\n * fields. The free-helper form (rather than a `protected freeze()`\n * instance method) keeps the class type structurally narrow so emitted\n * contract literal types remain assignable to their class types.\n *\n * The helper name stays `freezeNode` — it operates on IR nodes\n * regardless of root naming.\n */\nexport function freezeNode<T extends IRNode>(node: T): T {\n Object.freeze(node);\n return node;\n}\n","import type { StorageNamespace } from '@prisma-next/contract/types';\nimport { type IRNode, IRNodeBase } from './ir-node';\n\n/**\n * Reserved sentinel namespace id for the late-bound storage slot —\n * the slot whose binding the target resolves at connection time\n * rather than at authoring time. Postgres uses it for `search_path`\n * late binding; SQLite uses it for the trivial singleton; Mongo uses\n * it for the connection's `db` binding.\n *\n * Materialised target-side as a singleton subclass of the target's\n * `NamespaceBase` concretion that overrides the namespace's\n * qualifier-emission methods to elide the prefix entirely. Call sites\n * stay polymorphic and never branch on `id === UNBOUND_NAMESPACE_ID`\n * — the singleton's overrides drop the qualifier so emitted SQL / Mongo\n * commands look unqualified.\n *\n * The double-underscore decoration marks the id as a framework-reserved\n * coordinate when it appears in a JSON envelope (cold-read-as-reserved\n * — no realistic collision with user-declared namespace names).\n *\n * Encoded as an exported const (rather than scattered string literals)\n * so the sentinel-id invariant is single-sourced: any production-source\n * site that constructs an unbound-namespace singleton imports this\n * constant.\n */\nexport const UNBOUND_NAMESPACE_ID = '__unbound__' as const;\n\n/**\n * Framework-level building block for a \"namespace\" — the database-level\n * grouping under which storage objects (tables, collections, enums, …)\n * reside. Each target's namespace concretion maps the framework concept to\n * a target-native binding:\n *\n * - Postgres: a schema (`CREATE SCHEMA …`); rendered as `\"<schema>\"`.\n * - SQLite: the singleton `UNBOUND_NAMESPACE_ID`; emitted SQL has no qualifier.\n * - Mongo: the connection's `db` field; addressed as a database name.\n *\n * See `UNBOUND_NAMESPACE_ID` above for the sentinel id and the\n * singleton-subclass pattern that materialises it.\n *\n * The framework promises only the coordinate (`id`) — the named storage\n * entities a namespace contains are family-typed (SQL contributes\n * `table` / `type`, Mongo contributes `collection`, future families pick\n * their own native idiom under `entries`). Generic consumers walking \"all\n * named entries\" go through a family-typed namespace, not the framework\n * `Namespace`.\n *\n * Every namespace concretion (e.g. family-built SQL namespaces,\n * `MongoUnboundNamespace`, target-promoted namespaces like\n * `PostgresSchema`) carries exactly: `id` (enumerable string),\n * `entries` (frozen object holding entity-kind slot maps), and `kind`\n * (non-enumerable string discriminator set via `Object.defineProperty`).\n * Each slot map under `entries` uses a singular essence key (`table`,\n * `type`, `collection`, …) mapping entity names to IR classes. No other\n * own-enumerable data lives on a namespace; non-entity computed data lives\n * on the surrounding storage or contract IR. The framework's\n * `elementCoordinates(storage)` walk relies on this invariant to enumerate\n * entities structurally without family-specific knowledge.\n */\nexport interface Namespace extends IRNode, StorageNamespace {\n readonly kind: string;\n readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>;\n /**\n * Whether this namespace is the late-bound unbound slot (see\n * {@link UNBOUND_NAMESPACE_ID}). Optional so JSON-shaped structural\n * satisfiers remain valid; every hydrated `NamespaceBase` concretion\n * answers it.\n */\n readonly isUnbound?: boolean;\n}\n\nexport abstract class NamespaceBase extends IRNodeBase implements Namespace {\n abstract readonly id: string;\n abstract readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>;\n abstract override readonly kind: string;\n\n /**\n * Answers \"am I the unbound namespace\" as node behavior, so consumers\n * never compare ids against the sentinel. This getter is the single\n * encapsulated place the {@link UNBOUND_NAMESPACE_ID} comparison lives.\n */\n get isUnbound(): boolean {\n return this.id === UNBOUND_NAMESPACE_ID;\n }\n}\n","import { blindCast } from '@prisma-next/utils/casts';\nimport { UNBOUND_NAMESPACE_ID } from './namespace';\nimport type { Storage } from './storage';\n\n/**\n * Extracts the entries map of a contract's single default namespace\n * (`UNBOUND_NAMESPACE_ID`). Both single-namespace families (Mongo, SQLite)\n * store all entities under this one namespace.\n */\nexport type DefaultNamespaceEntries<TStorage extends { readonly namespaces: object }> =\n TStorage['namespaces'] extends Record<typeof UNBOUND_NAMESPACE_ID, { readonly entries: infer E }>\n ? E\n : never;\n\n/**\n * Generic single-namespace projection shape — one namespace's entity-kind slots.\n * A family supplies:\n * - `TEntries` — the family's `*NamespaceEntries` type for the namespace.\n * - `TBuiltinKinds` — the union of the family's statically-named built-in kind\n * keys (Mongo `'collection'`; SQL `'table' | 'valueSet'`).\n *\n * Each built-in kind becomes a top-level accessor; the remaining pack-contributed\n * kinds stay under `.entries` (keyed by their registered singular kind string).\n *\n * A built-in kind that the emitted contract does not carry resolves to an empty\n * map (`Record<string, never>`), matching the runtime which always materializes\n * each built-in slot. The `& string` index-signature member of `TEntries` is\n * excluded from `.entries` so only the literal pack-kind keys remain.\n */\nexport type SingleNamespaceView<TEntries, TBuiltinKinds extends string> = {\n readonly [K in TBuiltinKinds]-?: K extends keyof TEntries\n ? NonNullable<TEntries[K]>\n : Record<string, never>;\n} & {\n readonly entries: {\n readonly [K in Exclude<keyof TEntries, TBuiltinKinds | number | symbol> as string extends K\n ? never\n : K]: TEntries[K];\n };\n};\n\n/** The `entries` shape of one namespace in a storage map. */\ntype EntriesOf<TNamespace> = TNamespace extends { readonly entries: infer E } ? E : never;\n\n/**\n * The namespace-keyed entity-view map — every storage namespace keyed by its raw\n * id, each projected to its {@link SingleNamespaceView}. Mirrors\n * `NamespacedEnums` from `@prisma-next/contract/enum-accessor`: the migration\n * author's storage-side `view.namespace.<nsId>` is the twin of the runtime's\n * `db.enums.<nsId>`. Nesting the schema map under one fixed `namespace` member\n * makes it collision-proof — a schema named `storage` is `view.namespace.storage`,\n * never a contract-root key.\n */\nexport type NamespacedEntities<\n TStorage extends { readonly namespaces: object },\n TBuiltinKinds extends string,\n> = {\n readonly [Ns in keyof TStorage['namespaces']]: SingleNamespaceView<\n EntriesOf<TStorage['namespaces'][Ns]>,\n TBuiltinKinds\n >;\n};\n\n/**\n * Projects one namespace's `entries` into the view shape: each built-in kind\n * becomes a top-level slot (materialized empty if absent), and the remaining\n * pack-contributed kinds sit under `.entries`. Shared by the single-namespace\n * builder and the namespace-map builder.\n */\nexport function promoteBuiltinKinds<TView>(\n entries: Readonly<Record<string, unknown>>,\n builtinKinds: readonly string[],\n): TView {\n const view: Record<string, unknown> = {};\n const rest: Record<string, unknown> = {};\n for (const [kind, kindMap] of Object.entries(entries)) {\n if (builtinKinds.includes(kind)) {\n view[kind] = kindMap;\n } else {\n rest[kind] = kindMap;\n }\n }\n for (const kind of builtinKinds) {\n if (!(kind in view)) {\n view[kind] = {};\n }\n }\n view['entries'] = rest;\n return blindCast<TView, 'view is built to the SingleNamespaceView shape the caller parametrizes'>(\n view,\n );\n}\n\n/**\n * Builds one namespace's entity view: promotes the given built-in kind slots to\n * top-level for the default (`UNBOUND_NAMESPACE_ID`) namespace. Single-namespace\n * targets (Mongo, SQLite) use this to unwrap their sole namespace to the root.\n *\n * Throws if the contract has no default (`UNBOUND_NAMESPACE_ID`) namespace.\n */\nexport function buildSingleNamespaceView<TView>(\n storage: Storage,\n builtinKinds: readonly string[],\n): TView {\n const defaultNs = storage.namespaces[UNBOUND_NAMESPACE_ID];\n if (defaultNs === undefined) {\n throw new Error(`ContractView: contract has no default namespace (${UNBOUND_NAMESPACE_ID})`);\n }\n const entries = blindCast<\n Record<string, unknown>,\n 'Namespace.entries is the open ADR 224 dictionary Record<string, Record<string, unknown>>'\n >(defaultNs.entries);\n return promoteBuiltinKinds<TView>(entries, builtinKinds);\n}\n\n/**\n * Builds the namespace-keyed entity-view map (`{ <nsId>: SingleNamespaceView }`)\n * for every namespace in the storage, keyed by raw namespace id. Mirrors\n * `buildNamespacedEnums(domain)` — the storage-side twin.\n */\nexport function buildNamespacedEntities<TMap>(\n storage: Storage,\n builtinKinds: readonly string[],\n): TMap {\n const out: Record<string, unknown> = {};\n for (const [nsId, ns] of Object.entries(storage.namespaces)) {\n out[nsId] = promoteBuiltinKinds(\n blindCast<\n Readonly<Record<string, unknown>>,\n 'Namespace.entries is the open ADR 224 dictionary Record<string, Record<string, unknown>>'\n >(ns.entries),\n builtinKinds,\n );\n }\n return blindCast<\n TMap,\n 'each namespace projected to its SingleNamespaceView; keys mirror the storage namespace ids'\n >(out);\n}\n","import type { ApplicationDomain } from '@prisma-next/contract/types';\nimport type { EntityCoordinate } from './storage';\n\n/**\n * Lazy walk over every named domain entity in a {@link ApplicationDomain},\n * yielded as {@link EntityCoordinate} tuples with `plane: 'domain'`.\n *\n * Same structural rules as {@link elementCoordinates} over storage: skip\n * scalar `id`; each other object-valued property is an entity-kind slot.\n */\nexport function* domainElementCoordinates(\n domain: Pick<ApplicationDomain, 'namespaces'>,\n): Generator<EntityCoordinate> {\n for (const [namespaceId, ns] of Object.entries(domain.namespaces)) {\n for (const [entityKind, slot] of Object.entries(ns)) {\n if (entityKind === 'id') continue;\n if (slot === null || typeof slot !== 'object') continue;\n for (const entityName of Object.keys(slot)) {\n yield { plane: 'domain', namespaceId, entityKind, entityName };\n }\n }\n }\n}\n","import { blindCast } from '@prisma-next/utils/casts';\nimport type { Type } from 'arktype';\n\nexport interface EntityKindDescriptor<Input, Node> {\n readonly kind: string;\n // Type<unknown>, not Type<Input>: AnyEntityKindDescriptor widens Input to never, which would force an unusable Type<never>; concrete descriptors still carry their real schema.\n readonly schema: Type<unknown>;\n readonly construct: (input: Input) => Node;\n}\n\nexport type AnyEntityKindDescriptor = EntityKindDescriptor<never, unknown>;\n\n/**\n * Hydrates a namespace's entities from raw JSON maps into IR class instances.\n *\n * For each kind in `entries`: if the descriptor map has a descriptor,\n * construct each inner-map value; otherwise freeze-and-carry (`'carry'`)\n * or throw naming the kind and nsId (`'fail'`).\n *\n * The single boundary cast hands `value` to `descriptor.construct` as its\n * `Input`. The value satisfies the kind's `Input` either by the\n * entries-input contract at authoring time or by prior `validateStorage`\n * validation at hydration time.\n */\nexport function hydrateNamespaceEntities(\n entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>,\n kinds: ReadonlyMap<string, AnyEntityKindDescriptor>,\n onUnknown: 'carry' | 'fail',\n nsId?: string,\n): Record<string, Readonly<Record<string, unknown>>> {\n const result: Record<string, Readonly<Record<string, unknown>>> = {};\n for (const [kind, rawMap] of Object.entries(entries)) {\n const descriptor = kinds.get(kind);\n if (descriptor !== undefined) {\n const built: Record<string, unknown> = {};\n for (const [name, value] of Object.entries(rawMap)) {\n built[name] = descriptor.construct(\n blindCast<\n never,\n \"value is this kind's descriptor Input: when authoring, the typed entries-input contract produces it; when hydrating, it was validated against descriptor.schema before this loop. The never target is AnyEntityKindDescriptor's erased Input parameter.\"\n >(value),\n );\n }\n result[kind] = Object.freeze(built);\n } else if (onUnknown === 'carry') {\n result[kind] = Object.freeze(rawMap);\n } else {\n throw new Error(\n `Unknown entries key \"${kind}\" in namespace \"${nsId ?? '?'}\"; no hydration factory registered for this entity kind`,\n );\n }\n }\n return result;\n}\n","import { isPlainRecord } from '@prisma-next/contract/is-plain-record';\nimport type { StorageBase } from '@prisma-next/contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { IRNode } from './ir-node';\nimport type { Namespace } from './namespace';\n\nexport { isPlainRecord };\n\n/**\n * Canonical address for a named entity in Contract IR / Schema IR.\n *\n * `plane` is `'domain' | 'storage'`: which top-level contract plane the\n * entity lives on. Domain-side walks yield `plane: 'domain'` via\n * {@link domainElementCoordinates}; {@link elementCoordinates} over storage\n * yields `plane: 'storage'`.\n *\n * Cross-plane references obey a directional invariant: domain → storage is\n * allowed; storage → domain is forbidden. That rule is enforced by a\n * separate validator, not by constraining this coordinate shape — the\n * coordinate carries the axis the validator checks.\n *\n * Iteration order over namespace properties follows `Object.entries` order;\n * consumers that depend on ordering must sort.\n */\nexport interface EntityCoordinate {\n readonly plane: 'domain' | 'storage';\n readonly namespaceId: string;\n readonly entityKind: string;\n readonly entityName: string;\n}\n\n/**\n * Lazy walk over every named storage entity in a `Storage`-shaped\n * value, yielded as {@link EntityCoordinate} tuples with\n * `plane: 'storage'` (the parameter type binds the plane).\n *\n * Iterates each namespace's `entries` kind maps structurally. Skips\n * non-object `entries`; `id` and `kind` are not walked (`kind` is\n * non-enumerable on concretions). For every entity-kind key under\n * `entries` whose value is a non-null object, yields one coordinate per\n * entity name in that map. No family-specific kind vocabulary is required.\n */\nexport function* elementCoordinates(\n storage: Pick<StorageBase, 'namespaces'>,\n): Generator<EntityCoordinate> {\n for (const [namespaceId, ns] of Object.entries(storage.namespaces)) {\n const entries = ns.entries;\n if (entries === null || typeof entries !== 'object') continue;\n for (const [entityKind, kindMap] of Object.entries(entries)) {\n if (kindMap === null || typeof kindMap !== 'object') continue;\n for (const entityName of Object.keys(kindMap)) {\n yield { plane: 'storage', namespaceId, entityKind, entityName };\n }\n }\n }\n}\n\n/**\n * Canonical, collision-safe key for an {@link EntityCoordinate}. Encodes each\n * axis individually with `JSON.stringify` before joining with `-`, so no\n * namespace id, entity kind, or entity name can forge a collision by\n * embedding the delimiter itself (e.g. a delimiter of `:` would let\n * `('a', 'b:c', 'd')` collide with `('a:b', 'c', 'd')`) — each component is\n * quoted, and any `-` or `\"` inside it is escaped or safely inside those\n * quotes.\n *\n * The single shared key every coordinate-driven ownership/omission/collision\n * check should use — `contract infer`'s pack-described-element omission and\n * the migration tools' cross-space disjointness check both key on this.\n */\nexport function coordinateKey(\n coordinate: Pick<EntityCoordinate, 'namespaceId' | 'entityKind' | 'entityName'>,\n): string {\n return [coordinate.namespaceId, coordinate.entityKind, coordinate.entityName]\n .map((value) => JSON.stringify(value))\n .join('-');\n}\n\n/**\n * Looks up a single entity in a `Storage`-shaped value by its full coordinate.\n * Returns `undefined` if the namespace, entity kind, or entity name is absent.\n * The type parameter is a caller assertion — the walk itself is structural\n * and cannot verify the entity's shape.\n */\nexport function entityAt<T = unknown>(\n storage: Pick<StorageBase, 'namespaces'>,\n coord: Pick<EntityCoordinate, 'namespaceId' | 'entityKind' | 'entityName'>,\n): T | undefined {\n const ns = storage.namespaces[coord.namespaceId];\n if (ns === undefined) return undefined;\n const entries = ns.entries;\n if (!isPlainRecord(entries)) return undefined;\n const kindMap = entries[coord.entityKind];\n if (!isPlainRecord(kindMap)) return undefined;\n if (!Object.hasOwn(kindMap, coord.entityName)) return undefined;\n return blindCast<T | undefined, 'caller asserts the entity type at this coordinate'>(\n kindMap[coord.entityName],\n );\n}\n\n/**\n * Framework-level promise that every Contract IR / Schema IR carries a\n * collection of namespaces keyed by namespace id. Family storage\n * concretions (`SqlStorage`, `MongoStorage`) refine the shape with\n * family-specific fields (tables, collections, enums, …); target\n * concretions add target fields where the family vocabulary doesn't\n * reach.\n *\n * Keeping `namespaces` at the framework layer enforces that every storage\n * object — across any target — is namespace-scoped. The framework can\n * therefore walk the namespace map without knowing the family alphabet, and\n * the `(namespace.id, name)` keying that the verifier and planner depend on\n * is honest at every layer.\n *\n * Extends `IRNode` so the framework's IR-walking surfaces (verifiers,\n * serializers) can dispatch on `Storage`-typed fields through the same\n * IR-node alphabet as every other node — the structural dual already\n * holds in code (every concrete storage class extends an IR-node base);\n * the interface promotion makes the typing honest.\n *\n * **Persisted envelope shape is target-owned, not framework-promised.**\n * Whether the `namespaces` map appears in the on-disk JSON envelope is\n * a per-target decision made by `ContractSerializer.serializeContract`.\n * Some targets emit a JSON-clean namespace shape that round-trips\n * through `JSON.stringify` cleanly (SQL today via the family-layer\n * identity serializer); others ship runtime-only fields on their\n * namespace concretions and override `serializeContract` to strip\n * them (Mongo). Future open (F16): extend the per-target\n * `ContractSerializer` integration-test surface with an explicit\n * envelope-shape assertion for each target, so the strip-vs-pass-through\n * choice is locked at test time rather than implied by the override\n * presence/absence. Earned by PR2's per-target namespace lift, when\n * `PostgresSchema` / `SqliteUnboundDatabase` start carrying\n * target-specific fields.\n */\nexport interface Storage extends IRNode {\n readonly namespaces: Readonly<Record<string, Namespace>>;\n}\n"],"mappings":";;;AA6CA,IAAsB,aAAtB,MAAmD,CAEnD;;;;;;;;;;AAWA,SAAgB,WAA6B,MAAY;CACvD,OAAO,OAAO,IAAI;CAClB,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA,MAAa,uBAAuB;AA8CpC,IAAsB,gBAAtB,cAA4C,WAAgC;;;;;;CAU1E,IAAI,YAAqB;EACvB,OAAO,KAAK,OAAO;CACrB;AACF;;;;;;;;;AChBA,SAAgB,oBACd,SACA,cACO;CACP,MAAM,OAAgC,CAAC;CACvC,MAAM,OAAgC,CAAC;CACvC,KAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,OAAO,GAClD,IAAI,aAAa,SAAS,IAAI,GAC5B,KAAK,QAAQ;MAEb,KAAK,QAAQ;CAGjB,KAAK,MAAM,QAAQ,cACjB,IAAI,EAAE,QAAQ,OACZ,KAAK,QAAQ,CAAC;CAGlB,KAAK,aAAa;CAClB,OAAO,UACL,IACF;AACF;;;;;;;;AASA,SAAgB,yBACd,SACA,cACO;CACP,MAAM,YAAY,QAAQ,WAAW;CACrC,IAAI,cAAc,KAAA,GAChB,MAAM,IAAI,MAAM,oDAAoD,qBAAqB,EAAE;CAM7F,OAAO,oBAJS,UAGd,UAAU,OAC4B,GAAG,YAAY;AACzD;;;;;;AAOA,SAAgB,wBACd,SACA,cACM;CACN,MAAM,MAA+B,CAAC;CACtC,KAAK,MAAM,CAAC,MAAM,OAAO,OAAO,QAAQ,QAAQ,UAAU,GACxD,IAAI,QAAQ,oBACV,UAGE,GAAG,OAAO,GACZ,YACF;CAEF,OAAO,UAGL,GAAG;AACP;;;;;;;;;;AChIA,UAAiB,yBACf,QAC6B;CAC7B,KAAK,MAAM,CAAC,aAAa,OAAO,OAAO,QAAQ,OAAO,UAAU,GAC9D,KAAK,MAAM,CAAC,YAAY,SAAS,OAAO,QAAQ,EAAE,GAAG;EACnD,IAAI,eAAe,MAAM;EACzB,IAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;EAC/C,KAAK,MAAM,cAAc,OAAO,KAAK,IAAI,GACvC,MAAM;GAAE,OAAO;GAAU;GAAa;GAAY;EAAW;CAEjE;AAEJ;;;;;;;;;;;;;;;ACEA,SAAgB,yBACd,SACA,OACA,WACA,MACmD;CACnD,MAAM,SAA4D,CAAC;CACnE,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,OAAO,GAAG;EACpD,MAAM,aAAa,MAAM,IAAI,IAAI;EACjC,IAAI,eAAe,KAAA,GAAW;GAC5B,MAAM,QAAiC,CAAC;GACxC,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,GAC/C,MAAM,QAAQ,WAAW,UACvB,UAGE,KAAK,CACT;GAEF,OAAO,QAAQ,OAAO,OAAO,KAAK;EACpC,OAAO,IAAI,cAAc,SACvB,OAAO,QAAQ,OAAO,OAAO,MAAM;OAEnC,MAAM,IAAI,MACR,wBAAwB,KAAK,kBAAkB,QAAQ,IAAI,wDAC7D;CAEJ;CACA,OAAO;AACT;;;;;;;;;;;;;;ACXA,UAAiB,mBACf,SAC6B;CAC7B,KAAK,MAAM,CAAC,aAAa,OAAO,OAAO,QAAQ,QAAQ,UAAU,GAAG;EAClE,MAAM,UAAU,GAAG;EACnB,IAAI,YAAY,QAAQ,OAAO,YAAY,UAAU;EACrD,KAAK,MAAM,CAAC,YAAY,YAAY,OAAO,QAAQ,OAAO,GAAG;GAC3D,IAAI,YAAY,QAAQ,OAAO,YAAY,UAAU;GACrD,KAAK,MAAM,cAAc,OAAO,KAAK,OAAO,GAC1C,MAAM;IAAE,OAAO;IAAW;IAAa;IAAY;GAAW;EAElE;CACF;AACF;;;;;;;;;;;;;;AAeA,SAAgB,cACd,YACQ;CACR,OAAO;EAAC,WAAW;EAAa,WAAW;EAAY,WAAW;CAAU,CAAC,CAC1E,KAAK,UAAU,KAAK,UAAU,KAAK,CAAC,CAAC,CACrC,KAAK,GAAG;AACb;;;;;;;AAQA,SAAgB,SACd,SACA,OACe;CACf,MAAM,KAAK,QAAQ,WAAW,MAAM;CACpC,IAAI,OAAO,KAAA,GAAW,OAAO,KAAA;CAC7B,MAAM,UAAU,GAAG;CACnB,IAAI,CAAC,cAAc,OAAO,GAAG,OAAO,KAAA;CACpC,MAAM,UAAU,QAAQ,MAAM;CAC9B,IAAI,CAAC,cAAc,OAAO,GAAG,OAAO,KAAA;CACpC,IAAI,CAAC,OAAO,OAAO,SAAS,MAAM,UAAU,GAAG,OAAO,KAAA;CACtD,OAAO,UACL,QAAQ,MAAM,WAChB;AACF"} |
@@ -1,4 +0,4 @@ | ||
| import { r as CodecLookup } from "./codec-types-yY3eSmi0.mjs"; | ||
| import { B as PslExtensionBlockAttribute, F as PslBlockParamOption, G as PslExtensionBlockParamRef, H as PslExtensionBlockParamBare, I as PslBlockParamRef, J as PslPosition, K as PslExtensionBlockParamScalarValue, L as PslBlockParamValue, N as PslBlockParam, P as PslBlockParamList, R as PslDiagnosticCode, U as PslExtensionBlockParamList, V as PslExtensionBlockAttributeArg, W as PslExtensionBlockParamOption, Y as PslSpan, h as AuthoringPslBlockDescriptorNamespace, m as AuthoringPslBlockDescriptor, q as PslExtensionBlockParamValue, z as PslExtensionBlock } from "./framework-authoring-CJC4jwGo.mjs"; | ||
| import { A as makePslNamespace, C as PslReferentialAction, D as UNSPECIFIED_PSL_NAMESPACE_ID, E as PslUniqueConstraint, M as namespacePslExtensionBlocks, O as flatPslCompositeTypes, S as PslNamespaceEntry, T as PslTypesBlock, _ as PslIndexConstraint, a as PslAttributeArgument, b as PslNamedTypeDeclaration, c as PslAttributeTarget, d as PslDefaultLiteralValue, f as PslDefaultValue, g as PslFieldAttribute, h as PslField, i as PslAttribute, j as makePslNamespaceEntries, k as flatPslModels, l as PslCompositeType, m as PslDocumentAst, n as ParsePslDocumentInput, o as PslAttributeNamedArgument, p as PslDiagnostic, r as ParsePslDocumentResult, s as PslAttributePositionalArgument, t as BUILTIN_PSL_KIND_KEYS, u as PslDefaultFunctionValue, v as PslModel, w as PslTypeConstructorCall, x as PslNamespace, y as PslModelAttribute } from "./psl-ast-B-C_9dWr.mjs"; | ||
| import { r as CodecLookup } from "./codec-types-e32YHT3D.mjs"; | ||
| import { $ as PslExtensionBlockParamRef, G as PslBlockParamValue, H as PslBlockParamList, J as PslExtensionBlockAttribute, K as PslDiagnosticCode, Q as PslExtensionBlockParamOption, U as PslBlockParamOption, V as PslBlockParam, W as PslBlockParamRef, X as PslExtensionBlockParamBare, Y as PslExtensionBlockAttributeArg, Z as PslExtensionBlockParamList, et as PslExtensionBlockParamScalarValue, nt as PslPosition, q as PslExtensionBlock, rt as PslSpan, tt as PslExtensionBlockParamValue, v as AuthoringPslBlockDescriptor, y as AuthoringPslBlockDescriptorNamespace } from "./framework-authoring-DEadmUb3.mjs"; | ||
| import { A as makePslNamespace, C as PslReferentialAction, D as UNSPECIFIED_PSL_NAMESPACE_ID, E as PslUniqueConstraint, M as namespacePslExtensionBlocks, O as flatPslCompositeTypes, S as PslNamespaceEntry, T as PslTypesBlock, _ as PslIndexConstraint, a as PslAttributeArgument, b as PslNamedTypeDeclaration, c as PslAttributeTarget, d as PslDefaultLiteralValue, f as PslDefaultValue, g as PslFieldAttribute, h as PslField, i as PslAttribute, j as makePslNamespaceEntries, k as flatPslModels, l as PslCompositeType, m as PslDocumentAst, n as ParsePslDocumentInput, o as PslAttributeNamedArgument, p as PslDiagnostic, r as ParsePslDocumentResult, s as PslAttributePositionalArgument, t as BUILTIN_PSL_KIND_KEYS, u as PslDefaultFunctionValue, v as PslModel, w as PslTypeConstructorCall, x as PslNamespace, y as PslModelAttribute } from "./psl-ast-jgAyMeUx.mjs"; | ||
@@ -5,0 +5,0 @@ //#region src/control/psl-extension-block-validator.d.ts |
+1
-1
@@ -91,3 +91,3 @@ import { blindCast } from "@prisma-next/utils/casts"; | ||
| */ | ||
| const BUILTIN_PSL_KIND_KEYS = new Set(["model", "compositeType"]); | ||
| const BUILTIN_PSL_KIND_KEYS = /* @__PURE__ */ new Set(["model", "compositeType"]); | ||
| /** | ||
@@ -94,0 +94,0 @@ * Returns all extension-contributed blocks in the given namespace, in |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"psl-ast.mjs","names":[],"sources":["../src/control/psl-ast.ts","../src/control/psl-extension-block-validator.ts"],"sourcesContent":["export type { AuthoringPslBlockDescriptorNamespace } from '../shared/framework-authoring';\nexport type {\n PslBlockParam,\n PslBlockParamList,\n PslBlockParamOption,\n PslBlockParamRef,\n PslBlockParamValue,\n PslDiagnosticCode,\n PslExtensionBlock,\n PslExtensionBlockAttribute,\n PslExtensionBlockAttributeArg,\n PslExtensionBlockParamBare,\n PslExtensionBlockParamList,\n PslExtensionBlockParamOption,\n PslExtensionBlockParamRef,\n PslExtensionBlockParamScalarValue,\n PslExtensionBlockParamValue,\n PslPosition,\n PslSpan,\n} from '../shared/psl-extension-block';\n\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { CodecLookup } from '../shared/codec-types';\nimport type { AuthoringPslBlockDescriptorNamespace } from '../shared/framework-authoring';\nimport type { PslDiagnosticCode, PslExtensionBlock, PslSpan } from '../shared/psl-extension-block';\n\nexport interface PslDiagnostic {\n readonly code: PslDiagnosticCode;\n readonly message: string;\n readonly sourceId: string;\n readonly span: PslSpan;\n}\n\nexport interface PslDefaultFunctionValue {\n readonly kind: 'function';\n readonly name: 'autoincrement' | 'now';\n}\n\nexport interface PslDefaultLiteralValue {\n readonly kind: 'literal';\n readonly value: string | number | boolean;\n}\n\nexport type PslDefaultValue = PslDefaultFunctionValue | PslDefaultLiteralValue;\n\nexport type PslAttributeTarget = 'field' | 'model' | 'enum' | 'namedType';\n\nexport interface PslAttributePositionalArgument {\n readonly kind: 'positional';\n readonly value: string;\n readonly span: PslSpan;\n}\n\nexport interface PslAttributeNamedArgument {\n readonly kind: 'named';\n readonly name: string;\n readonly value: string;\n readonly span: PslSpan;\n}\n\nexport type PslAttributeArgument = PslAttributePositionalArgument | PslAttributeNamedArgument;\n\nexport interface PslTypeConstructorCall {\n readonly kind: 'typeConstructor';\n readonly path: readonly string[];\n readonly args: readonly PslAttributeArgument[];\n readonly span: PslSpan;\n}\n\nexport interface PslAttribute {\n readonly kind: 'attribute';\n readonly target: PslAttributeTarget;\n readonly name: string;\n readonly args: readonly PslAttributeArgument[];\n readonly span: PslSpan;\n}\n\nexport type PslReferentialAction = string;\n\nexport type PslFieldAttribute = PslAttribute;\n\nexport interface PslField {\n readonly kind: 'field';\n readonly name: string;\n /** Unqualified type name, e.g. `\"User\"` for both `User`, `auth.User`, and `supabase:auth.User`. */\n readonly typeName: string;\n /** Namespace qualifier from a dot-qualified type reference, e.g. `\"auth\"` for `auth.User` or `supabase:auth.User`. Absent for unqualified types. */\n readonly typeNamespaceId?: string;\n /**\n * Contract-space qualifier from a colon-prefix type reference, e.g. `\"supabase\"` for\n * `supabase:auth.User` or `supabase:User`. Absent for local (same-space) type references.\n *\n * When present, the field references a model from a different contract space. The namespace\n * (`typeNamespaceId`) and model name (`typeName`) identify the target within that space.\n * Physical table resolution against the extension contract is deferred to the aggregate stage (M3).\n */\n readonly typeContractSpaceId?: string;\n readonly typeConstructor?: PslTypeConstructorCall;\n readonly optional: boolean;\n readonly list: boolean;\n readonly typeRef?: string;\n readonly attributes: readonly PslFieldAttribute[];\n readonly span: PslSpan;\n}\n\nexport interface PslUniqueConstraint {\n readonly kind: 'unique';\n readonly fields: readonly string[];\n readonly span: PslSpan;\n}\n\nexport interface PslIndexConstraint {\n readonly kind: 'index';\n readonly fields: readonly string[];\n readonly span: PslSpan;\n}\n\nexport type PslModelAttribute = PslAttribute;\n\nexport interface PslModel {\n readonly kind: 'model';\n readonly name: string;\n readonly fields: readonly PslField[];\n readonly attributes: readonly PslModelAttribute[];\n readonly span: PslSpan;\n /**\n * Optional leading comment line emitted above the `model` keyword by the\n * printer. Producers (e.g. `sqlSchemaIrToPslAst`) attach introspection\n * advisories such as \"// WARNING: This table has no primary key in the\n * database\" here. The parser leaves this field unset; round-tripping a\n * parsed schema does not re-attach comments.\n */\n readonly comment?: string;\n}\n\n/**\n * A reusable group of fields embedded in a model (a `type Name { … }` block) —\n * e.g. a MongoDB embedded document or a Postgres composite type. Unlike\n * {@link PslModel} it has no storage or identity of its own.\n */\nexport interface PslCompositeType {\n readonly kind: 'compositeType';\n readonly name: string;\n readonly fields: readonly PslField[];\n readonly attributes: readonly PslAttribute[];\n readonly span: PslSpan;\n}\n\nexport interface PslNamedTypeDeclaration {\n readonly kind: 'namedType';\n readonly name: string;\n /**\n * Parser invariant: exactly one of `baseType` and `typeConstructor` is set.\n * Expressing this as a discriminated union trips TypeScript narrowing when\n * the declaration flows through helpers that accept the full union.\n */\n readonly baseType?: string;\n readonly typeConstructor?: PslTypeConstructorCall;\n readonly attributes: readonly PslAttribute[];\n readonly span: PslSpan;\n}\n\nexport interface PslTypesBlock {\n readonly kind: 'types';\n readonly declarations: readonly PslNamedTypeDeclaration[];\n readonly span: PslSpan;\n}\n\n/**\n * Name of the synthesised namespace bucket the framework parser uses for\n * top-level declarations that appear outside any `namespace { … }` block.\n * The double-underscore decoration signals that the identifier is parser-\n * synthesised and never appears in user-authored PSL source — writing\n * `namespace __unspecified__ { … }` is a parse error.\n *\n * Distinct from the IR sentinel `__unbound__`: the PSL bucket describes\n * syntactic absence at the parser layer; the IR sentinel describes a late-\n * bound storage slot at the IR layer. Per-target interpreters decide how\n * (or whether) to map the PSL bucket to the IR sentinel.\n */\nexport const UNSPECIFIED_PSL_NAMESPACE_ID = '__unspecified__';\n\n/** A value in {@link PslNamespace.entries}: a built-in entity node or an extension-contributed {@link PslExtensionBlock}. */\nexport type PslNamespaceEntry = PslModel | PslCompositeType | PslExtensionBlock;\n\n/**\n * A namespace block, or the parser's synthesised `__unspecified__` bucket for\n * declarations outside any `namespace { … }`. Same-name blocks reopen-merge;\n * `span` points at the first opening.\n *\n * Entities are stored canonically (ADR 224) in `entries[kind][name]`, where\n * `kind` is the PSL keyword for built-ins or the block discriminator for\n * extension kinds, e.g. `entries['policy_select']['ReadPosts']`.\n */\nexport interface PslNamespace {\n readonly kind: 'namespace';\n readonly name: string;\n /** Canonical store: a frozen container of frozen per-kind maps. The accessors below derive from it. */\n readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>;\n /** Built-in models, from `entries['model']`. Extension kinds: {@link namespacePslExtensionBlocks}. */\n readonly models: readonly PslModel[];\n /** Built-in composite types, from `entries['compositeType']`. */\n readonly compositeTypes: readonly PslCompositeType[];\n readonly span: PslSpan;\n}\n\n/**\n * Stores `entries`; exposes `models`/`enums`/`compositeTypes` as getters over\n * it. The getters are prototype members (non-enumerable), so spreading or\n * `JSON.stringify`-ing a namespace copies only `entries`, never a duplicate view.\n */\nclass PslNamespaceNode implements PslNamespace {\n readonly kind = 'namespace' as const;\n readonly name: string;\n readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>;\n readonly span: PslSpan;\n\n constructor(init: {\n readonly name: string;\n readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>;\n readonly span: PslSpan;\n }) {\n this.name = init.name;\n this.entries = init.entries;\n this.span = init.span;\n Object.freeze(this);\n }\n\n get models(): readonly PslModel[] {\n return blindCast<readonly PslModel[], 'entries[model] holds only PslModel by construction'>(\n Object.values(this.entries['model'] ?? {}),\n );\n }\n\n get compositeTypes(): readonly PslCompositeType[] {\n return blindCast<\n readonly PslCompositeType[],\n 'entries[compositeType] holds only PslCompositeType by construction'\n >(Object.values(this.entries['compositeType'] ?? {}));\n }\n}\n\n/** Constructs a {@link PslNamespace}. Use this, never a namespace literal — the accessors must derive from `entries`. */\nexport function makePslNamespace(init: {\n readonly kind: 'namespace';\n readonly name: string;\n readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>;\n readonly span: PslSpan;\n}): PslNamespace {\n return new PslNamespaceNode(init);\n}\n\n/**\n * Builds the frozen `entries[kind][name]` container from per-kind arrays.\n * Built-ins key on their PSL keyword; extension blocks key on their `kind`\n * discriminator. Call this rather than hand-building the literal.\n */\nexport function makePslNamespaceEntries(\n models: readonly PslModel[],\n compositeTypes: readonly PslCompositeType[],\n extensionBlocks: readonly PslExtensionBlock[],\n): Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>> {\n const container: Record<string, Readonly<Record<string, PslNamespaceEntry>>> = {};\n\n if (models.length > 0) {\n const map: Record<string, PslModel> = {};\n for (const m of models) {\n map[m.name] = m;\n }\n container['model'] = Object.freeze(map);\n }\n\n if (compositeTypes.length > 0) {\n const map: Record<string, PslCompositeType> = {};\n for (const ct of compositeTypes) {\n map[ct.name] = ct;\n }\n container['compositeType'] = Object.freeze(map);\n }\n\n for (const block of extensionBlocks) {\n const existing = container[block.kind];\n const newMap: Record<string, PslExtensionBlock> = existing\n ? blindCast<Record<string, PslExtensionBlock>, 'kind map holds only PslExtensionBlock'>({\n ...existing,\n })\n : {};\n newMap[block.name] = block;\n container[block.kind] = Object.freeze(newMap);\n }\n\n return Object.freeze(container);\n}\n\nexport interface PslDocumentAst {\n readonly kind: 'document';\n readonly sourceId: string;\n readonly namespaces: readonly PslNamespace[];\n readonly types?: PslTypesBlock;\n readonly span: PslSpan;\n}\n\n/**\n * Returns all models from every namespace in document order. Convenience\n * for consumers that don't (yet) need namespace-awareness.\n */\nexport function flatPslModels(ast: PslDocumentAst): readonly PslModel[] {\n return ast.namespaces.flatMap((ns) =>\n blindCast<PslModel[], 'model kind map contains only PslModel by construction'>(\n Object.values(ns.entries['model'] ?? {}),\n ),\n );\n}\n\n/**\n * Returns all composite types from every namespace in document order.\n */\nexport function flatPslCompositeTypes(ast: PslDocumentAst): readonly PslCompositeType[] {\n return ast.namespaces.flatMap((ns) =>\n blindCast<\n PslCompositeType[],\n 'compositeType kind map contains only PslCompositeType by construction'\n >(Object.values(ns.entries['compositeType'] ?? {})),\n );\n}\n\n/**\n * The set of `entries` kind keys that the framework parser reserves for\n * built-in PSL entity kinds. Any own-enumerable key on `PslNamespace.entries`\n * that is **not** in this set was contributed by an extension-block descriptor.\n *\n * Built-in keys match the PSL keyword used on each block type:\n * `'model'`, `'compositeType'`. The `'enum'` keyword is claimed by the\n * extension-block grammar via a registered descriptor, so `entries['enum']`\n * holds `PslExtensionBlock` nodes and is returned by `namespacePslExtensionBlocks`.\n */\nexport const BUILTIN_PSL_KIND_KEYS: ReadonlySet<string> = new Set(['model', 'compositeType']);\n\n/**\n * Returns all extension-contributed blocks in the given namespace, in\n * insertion order (the order the parser encountered them in the source).\n *\n * Reads from `namespace.entries`, skipping the built-in kind keys\n * (`'model'`, `'compositeType'`). All remaining kind maps contain\n * only `PslExtensionBlock` nodes by construction (see `makePslNamespaceEntries`).\n */\nexport function namespacePslExtensionBlocks(ns: PslNamespace): readonly PslExtensionBlock[] {\n const result: PslExtensionBlock[] = [];\n for (const [kindKey, kindMap] of Object.entries(ns.entries)) {\n if (BUILTIN_PSL_KIND_KEYS.has(kindKey)) continue;\n for (const entry of Object.values(kindMap)) {\n result.push(\n blindCast<\n PslExtensionBlock,\n 'non-builtin kind maps contain only PslExtensionBlock by construction'\n >(entry),\n );\n }\n }\n return result;\n}\n\nexport interface ParsePslDocumentInput {\n readonly schema: string;\n readonly sourceId: string;\n /**\n * Registry of declarative block descriptors, keyed by arbitrary path\n * segments with {@link AuthoringPslBlockDescriptor} leaves. The registry\n * teaches the parser which top-level keywords belong to extension\n * contributions: when the parser encounters an unknown keyword, it looks\n * it up here and, when found, reads the block generically into a\n * {@link PslExtensionBlock} node. Absent or undefined means no extension\n * blocks are registered and any unknown keyword yields\n * `PSL_UNSUPPORTED_TOP_LEVEL_BLOCK`.\n *\n * Contrast with the parsed block nodes themselves, which live in\n * {@link PslNamespace.entries} under their discriminator key (read them with\n * {@link namespacePslExtensionBlocks}); this field holds the registry of\n * descriptors that teach the parser how to read those blocks.\n */\n readonly pslBlockDescriptors?: AuthoringPslBlockDescriptorNamespace;\n /**\n * Codec lookup for validating `value`-kind extension block parameters.\n * When provided alongside `pslBlockDescriptors`, the generic validator runs\n * over every parsed extension block after the full AST is assembled,\n * appending any diagnostics to the parse result. Absent or undefined means\n * no codec validation runs; `ref` resolution still runs when namespace\n * context is available (built from the assembled namespaces).\n */\n readonly codecLookup?: CodecLookup;\n}\n\nexport interface ParsePslDocumentResult {\n readonly ast: PslDocumentAst;\n readonly diagnostics: readonly PslDiagnostic[];\n readonly ok: boolean;\n}\n","/**\n * Generic validator for extension-contributed top-level PSL blocks.\n *\n * One function — {@link validateExtensionBlock} — takes a parsed\n * {@link PslExtensionBlock}, its {@link AuthoringPslBlockDescriptor}, a\n * {@link CodecLookup} (for `value` parameters), and the set of\n * {@link PslNamespace} objects from the document (for `ref` resolution), and\n * returns the full list of {@link PslDiagnostic} objects for the block.\n *\n * Detection logic per failure mode:\n *\n * 1. **Unknown parameter** — keys present in `node.parameters` that are absent\n * from `descriptor.parameters` (key-set difference). The parser stores\n * unknown parameters as `kind:'value'` stubs; the validator discovers them\n * by comparing the key sets, not by inspecting the captured kind.\n *\n * 2. **Missing required parameter** — `descriptor.parameters` entries with\n * `required: true` whose key is absent from `node.parameters`.\n *\n * 3. **`option` value outside its set** — the captured `token` is not in\n * `descriptor.values`.\n *\n * 4. **`value` rejected by its codec** — the raw string is first parsed as\n * JSON (`JSON.parse(raw)`). If `JSON.parse` throws, the literal is not valid\n * JSON and a `PSL_EXTENSION_INVALID_VALUE` diagnostic is emitted. If parsing\n * succeeds but `codec.decodeJson(jsonValue)` throws, the JSON value is not\n * acceptable to the codec and a `PSL_EXTENSION_INVALID_VALUE` diagnostic is\n * emitted. If `codecLookup.get(codecId)` returns `undefined` (unknown codec\n * id), a `PSL_EXTENSION_INVALID_VALUE` diagnostic is also emitted.\n *\n * 5. **`ref` that does not resolve within its scope** — the captured\n * `identifier` is looked up in the PSL document's `PslNamespace` objects\n * according to `param.scope`:\n * - `same-namespace`: the referent must be in the same namespace as the\n * block (the namespace containing the block).\n * - `same-space`: the referent may be in any namespace in the document.\n * - `cross-space`: pass-through — enforcement is scoped to first-consumer\n * need (RLS roles). This case is documented and clearly flagged; the\n * caller is responsible for wiring cross-space resolution when needed.\n *\n * 6. **`list`** — each element is validated against `param.of` recursively.\n *\n * ### `char`/`varchar` length\n * Not enforced. RLS `using`/`check` strings are unbounded text and the codec\n * already rejects structurally invalid literals; length constraints are a\n * database-side concern, not a PSL authoring constraint.\n *\n * ### `cross-space` scope\n * Implemented as a documented pass-through. The spec permits scoping\n * cross-space enforcement to first-consumer need (RLS roles). When RLS roles\n * arrive, wire `cross-space` resolution through the cross-contract-space\n * coordinate model `(spaceId, namespaceId, entityKind, entityName)`.\n */\n\nimport type { JsonValue } from '@prisma-next/contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { CodecLookup } from '../shared/codec-types';\nimport type { AuthoringPslBlockDescriptor } from '../shared/framework-authoring';\nimport type {\n PslBlockParam,\n PslBlockParamRef,\n PslExtensionBlock,\n PslExtensionBlockParamValue,\n PslSpan,\n} from '../shared/psl-extension-block';\nimport type { PslDiagnostic, PslNamespace } from './psl-ast';\n\n/**\n * Context for ref resolution during extension-block validation.\n *\n * - `ownerNamespace` is the `PslNamespace` that contains the block being\n * validated. Used for `same-namespace` scope checks.\n * - `allNamespaces` is every namespace in the document. Used for `same-space`\n * scope checks.\n */\nexport interface ExtensionBlockRefResolutionContext {\n readonly ownerNamespace: PslNamespace;\n readonly allNamespaces: readonly PslNamespace[];\n}\n\n/**\n * Validate a single parsed extension block against its descriptor.\n *\n * Returns an array of {@link PslDiagnostic} objects (possibly empty). The\n * caller is responsible for threading `sourceId` into each returned diagnostic\n * — the returned objects already have `sourceId` set from the `sourceId`\n * parameter.\n *\n * @param node - The parsed block node produced by the generic framework parser.\n * @param descriptor - The descriptor that claims this block's keyword.\n * @param sourceId - The PSL source file identifier (threaded into diagnostics).\n * @param codecLookup - Used to validate `value`-kind parameter literals via\n * `codecLookup.get(codecId)?.decodeJson(JSON.parse(raw))`.\n * @param refCtx - Namespace context for `ref`-kind scope resolution. Required\n * when any descriptor parameter is `kind: 'ref'`; may be omitted if none are.\n */\nexport function validateExtensionBlock(\n node: PslExtensionBlock,\n descriptor: AuthoringPslBlockDescriptor,\n sourceId: string,\n codecLookup: CodecLookup,\n refCtx?: ExtensionBlockRefResolutionContext,\n): readonly PslDiagnostic[] {\n const diagnostics: PslDiagnostic[] = [];\n\n const descriptorKeys = new Set(Object.keys(descriptor.parameters));\n const nodeKeys = new Set(Object.keys(node.parameters));\n\n // 1. Unknown parameters — keys in the node not in the descriptor.\n if (!descriptor.variadicParameters) {\n for (const key of nodeKeys) {\n if (!descriptorKeys.has(key)) {\n const captured = node.parameters[key];\n diagnostics.push({\n code: 'PSL_EXTENSION_UNKNOWN_PARAMETER',\n message: `Unknown parameter \"${key}\" in \"${descriptor.keyword}\" block \"${node.name}\". The descriptor does not declare this parameter.`,\n sourceId,\n span: captured?.span ?? node.span,\n });\n }\n }\n }\n\n // 2. Missing required parameters — required descriptor keys absent from the node.\n for (const [key, param] of Object.entries(descriptor.parameters)) {\n if (param.required === true && !nodeKeys.has(key)) {\n diagnostics.push({\n code: 'PSL_EXTENSION_MISSING_REQUIRED_PARAMETER',\n message: `Required parameter \"${key}\" is missing from \"${descriptor.keyword}\" block \"${node.name}\".`,\n sourceId,\n span: node.span,\n });\n }\n }\n\n // 3–5. Per-parameter validation for parameters that are present.\n for (const [key, param] of Object.entries(descriptor.parameters)) {\n const captured = node.parameters[key];\n if (captured === undefined) {\n continue;\n }\n validateParam(\n node,\n descriptor,\n key,\n param,\n captured,\n sourceId,\n codecLookup,\n refCtx,\n diagnostics,\n );\n }\n\n return diagnostics;\n}\n\nfunction validateParam(\n node: PslExtensionBlock,\n descriptor: AuthoringPslBlockDescriptor,\n key: string,\n param: PslBlockParam,\n captured: PslExtensionBlockParamValue,\n sourceId: string,\n codecLookup: CodecLookup,\n refCtx: ExtensionBlockRefResolutionContext | undefined,\n diagnostics: PslDiagnostic[],\n): void {\n switch (param.kind) {\n case 'option': {\n if (captured.kind !== 'option') {\n return;\n }\n if (!param.values.includes(captured.token)) {\n diagnostics.push({\n code: 'PSL_EXTENSION_OPTION_OUT_OF_SET',\n message: `Parameter \"${key}\" in \"${descriptor.keyword}\" block \"${node.name}\" has value \"${captured.token}\" which is not one of the allowed values: ${param.values.map((v) => `\"${v}\"`).join(', ')}.`,\n sourceId,\n span: captured.span,\n });\n }\n return;\n }\n\n case 'value': {\n if (captured.kind !== 'value') {\n return;\n }\n const codec = codecLookup.get(param.codecId);\n if (codec === undefined) {\n diagnostics.push({\n code: 'PSL_EXTENSION_INVALID_VALUE',\n message: `Parameter \"${key}\" in \"${descriptor.keyword}\" block \"${node.name}\" references unknown codec \"${param.codecId}\".`,\n sourceId,\n span: captured.span,\n });\n return;\n }\n let jsonValue: unknown;\n try {\n jsonValue = JSON.parse(captured.raw);\n } catch {\n diagnostics.push({\n code: 'PSL_EXTENSION_INVALID_VALUE',\n message: `Parameter \"${key}\" in \"${descriptor.keyword}\" block \"${node.name}\" is not a valid JSON literal (expected a JSON string, number, boolean, or null): ${captured.raw}`,\n sourceId,\n span: captured.span,\n });\n return;\n }\n try {\n codec.decodeJson(\n blindCast<JsonValue, 'JSON.parse returns a JsonValue-compatible value'>(jsonValue),\n );\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n diagnostics.push({\n code: 'PSL_EXTENSION_INVALID_VALUE',\n message: `Parameter \"${key}\" in \"${descriptor.keyword}\" block \"${node.name}\" was rejected by codec \"${param.codecId}\": ${reason}`,\n sourceId,\n span: captured.span,\n });\n }\n return;\n }\n\n case 'ref': {\n if (captured.kind !== 'ref') {\n return;\n }\n validateRef(\n node,\n descriptor,\n key,\n param,\n captured.identifier,\n captured.span,\n sourceId,\n refCtx,\n diagnostics,\n );\n return;\n }\n\n case 'list': {\n if (captured.kind !== 'list') {\n return;\n }\n for (const item of captured.items) {\n validateParam(\n node,\n descriptor,\n key,\n param.of,\n item,\n sourceId,\n codecLookup,\n refCtx,\n diagnostics,\n );\n }\n return;\n }\n }\n}\n\nfunction validateRef(\n node: PslExtensionBlock,\n descriptor: AuthoringPslBlockDescriptor,\n key: string,\n param: PslBlockParamRef,\n identifier: string,\n span: PslSpan,\n sourceId: string,\n refCtx: ExtensionBlockRefResolutionContext | undefined,\n diagnostics: PslDiagnostic[],\n): void {\n if (param.scope === 'cross-space') {\n // cross-space enforcement is a documented pass-through. The spec permits\n // scoping cross-space resolution to first-consumer need (RLS roles). When\n // that consumer arrives, wire resolution here through the\n // cross-contract-space coordinate model\n // (spaceId, namespaceId, entityKind, entityName).\n // For now, cross-space refs pass validation unconditionally.\n return;\n }\n\n if (refCtx === undefined) {\n // If no resolution context was provided, skip ref resolution. This matches\n // the closed-grammar invariant: callers that register ref parameters must\n // provide resolution context; callers without namespaces (e.g. unit tests\n // that only exercise other validation modes) can omit it.\n return;\n }\n\n const namespacesToSearch: readonly PslNamespace[] =\n param.scope === 'same-namespace' ? [refCtx.ownerNamespace] : refCtx.allNamespaces;\n\n if (!resolveEntityInNamespaces(identifier, param.refKind, namespacesToSearch)) {\n const scopeLabel =\n param.scope === 'same-namespace' ? 'the same namespace' : 'any namespace in the schema';\n diagnostics.push({\n code: 'PSL_EXTENSION_UNRESOLVED_REF',\n message: `Parameter \"${key}\" in \"${descriptor.keyword}\" block \"${node.name}\" refers to \"${identifier}\" (expected ${param.refKind}), but no entity with that name and kind was found in ${scopeLabel}.`,\n sourceId,\n span,\n });\n }\n}\n\n/**\n * True if an entity named `name` of kind `refKind` exists in any of the given\n * namespaces. Built-in and extension kinds resolve the same way, through\n * `entries[refKind]`.\n */\nfunction resolveEntityInNamespaces(\n name: string,\n refKind: string,\n namespaces: readonly PslNamespace[],\n): boolean {\n for (const ns of namespaces) {\n const kindMap = ns.entries[refKind];\n if (kindMap !== undefined && Object.hasOwn(kindMap, name)) return true;\n }\n return false;\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"psl-ast.mjs","names":[],"sources":["../src/control/psl-ast.ts","../src/control/psl-extension-block-validator.ts"],"sourcesContent":["export type { AuthoringPslBlockDescriptorNamespace } from '../shared/framework-authoring';\nexport type {\n PslBlockParam,\n PslBlockParamList,\n PslBlockParamOption,\n PslBlockParamRef,\n PslBlockParamValue,\n PslDiagnosticCode,\n PslExtensionBlock,\n PslExtensionBlockAttribute,\n PslExtensionBlockAttributeArg,\n PslExtensionBlockParamBare,\n PslExtensionBlockParamList,\n PslExtensionBlockParamOption,\n PslExtensionBlockParamRef,\n PslExtensionBlockParamScalarValue,\n PslExtensionBlockParamValue,\n PslPosition,\n PslSpan,\n} from '../shared/psl-extension-block';\n\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { CodecLookup } from '../shared/codec-types';\nimport type { AuthoringPslBlockDescriptorNamespace } from '../shared/framework-authoring';\nimport type { PslDiagnosticCode, PslExtensionBlock, PslSpan } from '../shared/psl-extension-block';\n\nexport interface PslDiagnostic {\n readonly code: PslDiagnosticCode;\n readonly message: string;\n readonly sourceId: string;\n readonly span: PslSpan;\n}\n\nexport interface PslDefaultFunctionValue {\n readonly kind: 'function';\n readonly name: 'autoincrement' | 'now';\n}\n\nexport interface PslDefaultLiteralValue {\n readonly kind: 'literal';\n readonly value: string | number | boolean;\n}\n\nexport type PslDefaultValue = PslDefaultFunctionValue | PslDefaultLiteralValue;\n\nexport type PslAttributeTarget = 'field' | 'model' | 'enum' | 'namedType';\n\nexport interface PslAttributePositionalArgument {\n readonly kind: 'positional';\n readonly value: string;\n readonly span: PslSpan;\n}\n\nexport interface PslAttributeNamedArgument {\n readonly kind: 'named';\n readonly name: string;\n readonly value: string;\n readonly span: PslSpan;\n}\n\nexport type PslAttributeArgument = PslAttributePositionalArgument | PslAttributeNamedArgument;\n\nexport interface PslTypeConstructorCall {\n readonly kind: 'typeConstructor';\n readonly path: readonly string[];\n readonly args: readonly PslAttributeArgument[];\n readonly span: PslSpan;\n}\n\nexport interface PslAttribute {\n readonly kind: 'attribute';\n readonly target: PslAttributeTarget;\n readonly name: string;\n readonly args: readonly PslAttributeArgument[];\n readonly span: PslSpan;\n}\n\nexport type PslReferentialAction = string;\n\nexport type PslFieldAttribute = PslAttribute;\n\nexport interface PslField {\n readonly kind: 'field';\n readonly name: string;\n /** Unqualified type name, e.g. `\"User\"` for both `User`, `auth.User`, and `supabase:auth.User`. */\n readonly typeName: string;\n /** Namespace qualifier from a dot-qualified type reference, e.g. `\"auth\"` for `auth.User` or `supabase:auth.User`. Absent for unqualified types. */\n readonly typeNamespaceId?: string;\n /**\n * Contract-space qualifier from a colon-prefix type reference, e.g. `\"supabase\"` for\n * `supabase:auth.User` or `supabase:User`. Absent for local (same-space) type references.\n *\n * When present, the field references a model from a different contract space. The namespace\n * (`typeNamespaceId`) and model name (`typeName`) identify the target within that space.\n * Physical table resolution against the extension contract is deferred to the aggregate stage (M3).\n */\n readonly typeContractSpaceId?: string;\n readonly typeConstructor?: PslTypeConstructorCall;\n readonly optional: boolean;\n readonly list: boolean;\n readonly typeRef?: string;\n readonly attributes: readonly PslFieldAttribute[];\n readonly span: PslSpan;\n}\n\nexport interface PslUniqueConstraint {\n readonly kind: 'unique';\n readonly fields: readonly string[];\n readonly span: PslSpan;\n}\n\nexport interface PslIndexConstraint {\n readonly kind: 'index';\n readonly fields: readonly string[];\n readonly span: PslSpan;\n}\n\nexport type PslModelAttribute = PslAttribute;\n\nexport interface PslModel {\n readonly kind: 'model';\n readonly name: string;\n readonly fields: readonly PslField[];\n readonly attributes: readonly PslModelAttribute[];\n readonly span: PslSpan;\n /**\n * Optional leading comment line emitted above the `model` keyword by the\n * printer. Producers (e.g. `sqlSchemaIrToPslAst`) attach introspection\n * advisories such as \"// WARNING: This table has no primary key in the\n * database\" here. The parser leaves this field unset; round-tripping a\n * parsed schema does not re-attach comments.\n */\n readonly comment?: string;\n}\n\n/**\n * A reusable group of fields embedded in a model (a `type Name { … }` block) —\n * e.g. a MongoDB embedded document or a Postgres composite type. Unlike\n * {@link PslModel} it has no storage or identity of its own.\n */\nexport interface PslCompositeType {\n readonly kind: 'compositeType';\n readonly name: string;\n readonly fields: readonly PslField[];\n readonly attributes: readonly PslAttribute[];\n readonly span: PslSpan;\n}\n\nexport interface PslNamedTypeDeclaration {\n readonly kind: 'namedType';\n readonly name: string;\n /**\n * Parser invariant: exactly one of `baseType` and `typeConstructor` is set.\n * Expressing this as a discriminated union trips TypeScript narrowing when\n * the declaration flows through helpers that accept the full union.\n */\n readonly baseType?: string;\n readonly typeConstructor?: PslTypeConstructorCall;\n readonly attributes: readonly PslAttribute[];\n readonly span: PslSpan;\n}\n\nexport interface PslTypesBlock {\n readonly kind: 'types';\n readonly declarations: readonly PslNamedTypeDeclaration[];\n readonly span: PslSpan;\n}\n\n/**\n * Name of the synthesised namespace bucket the framework parser uses for\n * top-level declarations that appear outside any `namespace { … }` block.\n * The double-underscore decoration signals that the identifier is parser-\n * synthesised and never appears in user-authored PSL source — writing\n * `namespace __unspecified__ { … }` is a parse error.\n *\n * Distinct from the IR sentinel `__unbound__`: the PSL bucket describes\n * syntactic absence at the parser layer; the IR sentinel describes a late-\n * bound storage slot at the IR layer. Per-target interpreters decide how\n * (or whether) to map the PSL bucket to the IR sentinel.\n */\nexport const UNSPECIFIED_PSL_NAMESPACE_ID = '__unspecified__';\n\n/** A value in {@link PslNamespace.entries}: a built-in entity node or an extension-contributed {@link PslExtensionBlock}. */\nexport type PslNamespaceEntry = PslModel | PslCompositeType | PslExtensionBlock;\n\n/**\n * A namespace block, or the parser's synthesised `__unspecified__` bucket for\n * declarations outside any `namespace { … }`. Same-name blocks reopen-merge;\n * `span` points at the first opening.\n *\n * Entities are stored canonically (ADR 224) in `entries[kind][name]`, where\n * `kind` is the PSL keyword for built-ins or the block discriminator for\n * extension kinds, e.g. `entries['policy']['ReadPosts']` (the discriminator,\n * not the PSL keyword — a `policy_select` block lands under `'policy'` per\n * ADR 225).\n */\nexport interface PslNamespace {\n readonly kind: 'namespace';\n readonly name: string;\n /** Canonical store: a frozen container of frozen per-kind maps. The accessors below derive from it. */\n readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>;\n /** Built-in models, from `entries['model']`. Extension kinds: {@link namespacePslExtensionBlocks}. */\n readonly models: readonly PslModel[];\n /** Built-in composite types, from `entries['compositeType']`. */\n readonly compositeTypes: readonly PslCompositeType[];\n readonly span: PslSpan;\n}\n\n/**\n * Stores `entries`; exposes `models`/`enums`/`compositeTypes` as getters over\n * it. The getters are prototype members (non-enumerable), so spreading or\n * `JSON.stringify`-ing a namespace copies only `entries`, never a duplicate view.\n */\nclass PslNamespaceNode implements PslNamespace {\n readonly kind = 'namespace' as const;\n readonly name: string;\n readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>;\n readonly span: PslSpan;\n\n constructor(init: {\n readonly name: string;\n readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>;\n readonly span: PslSpan;\n }) {\n this.name = init.name;\n this.entries = init.entries;\n this.span = init.span;\n Object.freeze(this);\n }\n\n get models(): readonly PslModel[] {\n return blindCast<readonly PslModel[], 'entries[model] holds only PslModel by construction'>(\n Object.values(this.entries['model'] ?? {}),\n );\n }\n\n get compositeTypes(): readonly PslCompositeType[] {\n return blindCast<\n readonly PslCompositeType[],\n 'entries[compositeType] holds only PslCompositeType by construction'\n >(Object.values(this.entries['compositeType'] ?? {}));\n }\n}\n\n/** Constructs a {@link PslNamespace}. Use this, never a namespace literal — the accessors must derive from `entries`. */\nexport function makePslNamespace(init: {\n readonly kind: 'namespace';\n readonly name: string;\n readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>;\n readonly span: PslSpan;\n}): PslNamespace {\n return new PslNamespaceNode(init);\n}\n\n/**\n * Builds the frozen `entries[kind][name]` container from per-kind arrays.\n * Built-ins key on their PSL keyword; extension blocks key on their `kind`\n * discriminator. Call this rather than hand-building the literal.\n */\nexport function makePslNamespaceEntries(\n models: readonly PslModel[],\n compositeTypes: readonly PslCompositeType[],\n extensionBlocks: readonly PslExtensionBlock[],\n): Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>> {\n const container: Record<string, Readonly<Record<string, PslNamespaceEntry>>> = {};\n\n if (models.length > 0) {\n const map: Record<string, PslModel> = {};\n for (const m of models) {\n map[m.name] = m;\n }\n container['model'] = Object.freeze(map);\n }\n\n if (compositeTypes.length > 0) {\n const map: Record<string, PslCompositeType> = {};\n for (const ct of compositeTypes) {\n map[ct.name] = ct;\n }\n container['compositeType'] = Object.freeze(map);\n }\n\n for (const block of extensionBlocks) {\n const existing = container[block.kind];\n const newMap: Record<string, PslExtensionBlock> = existing\n ? blindCast<Record<string, PslExtensionBlock>, 'kind map holds only PslExtensionBlock'>({\n ...existing,\n })\n : {};\n newMap[block.name] = block;\n container[block.kind] = Object.freeze(newMap);\n }\n\n return Object.freeze(container);\n}\n\nexport interface PslDocumentAst {\n readonly kind: 'document';\n readonly sourceId: string;\n readonly namespaces: readonly PslNamespace[];\n readonly types?: PslTypesBlock;\n readonly span: PslSpan;\n}\n\n/**\n * Returns all models from every namespace in document order. Convenience\n * for consumers that don't (yet) need namespace-awareness.\n */\nexport function flatPslModels(ast: PslDocumentAst): readonly PslModel[] {\n return ast.namespaces.flatMap((ns) =>\n blindCast<PslModel[], 'model kind map contains only PslModel by construction'>(\n Object.values(ns.entries['model'] ?? {}),\n ),\n );\n}\n\n/**\n * Returns all composite types from every namespace in document order.\n */\nexport function flatPslCompositeTypes(ast: PslDocumentAst): readonly PslCompositeType[] {\n return ast.namespaces.flatMap((ns) =>\n blindCast<\n PslCompositeType[],\n 'compositeType kind map contains only PslCompositeType by construction'\n >(Object.values(ns.entries['compositeType'] ?? {})),\n );\n}\n\n/**\n * The set of `entries` kind keys that the framework parser reserves for\n * built-in PSL entity kinds. Any own-enumerable key on `PslNamespace.entries`\n * that is **not** in this set was contributed by an extension-block descriptor.\n *\n * Built-in keys match the PSL keyword used on each block type:\n * `'model'`, `'compositeType'`. The `'enum'` keyword is claimed by the\n * extension-block grammar via a registered descriptor, so `entries['enum']`\n * holds `PslExtensionBlock` nodes and is returned by `namespacePslExtensionBlocks`.\n */\nexport const BUILTIN_PSL_KIND_KEYS: ReadonlySet<string> = new Set(['model', 'compositeType']);\n\n/**\n * Returns all extension-contributed blocks in the given namespace, in\n * insertion order (the order the parser encountered them in the source).\n *\n * Reads from `namespace.entries`, skipping the built-in kind keys\n * (`'model'`, `'compositeType'`). All remaining kind maps contain\n * only `PslExtensionBlock` nodes by construction (see `makePslNamespaceEntries`).\n */\nexport function namespacePslExtensionBlocks(ns: PslNamespace): readonly PslExtensionBlock[] {\n const result: PslExtensionBlock[] = [];\n for (const [kindKey, kindMap] of Object.entries(ns.entries)) {\n if (BUILTIN_PSL_KIND_KEYS.has(kindKey)) continue;\n for (const entry of Object.values(kindMap)) {\n result.push(\n blindCast<\n PslExtensionBlock,\n 'non-builtin kind maps contain only PslExtensionBlock by construction'\n >(entry),\n );\n }\n }\n return result;\n}\n\nexport interface ParsePslDocumentInput {\n readonly schema: string;\n readonly sourceId: string;\n /**\n * Registry of declarative block descriptors, keyed by arbitrary path\n * segments with {@link AuthoringPslBlockDescriptor} leaves. The registry\n * teaches the parser which top-level keywords belong to extension\n * contributions: when the parser encounters an unknown keyword, it looks\n * it up here and, when found, reads the block generically into a\n * {@link PslExtensionBlock} node. Absent or undefined means no extension\n * blocks are registered and any unknown keyword yields\n * `PSL_UNSUPPORTED_TOP_LEVEL_BLOCK`.\n *\n * Contrast with the parsed block nodes themselves, which live in\n * {@link PslNamespace.entries} under their discriminator key (read them with\n * {@link namespacePslExtensionBlocks}); this field holds the registry of\n * descriptors that teach the parser how to read those blocks.\n */\n readonly pslBlockDescriptors?: AuthoringPslBlockDescriptorNamespace;\n /**\n * Codec lookup for validating `value`-kind extension block parameters.\n * When provided alongside `pslBlockDescriptors`, the generic validator runs\n * over every parsed extension block after the full AST is assembled,\n * appending any diagnostics to the parse result. Absent or undefined means\n * no codec validation runs; `ref` resolution still runs when namespace\n * context is available (built from the assembled namespaces).\n */\n readonly codecLookup?: CodecLookup;\n}\n\nexport interface ParsePslDocumentResult {\n readonly ast: PslDocumentAst;\n readonly diagnostics: readonly PslDiagnostic[];\n readonly ok: boolean;\n}\n","/**\n * Generic validator for extension-contributed top-level PSL blocks.\n *\n * One function — {@link validateExtensionBlock} — takes a parsed\n * {@link PslExtensionBlock}, its {@link AuthoringPslBlockDescriptor}, a\n * {@link CodecLookup} (for `value` parameters), and the set of\n * {@link PslNamespace} objects from the document (for `ref` resolution), and\n * returns the full list of {@link PslDiagnostic} objects for the block.\n *\n * Detection logic per failure mode:\n *\n * 1. **Unknown parameter** — keys present in `node.parameters` that are absent\n * from `descriptor.parameters` (key-set difference). The parser stores\n * unknown parameters as `kind:'value'` stubs; the validator discovers them\n * by comparing the key sets, not by inspecting the captured kind.\n *\n * 2. **Missing required parameter** — `descriptor.parameters` entries with\n * `required: true` whose key is absent from `node.parameters`.\n *\n * 3. **`option` value outside its set** — the captured `token` is not in\n * `descriptor.values`.\n *\n * 4. **`value` rejected by its codec** — the raw string is first parsed as\n * JSON (`JSON.parse(raw)`). If `JSON.parse` throws, the literal is not valid\n * JSON and a `PSL_EXTENSION_INVALID_VALUE` diagnostic is emitted. If parsing\n * succeeds but `codec.decodeJson(jsonValue)` throws, the JSON value is not\n * acceptable to the codec and a `PSL_EXTENSION_INVALID_VALUE` diagnostic is\n * emitted. If `codecLookup.get(codecId)` returns `undefined` (unknown codec\n * id), a `PSL_EXTENSION_INVALID_VALUE` diagnostic is also emitted.\n *\n * 5. **`ref` that does not resolve within its scope** — the captured\n * `identifier` is looked up in the PSL document's `PslNamespace` objects\n * according to `param.scope`:\n * - `same-namespace`: the referent must be in the same namespace as the\n * block (the namespace containing the block).\n * - `same-space`: the referent may be in any namespace in the document.\n * - `cross-space`: pass-through — enforcement is scoped to first-consumer\n * need (RLS roles). This case is documented and clearly flagged; the\n * caller is responsible for wiring cross-space resolution when needed.\n *\n * 6. **`list`** — each element is validated against `param.of` recursively.\n *\n * ### `char`/`varchar` length\n * Not enforced. RLS `using`/`check` strings are unbounded text and the codec\n * already rejects structurally invalid literals; length constraints are a\n * database-side concern, not a PSL authoring constraint.\n *\n * ### `cross-space` scope\n * Implemented as a documented pass-through. The spec permits scoping\n * cross-space enforcement to first-consumer need (RLS roles). When RLS roles\n * arrive, wire `cross-space` resolution through the cross-contract-space\n * coordinate model `(spaceId, namespaceId, entityKind, entityName)`.\n */\n\nimport type { JsonValue } from '@prisma-next/contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { CodecLookup } from '../shared/codec-types';\nimport type { AuthoringPslBlockDescriptor } from '../shared/framework-authoring';\nimport type {\n PslBlockParam,\n PslBlockParamRef,\n PslExtensionBlock,\n PslExtensionBlockParamValue,\n PslSpan,\n} from '../shared/psl-extension-block';\nimport type { PslDiagnostic, PslNamespace } from './psl-ast';\n\n/**\n * Context for ref resolution during extension-block validation.\n *\n * - `ownerNamespace` is the `PslNamespace` that contains the block being\n * validated. Used for `same-namespace` scope checks.\n * - `allNamespaces` is every namespace in the document. Used for `same-space`\n * scope checks.\n */\nexport interface ExtensionBlockRefResolutionContext {\n readonly ownerNamespace: PslNamespace;\n readonly allNamespaces: readonly PslNamespace[];\n}\n\n/**\n * Validate a single parsed extension block against its descriptor.\n *\n * Returns an array of {@link PslDiagnostic} objects (possibly empty). The\n * caller is responsible for threading `sourceId` into each returned diagnostic\n * — the returned objects already have `sourceId` set from the `sourceId`\n * parameter.\n *\n * @param node - The parsed block node produced by the generic framework parser.\n * @param descriptor - The descriptor that claims this block's keyword.\n * @param sourceId - The PSL source file identifier (threaded into diagnostics).\n * @param codecLookup - Used to validate `value`-kind parameter literals via\n * `codecLookup.get(codecId)?.decodeJson(JSON.parse(raw))`.\n * @param refCtx - Namespace context for `ref`-kind scope resolution. Required\n * when any descriptor parameter is `kind: 'ref'`; may be omitted if none are.\n */\nexport function validateExtensionBlock(\n node: PslExtensionBlock,\n descriptor: AuthoringPslBlockDescriptor,\n sourceId: string,\n codecLookup: CodecLookup,\n refCtx?: ExtensionBlockRefResolutionContext,\n): readonly PslDiagnostic[] {\n const diagnostics: PslDiagnostic[] = [];\n\n const descriptorKeys = new Set(Object.keys(descriptor.parameters));\n const nodeKeys = new Set(Object.keys(node.parameters));\n\n // 1. Unknown parameters — keys in the node not in the descriptor.\n if (!descriptor.variadicParameters) {\n for (const key of nodeKeys) {\n if (!descriptorKeys.has(key)) {\n const captured = node.parameters[key];\n diagnostics.push({\n code: 'PSL_EXTENSION_UNKNOWN_PARAMETER',\n message: `Unknown parameter \"${key}\" in \"${descriptor.keyword}\" block \"${node.name}\". The descriptor does not declare this parameter.`,\n sourceId,\n span: captured?.span ?? node.span,\n });\n }\n }\n }\n\n // 2. Missing required parameters — required descriptor keys absent from the node.\n for (const [key, param] of Object.entries(descriptor.parameters)) {\n if (param.required === true && !nodeKeys.has(key)) {\n diagnostics.push({\n code: 'PSL_EXTENSION_MISSING_REQUIRED_PARAMETER',\n message: `Required parameter \"${key}\" is missing from \"${descriptor.keyword}\" block \"${node.name}\".`,\n sourceId,\n span: node.span,\n });\n }\n }\n\n // 3–5. Per-parameter validation for parameters that are present.\n for (const [key, param] of Object.entries(descriptor.parameters)) {\n const captured = node.parameters[key];\n if (captured === undefined) {\n continue;\n }\n validateParam(\n node,\n descriptor,\n key,\n param,\n captured,\n sourceId,\n codecLookup,\n refCtx,\n diagnostics,\n );\n }\n\n return diagnostics;\n}\n\nfunction validateParam(\n node: PslExtensionBlock,\n descriptor: AuthoringPslBlockDescriptor,\n key: string,\n param: PslBlockParam,\n captured: PslExtensionBlockParamValue,\n sourceId: string,\n codecLookup: CodecLookup,\n refCtx: ExtensionBlockRefResolutionContext | undefined,\n diagnostics: PslDiagnostic[],\n): void {\n switch (param.kind) {\n case 'option': {\n if (captured.kind !== 'option') {\n return;\n }\n if (!param.values.includes(captured.token)) {\n diagnostics.push({\n code: 'PSL_EXTENSION_OPTION_OUT_OF_SET',\n message: `Parameter \"${key}\" in \"${descriptor.keyword}\" block \"${node.name}\" has value \"${captured.token}\" which is not one of the allowed values: ${param.values.map((v) => `\"${v}\"`).join(', ')}.`,\n sourceId,\n span: captured.span,\n });\n }\n return;\n }\n\n case 'value': {\n if (captured.kind !== 'value') {\n return;\n }\n const codec = codecLookup.get(param.codecId);\n if (codec === undefined) {\n diagnostics.push({\n code: 'PSL_EXTENSION_INVALID_VALUE',\n message: `Parameter \"${key}\" in \"${descriptor.keyword}\" block \"${node.name}\" references unknown codec \"${param.codecId}\".`,\n sourceId,\n span: captured.span,\n });\n return;\n }\n let jsonValue: unknown;\n try {\n jsonValue = JSON.parse(captured.raw);\n } catch {\n diagnostics.push({\n code: 'PSL_EXTENSION_INVALID_VALUE',\n message: `Parameter \"${key}\" in \"${descriptor.keyword}\" block \"${node.name}\" is not a valid JSON literal (expected a JSON string, number, boolean, or null): ${captured.raw}`,\n sourceId,\n span: captured.span,\n });\n return;\n }\n try {\n codec.decodeJson(\n blindCast<JsonValue, 'JSON.parse returns a JsonValue-compatible value'>(jsonValue),\n );\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n diagnostics.push({\n code: 'PSL_EXTENSION_INVALID_VALUE',\n message: `Parameter \"${key}\" in \"${descriptor.keyword}\" block \"${node.name}\" was rejected by codec \"${param.codecId}\": ${reason}`,\n sourceId,\n span: captured.span,\n });\n }\n return;\n }\n\n case 'ref': {\n if (captured.kind !== 'ref') {\n return;\n }\n validateRef(\n node,\n descriptor,\n key,\n param,\n captured.identifier,\n captured.span,\n sourceId,\n refCtx,\n diagnostics,\n );\n return;\n }\n\n case 'list': {\n if (captured.kind !== 'list') {\n return;\n }\n for (const item of captured.items) {\n validateParam(\n node,\n descriptor,\n key,\n param.of,\n item,\n sourceId,\n codecLookup,\n refCtx,\n diagnostics,\n );\n }\n return;\n }\n }\n}\n\nfunction validateRef(\n node: PslExtensionBlock,\n descriptor: AuthoringPslBlockDescriptor,\n key: string,\n param: PslBlockParamRef,\n identifier: string,\n span: PslSpan,\n sourceId: string,\n refCtx: ExtensionBlockRefResolutionContext | undefined,\n diagnostics: PslDiagnostic[],\n): void {\n if (param.scope === 'cross-space') {\n // cross-space enforcement is a documented pass-through. The spec permits\n // scoping cross-space resolution to first-consumer need (RLS roles). When\n // that consumer arrives, wire resolution here through the\n // cross-contract-space coordinate model\n // (spaceId, namespaceId, entityKind, entityName).\n // For now, cross-space refs pass validation unconditionally.\n return;\n }\n\n if (refCtx === undefined) {\n // If no resolution context was provided, skip ref resolution. This matches\n // the closed-grammar invariant: callers that register ref parameters must\n // provide resolution context; callers without namespaces (e.g. unit tests\n // that only exercise other validation modes) can omit it.\n return;\n }\n\n const namespacesToSearch: readonly PslNamespace[] =\n param.scope === 'same-namespace' ? [refCtx.ownerNamespace] : refCtx.allNamespaces;\n\n if (!resolveEntityInNamespaces(identifier, param.refKind, namespacesToSearch)) {\n const scopeLabel =\n param.scope === 'same-namespace' ? 'the same namespace' : 'any namespace in the schema';\n diagnostics.push({\n code: 'PSL_EXTENSION_UNRESOLVED_REF',\n message: `Parameter \"${key}\" in \"${descriptor.keyword}\" block \"${node.name}\" refers to \"${identifier}\" (expected ${param.refKind}), but no entity with that name and kind was found in ${scopeLabel}.`,\n sourceId,\n span,\n });\n }\n}\n\n/**\n * True if an entity named `name` of kind `refKind` exists in any of the given\n * namespaces. Built-in and extension kinds resolve the same way, through\n * `entries[refKind]`.\n */\nfunction resolveEntityInNamespaces(\n name: string,\n refKind: string,\n namespaces: readonly PslNamespace[],\n): boolean {\n for (const ns of namespaces) {\n const kindMap = ns.entries[refKind];\n if (kindMap !== undefined && Object.hasOwn(kindMap, name)) return true;\n }\n return false;\n}\n"],"mappings":"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"} |
@@ -1,2 +0,2 @@ | ||
| import { t as CodecCallContext } from "./codec-types-yY3eSmi0.mjs"; | ||
| import { t as CodecCallContext } from "./codec-types-e32YHT3D.mjs"; | ||
| import { PlanMeta } from "@prisma-next/contract/types"; | ||
@@ -3,0 +3,0 @@ |
+10
-10
| { | ||
| "name": "@prisma-next/framework-components", | ||
| "version": "0.14.0", | ||
| "version": "0.15.0-dev.1", | ||
| "license": "Apache-2.0", | ||
@@ -9,15 +9,15 @@ "type": "module", | ||
| "dependencies": { | ||
| "@prisma-next/contract": "0.14.0", | ||
| "@prisma-next/operations": "0.14.0", | ||
| "@prisma-next/ts-render": "0.14.0", | ||
| "@prisma-next/utils": "0.14.0", | ||
| "@prisma-next/contract": "0.15.0-dev.1", | ||
| "@prisma-next/operations": "0.15.0-dev.1", | ||
| "@prisma-next/ts-render": "0.15.0-dev.1", | ||
| "@prisma-next/utils": "0.15.0-dev.1", | ||
| "@standard-schema/spec": "^1.1.0", | ||
| "arktype": "^2.2.0" | ||
| "arktype": "^2.2.2" | ||
| }, | ||
| "devDependencies": { | ||
| "@prisma-next/tsconfig": "0.14.0", | ||
| "@prisma-next/tsdown": "0.14.0", | ||
| "tsdown": "0.22.1", | ||
| "@prisma-next/tsconfig": "0.15.0-dev.1", | ||
| "@prisma-next/tsdown": "0.15.0-dev.1", | ||
| "tsdown": "0.22.3", | ||
| "typescript": "5.9.3", | ||
| "vitest": "4.1.8" | ||
| "vitest": "4.1.10" | ||
| }, | ||
@@ -24,0 +24,0 @@ "peerDependencies": { |
@@ -7,2 +7,3 @@ import type { ControlTargetDescriptor } from './control-descriptors'; | ||
| import type { PslDocumentAst } from './psl-ast'; | ||
| import type { SchemaDiffIssue } from './schema-diff'; | ||
@@ -73,1 +74,47 @@ export interface MigratableTargetDescriptor< | ||
| } | ||
| /** | ||
| * The granularity of a {@link SchemaDiffIssue}'s subject, resolved on demand | ||
| * from the issue's node `nodeKind` — never stamped on the issue or the node. | ||
| * | ||
| * - `namespace`: a whole namespace. | ||
| * - `entity`: a whole top-level entity (the thing a namespace contains). | ||
| * - `field`: a field of an entity. | ||
| * - `auxiliary`: a secondary part of an entity (an index, a default, a key). | ||
| * - `structural`: a cross-cutting object (an access policy, a tree root) that | ||
| * is the owning space's own concern, never a sibling's unclaimed entity — | ||
| * its extras fail verify in both modes. | ||
| */ | ||
| export type DiffSubjectGranularity = 'namespace' | 'entity' | 'field' | 'auxiliary' | 'structural'; | ||
| /** | ||
| * Capability declaring that a family can classify a {@link SchemaDiffIssue}'s | ||
| * subject granularity, and separately its storage `entityKind`, on demand — | ||
| * both resolved from its node's `nodeKind` through the family/target | ||
| * vocabulary it owns. Consumed by framework code that spans contract spaces | ||
| * (the migration aggregate's unclaimed-elements sweep) and cannot itself read | ||
| * family/target node vocabulary, so it asks this capability instead of | ||
| * hardcoding a family entity kind. `undefined` when the issue's node kind is | ||
| * unrecognized, or when the family injects no classifier at all — callers | ||
| * fall back to path shape in that case. | ||
| * | ||
| * `classifyEntityKind` returns the same per-family vocabulary as the contract | ||
| * storage's `entries` dictionary keys (the vocabulary | ||
| * {@link import('../ir/storage').elementCoordinates} walks) — never a | ||
| * granularity word, and never a word this framework layer names itself. | ||
| */ | ||
| export interface SchemaSubjectClassifierCapable { | ||
| classifySubjectGranularity(issue: SchemaDiffIssue): DiffSubjectGranularity | undefined; | ||
| classifyEntityKind(issue: SchemaDiffIssue): string | undefined; | ||
| } | ||
| export function hasSchemaSubjectClassifier<TFamilyId extends string, TSchemaIR>( | ||
| instance: ControlFamilyInstance<TFamilyId, TSchemaIR>, | ||
| ): instance is ControlFamilyInstance<TFamilyId, TSchemaIR> & SchemaSubjectClassifierCapable { | ||
| return ( | ||
| 'classifySubjectGranularity' in instance && | ||
| typeof (instance as Record<string, unknown>)['classifySubjectGranularity'] === 'function' && | ||
| 'classifyEntityKind' in instance && | ||
| typeof (instance as Record<string, unknown>)['classifyEntityKind'] === 'function' | ||
| ); | ||
| } |
@@ -17,2 +17,3 @@ import type { Contract } from '@prisma-next/contract/types'; | ||
| } from './control-instances'; | ||
| import type { ContractSpace } from './control-spaces'; | ||
| import type { ControlStack } from './control-stack'; | ||
@@ -89,3 +90,4 @@ import type { EmissionSpi } from './emission-types'; | ||
| > extends ExtensionDescriptor<TFamilyId, TTargetId> { | ||
| readonly contractSpace?: ContractSpace; | ||
| create(): TExtensionInstance; | ||
| } |
@@ -18,3 +18,3 @@ import type { | ||
| VerifyDatabaseSchemaResult, | ||
| } from './control-result-types'; | ||
| } from './control-operation-results'; | ||
@@ -42,10 +42,9 @@ export interface ControlFamilyInstance<TFamilyId extends string, TSchemaIR> | ||
| /** | ||
| * Verify a contract against an already-introspected schema slice. | ||
| * Verify a contract against an already-introspected schema. | ||
| * | ||
| * Callers that need to verify against the live database compose | ||
| * {@link introspect} + `verifySchema` directly; the family | ||
| * interface deliberately exposes the introspection step so callers | ||
| * can pre-project the schema (e.g. the aggregate verifier projects | ||
| * each member's claimed slice via | ||
| * {@link import('@prisma-next/migration-tools/aggregate').projectSchemaToSpace}). | ||
| * {@link introspect} + `verifySchema` directly. The aggregate verifier | ||
| * verifies each member against the full introspected schema and scopes the | ||
| * result to that member's contract space afterwards — it never prunes the | ||
| * schema up front. | ||
| * | ||
@@ -52,0 +51,0 @@ * Synchronous — no I/O. Idempotent. |
@@ -21,3 +21,3 @@ /** | ||
| } from './control-instances'; | ||
| import type { OperationContext } from './control-result-types'; | ||
| import type { OperationContext } from './control-operation-results'; | ||
@@ -365,2 +365,51 @@ // ============================================================================ | ||
| /** | ||
| * The canonical schema-IR entity coordinate: which namespace, which kind of | ||
| * entity, and which name. A bare entity name is not a unique identity — | ||
| * two namespaces can each declare an entity of the same name, and one | ||
| * namespace can declare two different-kind entities that share a name — so | ||
| * every schema-IR consumer that addresses one live or declared entity does | ||
| * it by this full triple. | ||
| * | ||
| * `entityKind` uses the same vocabulary as the contract storage's `entries` | ||
| * dictionary — the same vocabulary | ||
| * {@link import('../ir/storage').elementCoordinates} walks. This type has no | ||
| * `plane`: schema IR is storage-only (contract IR spans domain and storage, | ||
| * which is why its own coordinate type carries a plane), so a plane field | ||
| * here would always read `'storage'` and say nothing. | ||
| */ | ||
| export interface SchemaEntityCoordinate { | ||
| readonly namespaceId: string; | ||
| readonly entityKind: string; | ||
| readonly entityName: string; | ||
| } | ||
| /** | ||
| * Contract-space ownership query the planner consults while planning one | ||
| * space against a live database. | ||
| * | ||
| * A live schema node the planned space does not own surfaces from the diff | ||
| * as `not-expected` (an extra). Before treating such a node as this plan's | ||
| * to drop, the planner asks the ownership oracle whether *any* contract | ||
| * space in the composition declares it: a node another (sibling) space owns | ||
| * is not an orphan, so it is left untouched; a node no space owns is a | ||
| * genuine extra the planner may drop under a destructive policy. (A node the | ||
| * planned space itself owns is in its expected tree and never surfaces as an | ||
| * extra, so a positive answer always means a sibling.) | ||
| * | ||
| * The oracle is a real domain object — the passive | ||
| * {@link import('@prisma-next/migration-tools/aggregate').ContractSpaceAggregate}, | ||
| * which answers this from its loaded contract spaces. The planner holds no | ||
| * list of other spaces' names and no ownership rules of its own; it only | ||
| * asks. Single-space plans (offline `migration plan`) pass an aggregate of | ||
| * one — the same path, no special-casing. | ||
| */ | ||
| export interface SchemaOwnership { | ||
| /** | ||
| * True when some contract space in the composition declares a storage | ||
| * entity at this coordinate. | ||
| */ | ||
| declaresEntity(coordinate: SchemaEntityCoordinate): boolean; | ||
| } | ||
| /** | ||
| * Migration planner interface for planning schema changes. | ||
@@ -412,2 +461,12 @@ * This is the minimal interface that CLI commands use. | ||
| readonly spaceId: string; | ||
| /** | ||
| * Ownership oracle over the whole contract-space composition (the | ||
| * passive aggregate). The planner asks it, per live extra node, whether | ||
| * any space declares that entity: a sibling-owned node is left | ||
| * untouched, an unowned node is a genuine extra. The planner holds no | ||
| * list of other spaces' names — ownership lives in the aggregate; it | ||
| * only asks. Absent for a single-space plan handed no aggregate. | ||
| * See {@link SchemaOwnership}. | ||
| */ | ||
| readonly ownership?: SchemaOwnership; | ||
| }): MigrationPlannerResult; | ||
@@ -483,2 +542,3 @@ | ||
| readonly operationCount: number; | ||
| readonly destinationContractJson?: unknown; | ||
| }>; | ||
@@ -485,0 +545,0 @@ } |
@@ -58,2 +58,12 @@ import type { Contract } from '@prisma-next/contract/types'; | ||
| readonly ops: readonly MigrationPlanOperation[]; | ||
| /** | ||
| * Contract IR JSON of this migration's destination state, populated by | ||
| * the on-disk readers from the sibling `end-contract.json` file when | ||
| * present (raw parsed JSON). Absent for packages loaded without the | ||
| * snapshot file — the runner never requires it (see ADR 199: identity | ||
| * is anchored on the storage-hash bookends). The edge's *start* state | ||
| * is deliberately not carried: it is by construction the end state of | ||
| * the predecessor edge, so consumers derive it from the previous row. | ||
| */ | ||
| readonly endContractJson?: unknown; | ||
| } | ||
@@ -60,0 +70,0 @@ |
@@ -0,2 +1,5 @@ | ||
| import type { Contract, JsonValue } from '@prisma-next/contract/types'; | ||
| import { blindCast } from '@prisma-next/utils/casts'; | ||
| import type { CapabilityMatrix } from '../shared/capabilities'; | ||
| import { mergeCapabilityMatrices } from '../shared/capabilities'; | ||
| import type { Codec } from '../shared/codec'; | ||
@@ -9,2 +12,3 @@ import type { AnyCodecDescriptor } from '../shared/codec-descriptor'; | ||
| AuthoringFieldNamespace, | ||
| AuthoringModelAttributeDescriptorNamespace, | ||
| AuthoringPslBlockDescriptorNamespace, | ||
@@ -15,6 +19,2 @@ AuthoringTypeNamespace, | ||
| assertNoCrossRegistryCollisions, | ||
| isAuthoringEntityTypeDescriptor, | ||
| isAuthoringFieldPresetDescriptor, | ||
| isAuthoringPslBlockDescriptor, | ||
| isAuthoringTypeConstructorDescriptor, | ||
| mergeAuthoringNamespaces, | ||
@@ -47,2 +47,3 @@ } from '../shared/framework-authoring'; | ||
| readonly pslBlockDescriptors: AuthoringPslBlockDescriptorNamespace; | ||
| readonly modelAttributes: AuthoringModelAttributeDescriptorNamespace; | ||
| } | ||
@@ -60,2 +61,4 @@ | ||
| readonly extensionContracts: ReadonlyMap<string, Contract>; | ||
| readonly codecTypeImports: ReadonlyArray<TypesImportSpec>; | ||
@@ -68,2 +71,3 @@ readonly queryOperationTypeImports: ReadonlyArray<TypesImportSpec>; | ||
| readonly controlMutationDefaults: ControlMutationDefaults; | ||
| readonly capabilities: CapabilityMatrix; | ||
| } | ||
@@ -170,21 +174,10 @@ | ||
| const pslBlockDescriptors: Record<string, unknown> = {}; | ||
| const modelAttributes: Record<string, unknown> = {}; | ||
| for (const descriptor of descriptors) { | ||
| if (descriptor.authoring?.field) { | ||
| mergeAuthoringNamespaces( | ||
| field, | ||
| descriptor.authoring.field, | ||
| [], | ||
| isAuthoringFieldPresetDescriptor, | ||
| 'field', | ||
| ); | ||
| mergeAuthoringNamespaces(field, descriptor.authoring.field, [], 'fieldPreset', 'field'); | ||
| } | ||
| if (descriptor.authoring?.type) { | ||
| mergeAuthoringNamespaces( | ||
| type, | ||
| descriptor.authoring.type, | ||
| [], | ||
| isAuthoringTypeConstructorDescriptor, | ||
| 'type', | ||
| ); | ||
| mergeAuthoringNamespaces(type, descriptor.authoring.type, [], 'typeConstructor', 'type'); | ||
| } | ||
@@ -196,4 +189,4 @@ if (descriptor.authoring?.entityTypes) { | ||
| [], | ||
| isAuthoringEntityTypeDescriptor, | ||
| 'entity', | ||
| 'entity', | ||
| ); | ||
@@ -206,6 +199,15 @@ } | ||
| [], | ||
| isAuthoringPslBlockDescriptor, | ||
| 'pslBlock', | ||
| 'pslBlock', | ||
| ); | ||
| } | ||
| if (descriptor.authoring?.modelAttributes) { | ||
| mergeAuthoringNamespaces( | ||
| modelAttributes, | ||
| descriptor.authoring.modelAttributes, | ||
| [], | ||
| 'modelAttribute', | ||
| 'modelAttribute', | ||
| ); | ||
| } | ||
| } | ||
@@ -220,2 +222,6 @@ | ||
| >(pslBlockDescriptors); | ||
| const modelAttributeNamespace = blindCast< | ||
| AuthoringModelAttributeDescriptorNamespace, | ||
| 'merge target accumulator narrows to typed namespace post-merge' | ||
| >(modelAttributes); | ||
| assertNoCrossRegistryCollisions( | ||
@@ -226,2 +232,3 @@ typeNamespace, | ||
| pslBlockDescriptorNamespace, | ||
| modelAttributeNamespace, | ||
| ); | ||
@@ -234,2 +241,3 @@ | ||
| pslBlockDescriptors: pslBlockDescriptorNamespace, | ||
| modelAttributes: modelAttributeNamespace, | ||
| }; | ||
@@ -319,2 +327,6 @@ } | ||
| const metaById = new Map<string, CodecMeta>(); | ||
| const metaRenderersById = new Map< | ||
| string, | ||
| (params: Record<string, unknown> | JsonValue) => CodecMeta | undefined | ||
| >(); | ||
| const renderersById = new Map<string, (params: Record<string, unknown>) => string | undefined>(); | ||
@@ -325,2 +337,6 @@ const inputRenderersById = new Map< | ||
| >(); | ||
| const valueLiteralRenderersById = new Map< | ||
| string, | ||
| (value: JsonValue, side: 'output' | 'input') => string | undefined | ||
| >(); | ||
| const owners = new Map<string, string>(); | ||
@@ -330,3 +346,3 @@ for (const descriptor of descriptors) { | ||
| const descriptorId = descriptor.id; | ||
| // Descriptor-side metadata is the single source of truth for `targetTypes` / `meta` / `renderOutputType`. Every contributor ships a `codecDescriptors` list on `types.codecTypes`. | ||
| // Descriptor-side metadata is the single source of truth for `targetTypes` / `meta` / `renderOutputType`. A component contributes its codecs by listing `codecDescriptors` on `types.codecTypes`; each codecId has exactly one contributor across the stack. | ||
| for (const codecDescriptor of codecTypes?.codecDescriptors ?? []) { | ||
@@ -348,2 +364,5 @@ assertUniqueCodecOwner({ | ||
| } | ||
| if (typeof codecDescriptor.metaFor === 'function') { | ||
| metaRenderersById.set(codecDescriptor.codecId, codecDescriptor.metaFor); | ||
| } | ||
| if (typeof codecDescriptor.renderOutputType === 'function') { | ||
@@ -355,2 +374,5 @@ renderersById.set(codecDescriptor.codecId, codecDescriptor.renderOutputType); | ||
| } | ||
| if (typeof codecDescriptor.renderValueLiteral === 'function') { | ||
| valueLiteralRenderersById.set(codecDescriptor.codecId, codecDescriptor.renderValueLiteral); | ||
| } | ||
| // Materialize a representative `Codec` instance for `byId.get()` so consumers reading the lookup's instance side (e.g. SQL renderer's cast-policy lookup, or the contract emitter's literal-default `encodeJson` resolver) keep finding the codec. | ||
@@ -392,5 +414,13 @@ // | ||
| targetTypesFor: (id) => targetTypesById.get(id), | ||
| metaFor: (id) => metaById.get(id), | ||
| metaFor: (id, typeParams) => { | ||
| if (typeParams !== undefined) { | ||
| const paramsAware = metaRenderersById.get(id)?.(typeParams); | ||
| if (paramsAware !== undefined) return paramsAware; | ||
| } | ||
| return metaById.get(id); | ||
| }, | ||
| renderOutputTypeFor: (id, params) => renderersById.get(id)?.(params), | ||
| renderInputTypeFor: (id, params) => inputRenderersById.get(id)?.(params), | ||
| renderValueLiteralFor: (id, value, side) => valueLiteralRenderersById.get(id)?.(value, side), | ||
| descriptorFor: (id) => descriptorsById.get(id), | ||
| }; | ||
@@ -423,2 +453,15 @@ } | ||
| function assembleExtensionContracts( | ||
| extensions: ReadonlyArray< | ||
| Pick<ControlExtensionDescriptor<string, string>, 'id' | 'contractSpace'> | ||
| >, | ||
| ): ReadonlyMap<string, Contract> { | ||
| const result = new Map<string, Contract>(); | ||
| for (const ext of extensions) { | ||
| if (ext.contractSpace === undefined) continue; | ||
| result.set(ext.id, ext.contractSpace.contractJson); | ||
| } | ||
| return result; | ||
| } | ||
| function readDeclaredDependencyIds(descriptor: DependencyDeclaringDescriptor): readonly string[] { | ||
@@ -526,2 +569,3 @@ const packs = descriptor.contractSpace?.contractJson?.extensionPacks; | ||
| extensionPacks: orderedExtensionPacks, | ||
| extensionContracts: assembleExtensionContracts(orderedExtensionPacks), | ||
@@ -535,3 +579,8 @@ codecTypeImports: extractCodecTypeImports(allDescriptors), | ||
| controlMutationDefaults: assembleControlMutationDefaults(allDescriptors), | ||
| capabilities: mergeCapabilityMatrices({}, [ | ||
| target, | ||
| ...(adapter ? [adapter] : []), | ||
| ...orderedExtensionPacks, | ||
| ]), | ||
| }; | ||
| } |
@@ -1,2 +0,3 @@ | ||
| import type { Contract, ContractModelBase } from '@prisma-next/contract/types'; | ||
| import type { Contract, ContractModelBase, JsonValue } from '@prisma-next/contract/types'; | ||
| import type { CodecLookup } from '../shared/codec-types'; | ||
| import type { TypesImportSpec } from '../shared/types-import-spec'; | ||
@@ -28,17 +29,16 @@ | ||
| resolveFieldTypeParams?( | ||
| modelName: string, | ||
| fieldName: string, | ||
| model: ContractModelBase, | ||
| contract: Contract, | ||
| ): Record<string, unknown> | undefined; | ||
| /** | ||
| * Per-family resolver for typeParams that don't live inline on the | ||
| * framework-domain `ContractField`. Some families (notably SQL) let columns | ||
| * reference a named entry in `storage.types` via `typeRef`; the typeParams | ||
| * live on that named entry rather than on the domain field. The framework | ||
| * emit path consults this hook so the codec's `renderOutputType` can run | ||
| * for typeRef-shaped columns. | ||
| * | ||
| * Inline `field.type.typeParams` always takes precedence; the hook is only | ||
| * consulted when the domain field has no typeParams. Families without | ||
| * named storage types (e.g. mongo) don't implement this hook. | ||
| * | ||
| * Returns `undefined` when the field has no resolvable typeParams. | ||
| * Resolves a field's permitted values (codec-encoded) plus the codec that types them, or | ||
| * `undefined` for a field with no restricted value set. The framework renders the values into a TS | ||
| * literal union through the codec seam. Each family decides where the values live — a value set in | ||
| * its own storage plane, or another family-owned source. | ||
| */ | ||
| resolveFieldTypeParams?( | ||
| resolveFieldValueSet?( | ||
| modelName: string, | ||
@@ -48,3 +48,5 @@ fieldName: string, | ||
| contract: Contract, | ||
| ): Record<string, unknown> | undefined; | ||
| ): { readonly encodedValues: readonly JsonValue[]; readonly codecId: string } | undefined; | ||
| getStorageTypeExports?(contract: Contract, codecLookup?: CodecLookup): string | undefined; | ||
| } |
@@ -193,3 +193,5 @@ export type { AuthoringPslBlockDescriptorNamespace } from '../shared/framework-authoring'; | ||
| * `kind` is the PSL keyword for built-ins or the block discriminator for | ||
| * extension kinds, e.g. `entries['policy_select']['ReadPosts']`. | ||
| * extension kinds, e.g. `entries['policy']['ReadPosts']` (the discriminator, | ||
| * not the PSL keyword — a `policy_select` block lands under `'policy'` per | ||
| * ADR 225). | ||
| */ | ||
@@ -196,0 +198,0 @@ export interface PslNamespace { |
@@ -1,2 +0,2 @@ | ||
| import type { SchemaIssue } from './control-result-types'; | ||
| import type { SchemaDiffIssue } from './schema-diff'; | ||
@@ -11,4 +11,3 @@ /** | ||
| * per space, and wraps the per-target results into a unified | ||
| * `VerifyDatabaseSchemaResult` with timings, summary, and per-node | ||
| * verification tree. | ||
| * `VerifyDatabaseSchemaResult` with timings, summary, and the issue list. | ||
| * | ||
@@ -19,9 +18,2 @@ * Family-level abstract bases (e.g. `SqlSchemaVerifierBase`) carry the | ||
| * SqlSchemaVerifierBase`) own the dispatch on target-specific kinds. | ||
| * | ||
| * Target-specific issue kinds (RLS-policy-mismatch, namespace-mismatch, | ||
| * future function-shape-mismatch) are widened target-side; the framework | ||
| * `SchemaIssue` union (in `control-result-types.ts`) is intentionally not | ||
| * generic over target kinds in this project — see the spec's | ||
| * "Forward note: SchemaIssue layering" for the layering observation | ||
| * captured for a future project. | ||
| */ | ||
@@ -46,9 +38,8 @@ export interface SchemaVerifier<TContract, TSchema> { | ||
| * existing `VerifyDatabaseSchemaResult` envelope (with timings, summary, | ||
| * per-node verification tree); the SPI itself returns just the | ||
| * core ok/issues pair so the seam between target-walk and | ||
| * framework-aggregation is explicit. | ||
| * issue list); the SPI itself returns just the core ok/issues pair so the | ||
| * seam between target-walk and framework-aggregation is explicit. | ||
| */ | ||
| export interface SchemaVerifyResult { | ||
| readonly ok: boolean; | ||
| readonly issues: readonly SchemaIssue[]; | ||
| readonly issues: readonly SchemaDiffIssue[]; | ||
| } |
| import type { ControlPolicy } from '@prisma-next/contract/types'; | ||
| import type { SchemaVerificationNode } from './control-result-types'; | ||
| export type VerificationStatus = SchemaVerificationNode['status']; | ||
| export type VerificationStatus = 'pass' | 'warn' | 'fail'; | ||
@@ -6,0 +5,0 @@ export type VerifierOutcome = VerificationStatus | 'suppress'; |
@@ -15,2 +15,6 @@ export type { | ||
| AuthoringFieldPresetOutput, | ||
| AuthoringModelAttributeContext, | ||
| AuthoringModelAttributeDescriptor, | ||
| AuthoringModelAttributeDescriptorNamespace, | ||
| AuthoringModelAttributeLoweringOutput, | ||
| AuthoringPslBlockDescriptor, | ||
@@ -21,2 +25,3 @@ AuthoringPslBlockDescriptorNamespace, | ||
| AuthoringTypeConstructorDescriptor, | ||
| AuthoringTypeConstructorEntityRef, | ||
| AuthoringTypeNamespace, | ||
@@ -26,2 +31,3 @@ } from '../shared/framework-authoring'; | ||
| assertNoCrossRegistryCollisions, | ||
| classifyEnumMemberType, | ||
| hasRegisteredFieldNamespace, | ||
@@ -34,2 +40,3 @@ instantiateAuthoringEntityType, | ||
| isAuthoringFieldPresetDescriptor, | ||
| isAuthoringModelAttributeDescriptor, | ||
| isAuthoringPslBlockDescriptor, | ||
@@ -39,2 +46,3 @@ isAuthoringTypeConstructorDescriptor, | ||
| resolveAuthoringTemplateValue, | ||
| resolveEnumCodecId, | ||
| validateAuthoringHelperArguments, | ||
@@ -41,0 +49,0 @@ } from '../shared/framework-authoring'; |
@@ -30,2 +30,3 @@ /** | ||
| export { column } from '../shared/column-spec'; | ||
| export { renderTsLiteral } from '../shared/render-ts-literal'; | ||
| export { | ||
@@ -32,0 +33,0 @@ CONTRACT_CODEC_DESCRIPTOR_MISSING, |
@@ -0,1 +1,2 @@ | ||
| export type { CapabilityMatrix } from '../shared/capabilities'; | ||
| export { mergeCapabilityMatrices } from '../shared/capabilities'; | ||
@@ -2,0 +3,0 @@ export type { |
+11
-10
| export type { ImportRequirement } from '@prisma-next/ts-render'; | ||
| export type { ContractSerializer } from '../control/contract-serializer'; | ||
| export type { | ||
| DiffSubjectGranularity, | ||
| MigratableTargetDescriptor, | ||
| OperationPreviewCapable, | ||
| PslContractInferCapable, | ||
| SchemaSubjectClassifierCapable, | ||
| SchemaViewCapable, | ||
@@ -13,2 +15,3 @@ } from '../control/control-capabilities'; | ||
| hasPslContractInfer, | ||
| hasSchemaSubjectClassifier, | ||
| hasSchemaView, | ||
@@ -51,2 +54,4 @@ } from '../control/control-capabilities'; | ||
| OpFactoryCall, | ||
| SchemaEntityCoordinate, | ||
| SchemaOwnership, | ||
| TargetMigrationsCapability, | ||
@@ -59,13 +64,10 @@ } from '../control/control-migration-types'; | ||
| export type { | ||
| BaseSchemaIssue, | ||
| EmitContractResult, | ||
| EnumValuesChangedIssue, | ||
| ExpectationFailureReason, | ||
| IntrospectSchemaResult, | ||
| OperationContext, | ||
| SchemaIssue, | ||
| SchemaVerificationNode, | ||
| SignDatabaseResult, | ||
| VerifyDatabaseResult, | ||
| VerifyDatabaseSchemaResult, | ||
| } from '../control/control-result-types'; | ||
| } from '../control/control-operation-results'; | ||
| export { | ||
@@ -76,3 +78,3 @@ VERIFY_CODE_HASH_MISMATCH, | ||
| VERIFY_CODE_TARGET_MISMATCH, | ||
| } from '../control/control-result-types'; | ||
| } from '../control/control-operation-results'; | ||
| export type { | ||
@@ -108,2 +110,4 @@ CoreSchemaView, | ||
| } from '../control/control-stack'; | ||
| export type { DiffableNode, SchemaDiffIssue } from '../control/schema-diff'; | ||
| export { diffSchemas, SchemaDiff } from '../control/schema-diff'; | ||
| export type { | ||
@@ -125,11 +129,8 @@ SchemaVerifier, | ||
| DefaultFunctionLoweringContext, | ||
| DefaultFunctionLoweringHandler, | ||
| DefaultFunctionRegistry, | ||
| DefaultFunctionRegistryEntry, | ||
| LoweredDefaultResult, | ||
| LoweredDefaultValue, | ||
| MutationDefaultGeneratorDescriptor, | ||
| ParsedDefaultFunctionCall, | ||
| SourceDiagnostic, | ||
| SourceSpan, | ||
| TypedDefaultFunctionCall, | ||
| } from '../shared/mutation-default-types'; |
+11
-1
@@ -0,1 +1,11 @@ | ||
| export type { | ||
| DefaultNamespaceEntries, | ||
| NamespacedEntities, | ||
| SingleNamespaceView, | ||
| } from '../ir/contract-view'; | ||
| export { | ||
| buildNamespacedEntities, | ||
| buildSingleNamespaceView, | ||
| promoteBuiltinKinds, | ||
| } from '../ir/contract-view'; | ||
| export { domainElementCoordinates } from '../ir/domain'; | ||
@@ -9,3 +19,3 @@ export type { AnyEntityKindDescriptor, EntityKindDescriptor } from '../ir/entity-kind'; | ||
| export type { EntityCoordinate, Storage } from '../ir/storage'; | ||
| export { elementCoordinates, entityAt, isPlainRecord } from '../ir/storage'; | ||
| export { coordinateKey, elementCoordinates, entityAt, isPlainRecord } from '../ir/storage'; | ||
| export type { StorageType } from '../ir/storage-type'; |
+16
-0
@@ -64,2 +64,9 @@ import type { StorageNamespace } from '@prisma-next/contract/types'; | ||
| readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>; | ||
| /** | ||
| * Whether this namespace is the late-bound unbound slot (see | ||
| * {@link UNBOUND_NAMESPACE_ID}). Optional so JSON-shaped structural | ||
| * satisfiers remain valid; every hydrated `NamespaceBase` concretion | ||
| * answers it. | ||
| */ | ||
| readonly isUnbound?: boolean; | ||
| } | ||
@@ -71,2 +78,11 @@ | ||
| abstract override readonly kind: string; | ||
| /** | ||
| * Answers "am I the unbound namespace" as node behavior, so consumers | ||
| * never compare ids against the sentinel. This getter is the single | ||
| * encapsulated place the {@link UNBOUND_NAMESPACE_ID} comparison lives. | ||
| */ | ||
| get isUnbound(): boolean { | ||
| return this.id === UNBOUND_NAMESPACE_ID; | ||
| } | ||
| } |
+21
-0
@@ -59,2 +59,23 @@ import { isPlainRecord } from '@prisma-next/contract/is-plain-record'; | ||
| /** | ||
| * Canonical, collision-safe key for an {@link EntityCoordinate}. Encodes each | ||
| * axis individually with `JSON.stringify` before joining with `-`, so no | ||
| * namespace id, entity kind, or entity name can forge a collision by | ||
| * embedding the delimiter itself (e.g. a delimiter of `:` would let | ||
| * `('a', 'b:c', 'd')` collide with `('a:b', 'c', 'd')`) — each component is | ||
| * quoted, and any `-` or `"` inside it is escaped or safely inside those | ||
| * quotes. | ||
| * | ||
| * The single shared key every coordinate-driven ownership/omission/collision | ||
| * check should use — `contract infer`'s pack-described-element omission and | ||
| * the migration tools' cross-space disjointness check both key on this. | ||
| */ | ||
| export function coordinateKey( | ||
| coordinate: Pick<EntityCoordinate, 'namespaceId' | 'entityKind' | 'entityName'>, | ||
| ): string { | ||
| return [coordinate.namespaceId, coordinate.entityKind, coordinate.entityName] | ||
| .map((value) => JSON.stringify(value)) | ||
| .join('-'); | ||
| } | ||
| /** | ||
| * Looks up a single entity in a `Storage`-shaped value by its full coordinate. | ||
@@ -61,0 +82,0 @@ * Returns `undefined` if the namespace, entity kind, or entity name is absent. |
@@ -12,3 +12,3 @@ /** | ||
| type CapabilityMatrix = Record<string, Record<string, boolean>>; | ||
| export type CapabilityMatrix = Record<string, Record<string, boolean>>; | ||
@@ -15,0 +15,0 @@ function isPlainObject(value: unknown): value is Record<string, unknown> { |
@@ -11,2 +11,3 @@ /** | ||
| import type { JsonValue } from '@prisma-next/contract/types'; | ||
| import type { StandardSchemaV1 } from '@standard-schema/spec'; | ||
@@ -45,2 +46,4 @@ import type { Codec } from './codec'; | ||
| readonly isParameterized: boolean; | ||
| /** Optional params-aware metadata renderer. Computes this codec instance's `CodecMeta` from its `typeParams` (e.g. a per-instance identifier derived from an enum's declared member set). Optional; absent renderers cause `CodecLookup.metaFor` to fall back to the codec's static `meta`. Non-parameterized codecs typically omit it. */ | ||
| readonly metaFor?: (params: P) => CodecMeta | undefined; | ||
| /** Emit-path string renderer for `contract.d.ts`. Returns the TypeScript output type expression for given params (e.g. `Vector<1536>`). Optional; absent renderers cause the emitter to fall back to the codec's base output type. Non-parameterized codecs typically omit it. */ | ||
@@ -50,2 +53,13 @@ readonly renderOutputType?: (params: P) => string | undefined; | ||
| readonly renderInputType?: (params: P) => string | undefined; | ||
| /** | ||
| * Given one stored (codec-encoded) value, return the TypeScript literal type to print for it | ||
| * (e.g. `'low'`, `1`), or `undefined` if this codec's output isn't literal-expressible (e.g. a | ||
| * Date-output codec). | ||
| * | ||
| * `value` is the `encodeJson` form stored in the value set. `side` selects which type to print: | ||
| * `output` = the read/SELECT type; `input` = the create/update type. Most codecs render the same | ||
| * literal for both, but a codec whose read and write types differ can render per side. Called once | ||
| * per permitted value; the caller joins the results with `|`. | ||
| */ | ||
| readonly renderValueLiteral?: (value: JsonValue, side: 'output' | 'input') => string | undefined; | ||
| /** The curried higher-order codec. For non-parameterized codecs, the factory is constant — every call returns the same shared codec instance. For parameterized codecs, the factory is called once per `storage.types` instance (or once per inline-`typeParams` column), with `ctx` carrying the column set the resulting codec serves. */ | ||
@@ -83,2 +97,5 @@ readonly factory: (params: P) => (ctx: CodecInstanceContext) => Codec; | ||
| /** Optional params-aware metadata renderer. Computes this codec instance's `CodecMeta` from its `typeParams` (e.g. a per-instance identifier derived from an enum's declared member set). Non-parameterized codecs typically omit it. */ | ||
| metaFor?(params: TParams): CodecMeta | undefined; | ||
| /** Optional emit-path string renderer for `contract.d.ts`. Returns the TypeScript output type expression for the given params (e.g. `Vector<1536>`). Non-parameterized codecs typically omit it. */ | ||
@@ -90,2 +107,5 @@ renderOutputType?(params: TParams): string | undefined; | ||
| /** Optional emit-path renderer for a single stored value. See {@link CodecDescriptor.renderValueLiteral}. */ | ||
| renderValueLiteral?(value: JsonValue, side: 'output' | 'input'): string | undefined; | ||
| /** | ||
@@ -92,0 +112,0 @@ * Materialize a curried codec factory for the given params. Concrete subclasses override with a typed return type (e.g. `factory<N>(params: { length: N }): (ctx) => VectorCodec<N>`); per-codec helpers read the typed return at the *direct* call site, which is what preserves method-level generics. Type extraction (e.g. `ReturnType<D['factory']>`) widens method generics to their constraint — that's why the column-helper surface is per-codec, not polymorphic. |
| import type { JsonValue } from '@prisma-next/contract/types'; | ||
| import type { StandardSchemaV1 } from '@standard-schema/spec'; | ||
| import type { Codec } from './codec'; | ||
| import type { AnyCodecDescriptor } from './codec-descriptor'; | ||
@@ -14,2 +15,4 @@ export type CodecTrait = 'equality' | 'order' | 'boolean' | 'numeric' | 'textual'; | ||
| * | ||
| * `many` marks a scalar-array (list-typed) column. When `true`, the encode/decode paths map the element codec over the JS array rather than applying the codec to the whole value. The element codec id is `codecId`; the driver owns the array wire framing (`{…}`) in both directions. Absent for scalar columns. | ||
| * | ||
| * Family-agnostic by design — both SQL and Mongo AST nodes carry `codec: CodecRef | undefined`, and the resolver is the only dispatch path that survives serialization. | ||
@@ -20,2 +23,3 @@ */ | ||
| readonly typeParams?: JsonValue; | ||
| readonly many?: boolean; | ||
| } | ||
@@ -43,3 +47,3 @@ | ||
| * - `targetTypesFor(id)` exposes the codec-id-keyed `targetTypes` metadata the runtime instance no longer carries (TML-2357). Returns the same array `CodecDescriptor.targetTypes` would; for Mongo (whose registration doesn't yet resolve through the unified descriptor map — TML-2324) the family-side assembly populates this directly from the contributor's codec metadata. | ||
| * - `metaFor(id)` exposes the codec-id-keyed `meta` (e.g. SQL-side `db.sql.postgres.nativeType`) the runtime instance no longer carries. | ||
| * - `metaFor(id, typeParams)` exposes the codec-id-keyed `meta` (e.g. SQL-side `db.sql.postgres.nativeType`) the runtime instance no longer carries. `typeParams` is optional: when given and the codec descriptor implements a params-aware `metaFor`, the descriptor computes its meta from those params (e.g. a native enum's per-instance Postgres type name); otherwise (or when `typeParams` is omitted) the codec's static `meta` is returned. | ||
| * - `renderOutputTypeFor(id, params)` exposes the codec-id-keyed `renderOutputType` renderer the runtime instance no longer carries. Returns `undefined` when the codec doesn't render a custom type or when the codec id is unknown. | ||
@@ -50,6 +54,22 @@ */ | ||
| targetTypesFor(id: string): readonly string[] | undefined; | ||
| metaFor(id: string): CodecMeta | undefined; | ||
| metaFor(id: string, typeParams?: Record<string, unknown> | JsonValue): CodecMeta | undefined; | ||
| renderOutputTypeFor(id: string, params: Record<string, unknown>): string | undefined; | ||
| /** Codec-id-keyed `renderInputType` renderer for the `contract.d.ts` input position. Optional so existing lookups need not provide it; returns `undefined` when the codec renders no custom input type or the id is unknown. */ | ||
| renderInputTypeFor?(id: string, params: Record<string, unknown>): string | undefined; | ||
| /** Codec-id-keyed `renderValueLiteral` renderer for the emit path (`side`: `output` = read type, `input` = create/update type). Optional so existing lookups need not provide it; returns `undefined` when the codec's output isn't literal-expressible or the id is unknown. */ | ||
| renderValueLiteralFor?( | ||
| id: string, | ||
| value: JsonValue, | ||
| side: 'output' | 'input', | ||
| ): string | undefined; | ||
| /** | ||
| * Codec-id-keyed descriptor accessor. Returns the full registered | ||
| * {@link AnyCodecDescriptor} for `id`, or `undefined` if no descriptor is | ||
| * registered. Optional so existing lookups need not provide it; a consumer | ||
| * that needs more than the derived per-id readers above — e.g. an | ||
| * authoring-time hook a target-specific descriptor exposes but this | ||
| * framework interface does not model generically — fetches the descriptor | ||
| * itself and narrows it with its own structural predicate. | ||
| */ | ||
| descriptorFor?(id: string): AnyCodecDescriptor | undefined; | ||
| } | ||
@@ -56,0 +76,0 @@ |
@@ -16,5 +16,5 @@ /** | ||
| /** | ||
| * A codec is the contract between an application value and its on-wire and on-contract-disk representations. | ||
| * A codec is the contract between an application value and its driver-wire and JSON representations. | ||
| * | ||
| * The author's mental model is two JS-side types — `TInput` (the application JS type) and `TWire` (the database driver wire format) — plus `JsonValue` for build-time contract artifacts. The codec translates `TInput` to `TWire` on writes and back on reads, and to/from `JsonValue` during contract emission and loading. | ||
| * The author's mental model is two JS-side types — `TInput` (the application JS type) and `TWire` (the database driver wire format) — plus a target-defined `JsonValue`. The codec translates `TInput` to `TWire` on writes and back on ordinary reads, and to/from the target's JSON representation for contract artifacts and database-produced JSON values. | ||
| * | ||
@@ -24,3 +24,3 @@ * Three representations participate: | ||
| * - **Wire** (`TWire`): the format exchanged with the database driver. | ||
| * - **JSON** (`JsonValue`): a JSON-safe form used in contract artifacts. | ||
| * - **JSON** (`JsonValue`): the target-defined JSON-safe form used in contract artifacts. It uses the exact scalar shape the target produces inside JSON values, which can differ from the ordinary wire format. | ||
| * | ||
@@ -32,3 +32,3 @@ * The runtime instance carries only its `id` (the descriptor's `codecId`, set by the factory) and the four conversion methods. Static metadata (`traits`, `targetTypes`, `meta`) and the build-time `renderOutputType` renderer live on the {@link CodecDescriptor} keyed by `codecId` — the read-surface single source of truth. Consumers that need them resolve through `descriptorFor(codecId)`. | ||
| * - **Query-time** methods (`encode`, `decode`) run per row/parameter at the IO boundary; they are required and Promise-returning. The per-family codec factory accepts sync or async author functions and lifts sync ones to Promise-shaped methods automatically. | ||
| * - **Build-time** methods (`encodeJson`, `decodeJson`) run when the contract is serialized or loaded. They stay synchronous so contract validation and client construction are synchronous. | ||
| * - **JSON** methods (`encodeJson`, `decodeJson`) run when the contract is serialized or loaded. Runtimes may also use `decodeJson` for values embedded in database-produced JSON results. They stay synchronous so contract validation and client construction are synchronous. | ||
| * | ||
@@ -51,5 +51,5 @@ * Target-family codec interfaces extend this base; family-specific concerns (e.g. the SQL `column?` per-call context) layer on through the `CodecCallContext` extension pattern. | ||
| decode(wire: TWire, ctx: CodecCallContext): Promise<TInput>; | ||
| /** Converts a JS value to a JSON-safe representation for contract serialization. Synchronous; called during contract emission. */ | ||
| /** Converts a JS value to the target-defined JSON representation used for contract serialization. This must match the scalar shape produced by the target inside JSON values. Synchronous; called during contract emission. */ | ||
| encodeJson(value: TInput): JsonValue; | ||
| /** Converts a JSON representation back to the JS input type. Synchronous; called during contract loading via `family.deserializeContract`. */ | ||
| /** Converts the target-defined JSON representation back to the JS input type. Synchronous; called during contract loading via `family.deserializeContract` and may be called by runtimes for embedded JSON values. */ | ||
| decodeJson(json: JsonValue): TInput; | ||
@@ -61,3 +61,3 @@ } | ||
| * | ||
| * Codec authors extend this class with their typed `Id`, `TTraits`, `TWire`, `TInput` and override `encode`/`decode` (and optionally `encodeJson`/`decodeJson`). The runtime instance carries only its `id` (proxied through the descriptor so alias subclasses inherit the descriptor's id automatically) and the conversion methods — static metadata lives on the {@link CodecDescriptor}. | ||
| * Codec authors extend this class with their typed `Id`, `TTraits`, `TWire`, `TInput` and override all four abstract conversion methods: `encode`, `decode`, `encodeJson`, and `decodeJson`. The runtime instance carries only its `id` (proxied through the descriptor so alias subclasses inherit the descriptor's id automatically) and the conversion methods — static metadata lives on the {@link CodecDescriptor}. | ||
| */ | ||
@@ -64,0 +64,0 @@ export abstract class CodecImpl< |
@@ -9,2 +9,3 @@ /** | ||
| import type { ValueSetRef } from '@prisma-next/contract/types'; | ||
| import type { CodecDescriptor } from './codec-descriptor'; | ||
@@ -25,5 +26,28 @@ import type { CodecInstanceContext } from './codec-types'; | ||
| readonly typeRef?: string; | ||
| /** | ||
| * Storage-plane value-set ref, set by an authoring path that resolves a | ||
| * field's type against a value-set-deriving entity (e.g. a PSL entity-ref | ||
| * type constructor like `pg.enum(Ref)`, or a TS `enumType` handle). | ||
| * Threaded straight onto the storage node this descriptor builds, where it | ||
| * drives value-set → codec typing. Every codec's own descriptor leaves this | ||
| * unset. | ||
| */ | ||
| readonly valueSet?: ValueSetRef; | ||
| readonly entityRef?: EntityRef; | ||
| }; | ||
| /** | ||
| * Late-resolved pack-entity reference — a field on the type descriptor it is | ||
| * declared on: `entityKind`/`entityName` identify a pack entity whose final | ||
| * placement depends on data not yet known when the descriptor carrying this | ||
| * reference is built — e.g. an owning namespace resolved only once the | ||
| * surrounding structure is assembled. | ||
| */ | ||
| export type EntityRef = { | ||
| readonly entityKind: string; | ||
| readonly entityName: string; | ||
| readonly entity: unknown; | ||
| }; | ||
| /** | ||
| * Column spec carrying the codec factory closure alongside the {@link ColumnTypeDescriptor} fields. Codec authors return a `ColumnSpec` from per-codec column helpers; the runtime materializes the codec instance by calling `codecFactory(ctx)` once it knows the column's `CodecInstanceContext`. | ||
@@ -30,0 +54,0 @@ * |
@@ -14,4 +14,7 @@ import type { | ||
| import type { CodecLookup } from './codec-types'; | ||
| import type { PslBlockParam } from './psl-extension-block'; | ||
| import type { PslBlockParam, PslExtensionBlock, PslSpan } from './psl-extension-block'; | ||
| import { runtimeError } from './runtime-error'; | ||
| export type EnumInferredMemberType = 'text' | 'int'; | ||
| export type AuthoringArgRef = { | ||
@@ -57,6 +60,35 @@ readonly kind: 'arg'; | ||
| readonly codecId: string; | ||
| readonly nativeType: AuthoringTemplateValue; | ||
| /** | ||
| * Optional so a type constructor whose {@link AuthoringTypeConstructorDescriptor.entityRefArg} | ||
| * names another entity can omit this template entirely — its output for | ||
| * that case is derived by the codec at `codecId`, not by resolving a | ||
| * literal here. Every other consumer of this shape (field presets, plain | ||
| * type constructors) always supplies it. | ||
| */ | ||
| readonly nativeType?: AuthoringTemplateValue; | ||
| readonly typeParams?: Record<string, AuthoringTemplateValue>; | ||
| } | ||
| /** | ||
| * Declares that one positional argument of a | ||
| * {@link AuthoringTypeConstructorDescriptor} call names another entity | ||
| * parsed from the same document, rather than carrying a literal value (e.g. | ||
| * `pg.enum(AalLevel)` naming a `native_enum` entity). `index` is the | ||
| * argument's position in the call; `entityKind` is the entries-slot | ||
| * discriminator the interpreter looks the named entity up under (the same | ||
| * shape {@link AuthoringEntityTypeFactoryOutput.factory} output is collected | ||
| * into, keyed by discriminator then block name). | ||
| * | ||
| * The interpreter resolves the named argument to the entity instance | ||
| * generically, driven only by this declaration — it has no target-specific | ||
| * knowledge of which type constructors carry one. Converting the resolved | ||
| * entity into the constructor's params is a separate, codec-owned concern: | ||
| * the codec descriptor registered for `output.codecId` supplies that | ||
| * conversion, not this framework type. | ||
| */ | ||
| export interface AuthoringTypeConstructorEntityRef { | ||
| readonly index: number; | ||
| readonly entityKind: string; | ||
| } | ||
| export interface AuthoringTypeConstructorDescriptor { | ||
@@ -66,2 +98,4 @@ readonly kind: 'typeConstructor'; | ||
| readonly output: AuthoringStorageTypeTemplate; | ||
| /** Present when one of this constructor's positional arguments names another document-local entity instead of carrying a literal value. Absent for ordinary literal-argument constructors. */ | ||
| readonly entityRefArg?: AuthoringTypeConstructorEntityRef; | ||
| } | ||
@@ -140,4 +174,100 @@ | ||
| readonly diagnostics?: AuthoringDiagnosticSink; | ||
| /** | ||
| * The target's default codec ids for an `enum` block that omits `@@type`. | ||
| * `text` is used when every member is a bare name or a string value; | ||
| * `int` is used when every member is an integer value. Every target pack | ||
| * populates this so `@@type` omission can be inferred consistently. | ||
| */ | ||
| readonly enumInferenceCodecs?: { readonly text: string; readonly int: string }; | ||
| } | ||
| /** | ||
| * Classifies an `enum` block's members (before codec decoding, which needs | ||
| * the codec chosen first) into which default codec an omitted `@@type` | ||
| * should resolve to: | ||
| * | ||
| * - every member is `bare`, or a `value` whose raw JSON is a string → `'text'` | ||
| * - every member is a `value` whose raw JSON is an integer → `'int'` | ||
| * - anything else (float, bigint, boolean, mixed, or a `ref`/`option`/`list` | ||
| * parameter) → `null`, meaning the caller must require an explicit `@@type`. | ||
| */ | ||
| export function classifyEnumMemberType(block: PslExtensionBlock): 'text' | 'int' | null { | ||
| let sawText = false; | ||
| let sawInt = false; | ||
| for (const paramValue of Object.values(block.parameters)) { | ||
| if (paramValue.kind === 'bare') { | ||
| sawText = true; | ||
| continue; | ||
| } | ||
| if (paramValue.kind !== 'value') { | ||
| return null; | ||
| } | ||
| let jsonValue: unknown; | ||
| try { | ||
| jsonValue = JSON.parse(paramValue.raw); | ||
| } catch { | ||
| return null; | ||
| } | ||
| if (typeof jsonValue === 'string') { | ||
| sawText = true; | ||
| } else if (typeof jsonValue === 'number' && Number.isInteger(jsonValue)) { | ||
| sawInt = true; | ||
| } else { | ||
| return null; | ||
| } | ||
| } | ||
| if (sawText && sawInt) return null; | ||
| if (sawText) return 'text'; | ||
| if (sawInt) return 'int'; | ||
| return null; | ||
| } | ||
| /** | ||
| * Resolves the codec id for an `enum` block. When `@@type` is absent, the codec | ||
| * is inferred from the members via {@link classifyEnumMemberType}; otherwise the | ||
| * explicit `@@type("codec")` argument is parsed. Pushes the appropriate | ||
| * diagnostic and returns `undefined` when neither yields a codec. `codecSpan` is | ||
| * the span downstream codec-validation diagnostics should anchor to. Shared by | ||
| * every family's enum factory so inference and the explicit path stay identical. | ||
| */ | ||
| export function resolveEnumCodecId( | ||
| block: PslExtensionBlock, | ||
| ctx: AuthoringEntityContext, | ||
| ): { readonly codecId: string; readonly codecSpan: PslSpan } | undefined { | ||
| const sourceId = ctx.sourceId ?? 'unknown'; | ||
| const typeAttr = block.blockAttributes.find((a) => a.name === 'type'); | ||
| if (typeAttr === undefined) { | ||
| const inferredKind = classifyEnumMemberType(block); | ||
| if (inferredKind === null || ctx.enumInferenceCodecs === undefined) { | ||
| ctx.diagnostics?.push({ | ||
| code: 'PSL_ENUM_CANNOT_INFER_TYPE', | ||
| message: `cannot infer @@type for enum "${block.name}"; add an explicit @@type(...)`, | ||
| sourceId, | ||
| span: block.span, | ||
| }); | ||
| return undefined; | ||
| } | ||
| return { codecId: ctx.enumInferenceCodecs[inferredKind], codecSpan: block.span }; | ||
| } | ||
| const rawCodecArg = typeAttr.args[0]?.value; | ||
| const codecId = | ||
| rawCodecArg?.startsWith('"') && rawCodecArg.endsWith('"') && rawCodecArg.length >= 2 | ||
| ? rawCodecArg.slice(1, -1) | ||
| : undefined; | ||
| if (codecId === undefined) { | ||
| ctx.diagnostics?.push({ | ||
| code: 'PSL_ENUM_MISSING_TYPE', | ||
| message: `enum "${block.name}" @@type attribute must have a quoted codec id argument`, | ||
| sourceId, | ||
| span: typeAttr.span, | ||
| }); | ||
| return undefined; | ||
| } | ||
| return { codecId, codecSpan: typeAttr.args[0]?.span ?? typeAttr.span }; | ||
| } | ||
| export interface AuthoringEntityTypeTemplateOutput { | ||
@@ -230,2 +360,16 @@ readonly template: AuthoringTemplateValue; | ||
| readonly variadicParameters?: boolean; | ||
| /** | ||
| * Declares that the model named by the block's ref parameter `parameter` | ||
| * must carry the bare `@@` model attribute `attribute`. The family | ||
| * interpreter enforces this generically over the whole parsed document — | ||
| * declaration order of the block and the model does not matter — and | ||
| * emits `PSL_EXTENSION_TARGET_MODEL_MISSING_ATTRIBUTE` naming the block | ||
| * and the model when the attribute is absent. A parameter that is | ||
| * missing or does not resolve to a model is not this rule's concern | ||
| * (missing-parameter and unresolved-ref diagnostics own those cases). | ||
| */ | ||
| readonly requiresModelAttribute?: { | ||
| readonly parameter: string; | ||
| readonly attribute: string; | ||
| }; | ||
| } | ||
@@ -237,2 +381,70 @@ | ||
| /** | ||
| * Context surfaced to a model-attribute lowering at call time: the entity | ||
| * context shared with entity-type factories, plus the declaring model's | ||
| * name, its mapped storage name (the name of the storage object the model | ||
| * maps to; which kind of object that is belongs to the family, not the | ||
| * framework), and the namespace id the lowered entity should be filed | ||
| * under. | ||
| */ | ||
| export interface AuthoringModelAttributeContext extends AuthoringEntityContext { | ||
| readonly modelName: string; | ||
| readonly storageName: string; | ||
| readonly namespaceId: string; | ||
| } | ||
| /** | ||
| * What a model-attribute lowering returns when it produces an entity: `key` | ||
| * is the identity the entity is stored under within its `entries` slot | ||
| * (`entries[attribute][key]`); `entity` is the value stored there. A | ||
| * lowering that instead pushed a diagnostic through | ||
| * {@link AuthoringModelAttributeContext.diagnostics} returns `undefined` — | ||
| * the same convention {@link AuthoringEntityTypeFactoryOutput} uses. | ||
| */ | ||
| export interface AuthoringModelAttributeLoweringOutput { | ||
| readonly key: string; | ||
| readonly entity: unknown; | ||
| } | ||
| /** | ||
| * Declarative descriptor for an extension-contributed `@@` model attribute. | ||
| * | ||
| * An extension registers one of these per bare attribute name it | ||
| * contributes. The framework owns the generic consult in the interpreter's | ||
| * model-attribute loop; the contribution supplies only `spec` and `lower`. | ||
| * | ||
| * - `attribute` is the bare `@@` attribute name this descriptor claims and, | ||
| * by the one-string rule, the `entries` slot its lowered entities are | ||
| * grouped under (`entries[attribute][key]`). | ||
| * - `spec` is opaque to the framework core: an ADR-231 attribute-spec kit | ||
| * `AttributeSpec<Out>` value (`modelAttribute(name, {...})` from | ||
| * `@prisma-next/psl-parser`). Framework core does not depend on | ||
| * psl-parser and never inspects this field; the family interpreter, | ||
| * which does depend on psl-parser, parses the attribute's arguments | ||
| * against it. | ||
| * - `lower` receives the parsed arguments and the declaring model's | ||
| * context, and returns the entity to file into `entries`, or `undefined` | ||
| * after pushing a diagnostic via `ctx.diagnostics`. | ||
| * | ||
| * `Out` defaults to `never` — not `unknown` — for the same contravariance | ||
| * reason documented on {@link AuthoringEntityTypeFactoryOutput}: a concrete | ||
| * pack literal's narrower `lower(parsed: ConcreteOut, ctx)` is only | ||
| * assignable to this base shape when the base parameter is the bottom type. | ||
| */ | ||
| export interface AuthoringModelAttributeDescriptor<Out = never> { | ||
| readonly kind: 'modelAttribute'; | ||
| readonly attribute: string; | ||
| readonly spec: unknown; | ||
| readonly lower: ( | ||
| parsed: Out, | ||
| ctx: AuthoringModelAttributeContext, | ||
| ) => AuthoringModelAttributeLoweringOutput | undefined; | ||
| } | ||
| export type AuthoringModelAttributeDescriptorNamespace = { | ||
| readonly [name: string]: | ||
| | AuthoringModelAttributeDescriptor | ||
| | AuthoringModelAttributeDescriptorNamespace; | ||
| }; | ||
| export interface AuthoringContributions { | ||
@@ -254,2 +466,11 @@ readonly type?: AuthoringTypeNamespace; | ||
| readonly pslBlockDescriptors?: AuthoringPslBlockDescriptorNamespace; | ||
| /** | ||
| * Registry of declarative `@@` model attribute descriptors this | ||
| * contribution registers, keyed by arbitrary path segments. Each leaf is | ||
| * an {@link AuthoringModelAttributeDescriptor} that claims a bare model | ||
| * attribute name. The framework owns the generic consult in the family | ||
| * interpreter's model-attribute loop; the contribution supplies only the | ||
| * declarative spec and the lowering. | ||
| */ | ||
| readonly modelAttributes?: AuthoringModelAttributeDescriptorNamespace; | ||
| } | ||
@@ -276,84 +497,31 @@ | ||
| export function isAuthoringTypeConstructorDescriptor( | ||
| value: unknown, | ||
| value: AuthoringTypeConstructorDescriptor | AuthoringTypeNamespace, | ||
| ): value is AuthoringTypeConstructorDescriptor { | ||
| return ( | ||
| typeof value === 'object' && | ||
| value !== null && | ||
| (value as { kind?: unknown }).kind === 'typeConstructor' && | ||
| typeof (value as { output?: unknown }).output === 'object' && | ||
| (value as { output?: unknown }).output !== null | ||
| ); | ||
| return 'kind' in value && value.kind === 'typeConstructor'; | ||
| } | ||
| export function isAuthoringFieldPresetDescriptor( | ||
| value: unknown, | ||
| value: AuthoringFieldPresetDescriptor | AuthoringFieldNamespace, | ||
| ): value is AuthoringFieldPresetDescriptor { | ||
| return ( | ||
| typeof value === 'object' && | ||
| value !== null && | ||
| (value as { kind?: unknown }).kind === 'fieldPreset' && | ||
| typeof (value as { output?: unknown }).output === 'object' && | ||
| (value as { output?: unknown }).output !== null | ||
| ); | ||
| return 'kind' in value && value.kind === 'fieldPreset'; | ||
| } | ||
| export function isAuthoringEntityTypeDescriptor( | ||
| value: unknown, | ||
| value: AuthoringEntityTypeDescriptor | AuthoringEntityTypeNamespace, | ||
| ): value is AuthoringEntityTypeDescriptor { | ||
| if ( | ||
| typeof value !== 'object' || | ||
| value === null || | ||
| (value as { kind?: unknown }).kind !== 'entity' | ||
| ) { | ||
| return false; | ||
| } | ||
| const discriminator = (value as { discriminator?: unknown }).discriminator; | ||
| if (typeof discriminator !== 'string' || discriminator.length === 0) { | ||
| return false; | ||
| } | ||
| const output = (value as { output?: unknown }).output; | ||
| if (typeof output !== 'object' || output === null) { | ||
| return false; | ||
| } | ||
| const factory = (output as { factory?: unknown }).factory; | ||
| const template = (output as { template?: unknown }).template; | ||
| return typeof factory === 'function' || template !== undefined; | ||
| return 'kind' in value && value.kind === 'entity'; | ||
| } | ||
| export function isAuthoringPslBlockDescriptor( | ||
| value: unknown, | ||
| value: AuthoringPslBlockDescriptor | AuthoringPslBlockDescriptorNamespace, | ||
| ): value is AuthoringPslBlockDescriptor { | ||
| if (typeof value !== 'object' || value === null) { | ||
| return false; | ||
| } | ||
| const record = blindCast< | ||
| Record<string, unknown>, | ||
| 'type-guard probing an unknown candidate-descriptor object for known property names' | ||
| >(value); | ||
| if (record['kind'] !== 'pslBlock') { | ||
| return false; | ||
| } | ||
| const keyword = record['keyword']; | ||
| if (typeof keyword !== 'string' || keyword.length === 0) { | ||
| return false; | ||
| } | ||
| const discriminator = record['discriminator']; | ||
| if (typeof discriminator !== 'string' || discriminator.length === 0) { | ||
| return false; | ||
| } | ||
| const name = record['name']; | ||
| if (typeof name !== 'object' || name === null) { | ||
| return false; | ||
| } | ||
| const nameRecord = blindCast< | ||
| Record<string, unknown>, | ||
| 'type-guard probing the name property of a candidate pslBlock descriptor' | ||
| >(name); | ||
| if (typeof nameRecord['required'] !== 'boolean') { | ||
| return false; | ||
| } | ||
| const parameters = record['parameters']; | ||
| return typeof parameters === 'object' && parameters !== null && !Array.isArray(parameters); | ||
| return 'kind' in value && value.kind === 'pslBlock'; | ||
| } | ||
| export function isAuthoringModelAttributeDescriptor( | ||
| value: AuthoringModelAttributeDescriptor | AuthoringModelAttributeDescriptorNamespace, | ||
| ): value is AuthoringModelAttributeDescriptor { | ||
| return 'kind' in value && value.kind === 'modelAttribute'; | ||
| } | ||
| /** | ||
@@ -374,3 +542,4 @@ * Returns true when `namespace` is a non-leaf key in `contributions.field`. | ||
| } | ||
| return !isAuthoringFieldPresetDescriptor(contributions.field[namespace]); | ||
| const value = contributions.field[namespace]; | ||
| return value !== undefined && !isAuthoringFieldPresetDescriptor(value); | ||
| } | ||
@@ -384,5 +553,77 @@ | ||
| /** | ||
| * Deep structural check run only at the composition boundary (the merge and | ||
| * collect walkers) to classify a raw namespace-tree node as a leaf descriptor. | ||
| * A node counts as a leaf iff its `kind` matches `descriptorKind` AND it | ||
| * carries that kind's required fields. | ||
| * | ||
| * This is boundary validation over `unknown`, NOT a type-predicate: the four | ||
| * exported `isAuthoring*Descriptor` predicates deliberately narrow on `kind` | ||
| * alone and trust the static types. The walkers, by contrast, also receive | ||
| * type-bypassing packs (`as unknown as never` in tests, untyped JS at runtime) | ||
| * whose descriptor-shaped-but-incomplete nodes must be rejected rather than | ||
| * silently treated as sub-namespaces — so the well-formedness check lives here. | ||
| */ | ||
| function isWellFormedDescriptor(value: unknown, descriptorKind: string): boolean { | ||
| if (typeof value !== 'object' || value === null) return false; | ||
| if (!('kind' in value) || value.kind !== descriptorKind) return false; | ||
| switch (descriptorKind) { | ||
| case 'typeConstructor': | ||
| case 'fieldPreset': { | ||
| if (!('output' in value)) return false; | ||
| const output = value.output; | ||
| return typeof output === 'object' && output !== null; | ||
| } | ||
| case 'entity': { | ||
| if (!('discriminator' in value) || typeof value.discriminator !== 'string') return false; | ||
| if (value.discriminator.length === 0) return false; | ||
| if (!('output' in value)) return false; | ||
| const output = value.output; | ||
| if (typeof output !== 'object' || output === null) return false; | ||
| const factory = 'factory' in output ? output.factory : undefined; | ||
| const template = 'template' in output ? output.template : undefined; | ||
| return typeof factory === 'function' || template !== undefined; | ||
| } | ||
| case 'pslBlock': { | ||
| if ( | ||
| !('keyword' in value) || | ||
| typeof value.keyword !== 'string' || | ||
| value.keyword.length === 0 | ||
| ) { | ||
| return false; | ||
| } | ||
| if ( | ||
| !('discriminator' in value) || | ||
| typeof value.discriminator !== 'string' || | ||
| value.discriminator.length === 0 | ||
| ) { | ||
| return false; | ||
| } | ||
| if (!('name' in value)) return false; | ||
| const name = value.name; | ||
| if (typeof name !== 'object' || name === null) return false; | ||
| if (!('required' in name) || typeof name.required !== 'boolean') return false; | ||
| if (!('parameters' in value)) return false; | ||
| const parameters = value.parameters; | ||
| return typeof parameters === 'object' && parameters !== null && !Array.isArray(parameters); | ||
| } | ||
| case 'modelAttribute': { | ||
| if ( | ||
| !('attribute' in value) || | ||
| typeof value.attribute !== 'string' || | ||
| value.attribute.length === 0 | ||
| ) { | ||
| return false; | ||
| } | ||
| if (!('spec' in value)) return false; | ||
| return 'lower' in value && typeof value.lower === 'function'; | ||
| } | ||
| default: | ||
| return false; | ||
| } | ||
| } | ||
| function deepCopyNamespace( | ||
| source: Record<string, unknown>, | ||
| isLeafDescriptor: (value: unknown) => boolean, | ||
| descriptorKind: string, | ||
| ): Record<string, unknown> { | ||
@@ -392,4 +633,4 @@ const copy: Record<string, unknown> = {}; | ||
| copy[key] = | ||
| isCopyableNamespaceObject(value) && !isLeafDescriptor(value) | ||
| ? deepCopyNamespace(value, isLeafDescriptor) | ||
| isCopyableNamespaceObject(value) && !isWellFormedDescriptor(value, descriptorKind) | ||
| ? deepCopyNamespace(value, descriptorKind) | ||
| : value; | ||
@@ -402,5 +643,6 @@ } | ||
| * Merges `source` into `target` recursively at the descriptor-namespace | ||
| * level. `isLeafDescriptor` decides which values are descriptors (terminal | ||
| * merge points; same-path registrations across components are reported | ||
| * as duplicates) versus sub-namespaces (recursion targets). | ||
| * level. `descriptorKind` is the `kind` value ('typeConstructor', | ||
| * 'fieldPreset', 'entity', or 'pslBlock') that identifies a descriptor | ||
| * (terminal merge point; same-path registrations across components are | ||
| * reported as duplicates) as opposed to a sub-namespace (recursion target). | ||
| * | ||
@@ -423,3 +665,3 @@ * Path segments are validated against prototype-pollution names | ||
| path: readonly string[], | ||
| isLeafDescriptor: (value: unknown) => boolean, | ||
| descriptorKind: string, | ||
| label: string, | ||
@@ -450,4 +692,5 @@ ): void { | ||
| target[key] = | ||
| isCopyableNamespaceObject(sourceValue) && !isLeafDescriptor(sourceValue) | ||
| ? deepCopyNamespace(sourceValue, isLeafDescriptor) | ||
| isCopyableNamespaceObject(sourceValue) && | ||
| !isWellFormedDescriptor(sourceValue, descriptorKind) | ||
| ? deepCopyNamespace(sourceValue, descriptorKind) | ||
| : sourceValue; | ||
@@ -457,4 +700,4 @@ continue; | ||
| const existingIsLeaf = isLeafDescriptor(existingValue); | ||
| const sourceIsLeaf = isLeafDescriptor(sourceValue); | ||
| const existingIsLeaf = isWellFormedDescriptor(existingValue, descriptorKind); | ||
| const sourceIsLeaf = isWellFormedDescriptor(sourceValue, descriptorKind); | ||
@@ -473,9 +716,18 @@ if (existingIsLeaf || sourceIsLeaf) { | ||
| mergeAuthoringNamespaces(existingValue, sourceValue, currentPath, isLeafDescriptor, label); | ||
| mergeAuthoringNamespaces(existingValue, sourceValue, currentPath, descriptorKind, label); | ||
| } | ||
| } | ||
| function collectDescriptorPaths( | ||
| namespace: Readonly<Record<string, unknown>>, | ||
| isLeaf: (value: unknown) => boolean, | ||
| /** | ||
| * Shape shared by every `Authoring*Namespace` type: a tree whose leaves are | ||
| * descriptors of type `D` and whose internal nodes are sub-namespaces of the | ||
| * same shape. `collectDescriptorPaths` and `collectDescriptorEntries` are | ||
| * generic over `D` so they can walk any of the four descriptor families with | ||
| * a properly narrowed `isLeaf` predicate instead of an `unknown`-typed one. | ||
| */ | ||
| type AuthoringNamespaceTree<D> = { readonly [name: string]: D | AuthoringNamespaceTree<D> }; | ||
| function collectDescriptorPaths<D>( | ||
| namespace: AuthoringNamespaceTree<D>, | ||
| isLeaf: (value: D | AuthoringNamespaceTree<D>) => value is D, | ||
| path: readonly string[] = [], | ||
@@ -491,5 +743,3 @@ ): string[] { | ||
| if (typeof value === 'object' && value !== null && !Array.isArray(value)) { | ||
| paths.push( | ||
| ...collectDescriptorPaths(value as Readonly<Record<string, unknown>>, isLeaf, currentPath), | ||
| ); | ||
| paths.push(...collectDescriptorPaths(value, isLeaf, currentPath)); | ||
| } | ||
@@ -505,5 +755,6 @@ } | ||
| function collectDescriptorEntries( | ||
| namespace: Readonly<Record<string, unknown>>, | ||
| isLeaf: (value: unknown) => boolean, | ||
| function collectDescriptorEntries<D extends { readonly discriminator: string }>( | ||
| namespace: AuthoringNamespaceTree<D>, | ||
| isLeaf: (value: D | AuthoringNamespaceTree<D>) => value is D, | ||
| descriptorKind: string, | ||
| label: string, | ||
@@ -516,10 +767,13 @@ path: readonly string[] = [], | ||
| if (isLeaf(value)) { | ||
| const record = blindCast< | ||
| Record<string, unknown>, | ||
| 'discriminator extraction from a leaf already validated by isLeaf' | ||
| >(value); | ||
| const discriminator = record['discriminator']; | ||
| if (typeof discriminator === 'string' && discriminator.length > 0) { | ||
| entries.push({ path: currentPath.join('.'), discriminator }); | ||
| // `isLeaf` narrows on `kind` alone; a type-bypassing pack can carry the | ||
| // right `kind` while missing the rest of the descriptor shape. Reject | ||
| // that here so a half-built contribution can't pass validation. | ||
| if (!isWellFormedDescriptor(value, descriptorKind)) { | ||
| throw new Error( | ||
| `Malformed authoring ${label} contribution at "${currentPath.join('.')}". The value carries descriptor keys (kind/keyword/discriminator) but does not satisfy the ${label} descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`, | ||
| ); | ||
| } | ||
| if (value.discriminator.length > 0) { | ||
| entries.push({ path: currentPath.join('.'), discriminator: value.discriminator }); | ||
| } | ||
| continue; | ||
@@ -533,5 +787,5 @@ } | ||
| // A value carrying descriptor-shaped keys (`kind`/`keyword`/`discriminator`) | ||
| // but failing `isAuthoringPslBlockDescriptor` (e.g. missing `parameters`) is | ||
| // a malformed declarative descriptor. Descending into it as a sub-namespace | ||
| // would silently skip it, so a half-built contribution would pass validation. | ||
| // but lacking a matching `kind` (so `isLeaf` rejected it) is a malformed | ||
| // declarative descriptor. Descending into it as a sub-namespace would | ||
| // silently skip it, so a half-built contribution would pass validation. | ||
| // Reject it at load time instead, naming the path and what's wrong. | ||
@@ -558,3 +812,3 @@ // | ||
| } | ||
| entries.push(...collectDescriptorEntries(record, isLeaf, label, currentPath)); | ||
| entries.push(...collectDescriptorEntries(value, isLeaf, descriptorKind, label, currentPath)); | ||
| } | ||
@@ -566,31 +820,52 @@ } | ||
| /** | ||
| * Throws when two or more entries in the same namespace share a discriminator. | ||
| * Duplicate discriminators within a namespace make dispatch ambiguous — the | ||
| * lowering factory lookup dispatches by discriminator, so one would silently | ||
| * shadow the other. Catch duplicates before building any dispatch map. | ||
| * Throws when two or more entries in the same namespace share a key. A | ||
| * duplicate key makes dispatch ambiguous — the caller's lookup dispatches by | ||
| * this key, so one entry would silently shadow the other. Catch duplicates | ||
| * before building any dispatch map. | ||
| * | ||
| * `label` (e.g. `'pslBlock'`, `'entityType'`) names which namespace the | ||
| * duplicate was found in and is carried in the structured error metadata; | ||
| * the key itself is always called `key` in both the message and the | ||
| * metadata, since what it semantically represents (a discriminator for | ||
| * `entityType`, the parser's dispatch keyword for `pslBlock`) is the | ||
| * caller's concern, not this function's. | ||
| */ | ||
| function assertUniqueDiscriminators(entries: readonly DescriptorEntry[], label: string): void { | ||
| const seen = new Map<string, string>(); | ||
| for (const { path, discriminator } of entries) { | ||
| const existing = seen.get(discriminator); | ||
| for (const { path, discriminator: key } of entries) { | ||
| const existing = seen.get(key); | ||
| if (existing !== undefined) { | ||
| throw new Error( | ||
| `Duplicate ${label} discriminator "${discriminator}" registered at both "${existing}" and "${path}". Each ${label} contribution must use a unique discriminator.`, | ||
| throw runtimeError( | ||
| 'RUNTIME.DUPLICATE_AUTHORING_DISCRIMINATOR', | ||
| `Duplicate ${label} key "${key}" registered at both "${existing}" and "${path}". Each ${label} contribution must use a unique key.`, | ||
| { label, key, existingPath: existing, path }, | ||
| ); | ||
| } | ||
| seen.set(discriminator, path); | ||
| seen.set(key, path); | ||
| } | ||
| } | ||
| interface PslBlockDescriptorEntry extends DescriptorEntry { | ||
| readonly keyword: string; | ||
| } | ||
| function collectPslBlockDescriptorEntries( | ||
| namespace: Readonly<Record<string, unknown>>, | ||
| namespace: AuthoringPslBlockDescriptorNamespace, | ||
| path: readonly string[] = [], | ||
| ): DescriptorEntry[] { | ||
| const entries: DescriptorEntry[] = []; | ||
| ): PslBlockDescriptorEntry[] { | ||
| const entries: PslBlockDescriptorEntry[] = []; | ||
| for (const [key, value] of Object.entries(namespace)) { | ||
| const currentPath = [...path, key]; | ||
| if (isAuthoringPslBlockDescriptor(value)) { | ||
| // `isAuthoringPslBlockDescriptor` narrows on `kind` alone; reject a | ||
| // `kind: 'pslBlock'` value that is missing the rest of the shape. | ||
| if (!isWellFormedDescriptor(value, 'pslBlock')) { | ||
| throw new Error( | ||
| `Malformed authoring pslBlock contribution at "${currentPath.join('.')}". The value carries descriptor keys (kind/keyword/discriminator) but does not satisfy the pslBlock descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`, | ||
| ); | ||
| } | ||
| entries.push({ | ||
| path: currentPath.join('.'), | ||
| discriminator: value.discriminator, | ||
| keyword: value.keyword, | ||
| }); | ||
@@ -612,3 +887,3 @@ continue; | ||
| } | ||
| entries.push(...collectPslBlockDescriptorEntries(record, currentPath)); | ||
| entries.push(...collectPslBlockDescriptorEntries(value, currentPath)); | ||
| } | ||
@@ -623,2 +898,9 @@ } | ||
| * `enum`, reachable from the TypeScript builder without any PSL block). | ||
| * | ||
| * Uniqueness for pslBlock entries is keyed on **keyword**, not discriminator: | ||
| * several keywords (e.g. `policy_select`/`policy_insert`) may legitimately | ||
| * share one discriminator, routing to the same `entityTypes` factory and the | ||
| * same `entries[discriminator]` slot — that N:1 shape is exactly what lets | ||
| * one entity kind be authored through several PSL keywords. What must stay | ||
| * unique is the keyword itself, since that's what the parser dispatches on. | ||
| */ | ||
@@ -633,6 +915,10 @@ function assertPslBlocksHaveFactories( | ||
| isAuthoringEntityTypeDescriptor, | ||
| 'entity', | ||
| 'entityType', | ||
| ); | ||
| assertUniqueDiscriminators(blockEntries, 'pslBlock'); | ||
| assertUniqueDiscriminators( | ||
| blockEntries.map((entry) => ({ path: entry.path, discriminator: entry.keyword })), | ||
| 'pslBlock', | ||
| ); | ||
| assertUniqueDiscriminators(entityEntries, 'entityType'); | ||
@@ -651,2 +937,61 @@ | ||
| function collectModelAttributeEntries( | ||
| namespace: AuthoringModelAttributeDescriptorNamespace, | ||
| path: readonly string[] = [], | ||
| ): DescriptorEntry[] { | ||
| const entries: DescriptorEntry[] = []; | ||
| for (const [key, value] of Object.entries(namespace)) { | ||
| const currentPath = [...path, key]; | ||
| if (isAuthoringModelAttributeDescriptor(value)) { | ||
| // `isAuthoringModelAttributeDescriptor` narrows on `kind` alone; reject a | ||
| // `kind: 'modelAttribute'` value that is missing the rest of the shape. | ||
| if (!isWellFormedDescriptor(value, 'modelAttribute')) { | ||
| throw new Error( | ||
| `Malformed authoring modelAttribute contribution at "${currentPath.join('.')}". The value carries descriptor keys (kind/attribute) but does not satisfy the modelAttribute descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`, | ||
| ); | ||
| } | ||
| entries.push({ path: currentPath.join('.'), discriminator: value.attribute }); | ||
| continue; | ||
| } | ||
| if (typeof value === 'object' && value !== null && !Array.isArray(value)) { | ||
| const record = blindCast< | ||
| Readonly<Record<string, unknown>>, | ||
| 'walker descends into modelAttribute namespace' | ||
| >(value); | ||
| // `kind === 'modelAttribute'` is unreachable here: it would have made | ||
| // `isAuthoringModelAttributeDescriptor` true and taken the leaf branch | ||
| // above. A descriptor-shaped-but-kindless value (attribute + spec) is | ||
| // the only malformed case a sub-namespace walk can hit. | ||
| const hasAttribute = typeof record['attribute'] === 'string'; | ||
| if (hasAttribute && 'spec' in record) { | ||
| throw new Error( | ||
| `Malformed authoring modelAttribute contribution at "${currentPath.join('.')}". The value carries descriptor keys (kind/attribute) but does not satisfy the modelAttribute descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`, | ||
| ); | ||
| } | ||
| entries.push(...collectModelAttributeEntries(value, currentPath)); | ||
| } | ||
| } | ||
| return entries; | ||
| } | ||
| /** | ||
| * Throws when two modelAttribute contributions — at any paths, even | ||
| * different ones — claim the same bare `@@` attribute name. The family | ||
| * interpreter dispatches by attribute name, not by registration path, so | ||
| * two descriptors claiming the same name would have one silently shadow | ||
| * the other. | ||
| */ | ||
| function assertUniqueModelAttributeNames(entries: readonly DescriptorEntry[]): void { | ||
| const seen = new Map<string, string>(); | ||
| for (const { path, discriminator: attribute } of entries) { | ||
| const existing = seen.get(attribute); | ||
| if (existing !== undefined) { | ||
| throw new Error( | ||
| `Duplicate modelAttribute "${attribute}" registered at both "${existing}" and "${path}". Each modelAttribute contribution must claim a unique attribute name.`, | ||
| ); | ||
| } | ||
| seen.set(attribute, path); | ||
| } | ||
| } | ||
| export function assertNoCrossRegistryCollisions( | ||
@@ -657,2 +1002,3 @@ typeNamespace: AuthoringTypeNamespace, | ||
| pslBlockNamespace: AuthoringPslBlockDescriptorNamespace = {}, | ||
| modelAttributeNamespace: AuthoringModelAttributeDescriptorNamespace = {}, | ||
| ): void { | ||
@@ -668,16 +1014,7 @@ const typePaths = new Set( | ||
| ); | ||
| // Within-registry duplicate detection is handled upstream by the merge | ||
| // walker (`mergeAuthoringNamespaces` in control-stack.ts and | ||
| // `mergeHelperNamespaces` in composed-authoring-helpers.ts), which throws | ||
| // on same-path registrations within any single registry before this check | ||
| // runs. This function only handles the cross-registry case. | ||
| // | ||
| // Cross-registry collisions are checked among `type` / `field` / | ||
| // `entityTypes` only — these three are user-facing helper paths that PSL | ||
| // must resolve unambiguously. `pslBlockDescriptors` is an internal | ||
| // framework index consumed by parser and printer dispatch, not a | ||
| // user-facing helper path; the natural authoring pattern is the same | ||
| // path key in `entityTypes` and `pslBlockDescriptors` for a single | ||
| // contribution. The block→factory link is enforced by | ||
| // `assertPslBlocksHaveFactories` via the discriminator string, not by path. | ||
| // Within-registry duplicates are caught upstream by the merge walkers; this | ||
| // checks only cross-registry collisions, and only among the user-facing | ||
| // `type`/`field`/`entityTypes` paths. `pslBlockDescriptors` is an internal | ||
| // index — its block→factory link is checked by discriminator in | ||
| // `assertPslBlocksHaveFactories`, not by path. | ||
| const ambiguityHint = | ||
@@ -701,8 +1038,12 @@ 'Register each path in only one of authoringContributions.field / authoringContributions.type / authoringContributions.entityTypes.'; | ||
| assertPslBlocksHaveFactories(entityTypeNamespace, pslBlockNamespace); | ||
| assertUniqueModelAttributeNames(collectModelAttributeEntries(modelAttributeNamespace)); | ||
| } | ||
| export function resolveAuthoringTemplateValue( | ||
| template: AuthoringTemplateValue, | ||
| template: AuthoringTemplateValue | undefined, | ||
| args: readonly unknown[], | ||
| ): unknown { | ||
| if (template === undefined) { | ||
| return undefined; | ||
| } | ||
| if (isAuthoringArgRef(template)) { | ||
@@ -867,3 +1208,3 @@ let value = args[template.index]; | ||
| nativeType, | ||
| ...(typeParams === undefined ? {} : { typeParams }), | ||
| ...ifDefined('typeParams', typeParams), | ||
| }; | ||
@@ -949,3 +1290,3 @@ } | ||
| export function instantiateAuthoringEntityType( | ||
| export function instantiateAuthoringEntityType<TOutput = unknown>( | ||
| helperPath: string, | ||
@@ -955,3 +1296,3 @@ descriptor: AuthoringEntityTypeDescriptor, | ||
| ctx: AuthoringEntityContext, | ||
| ): unknown { | ||
| ): TOutput { | ||
| // Factory-output entities carry their input contract on the factory | ||
@@ -971,10 +1312,12 @@ // signature itself — TypeScript narrows callers via | ||
| // forward the supplied input here without a static input contract. | ||
| const factory = descriptor.output.factory as ( | ||
| input: unknown, | ||
| ctx: AuthoringEntityContext, | ||
| ) => unknown; | ||
| const factory = blindCast< | ||
| (input: unknown, ctx: AuthoringEntityContext) => TOutput, | ||
| 'entity factory output is caller-selected via instantiateAuthoringEntityType<TOutput>' | ||
| >(descriptor.output.factory); | ||
| return factory(input, ctx); | ||
| } | ||
| validateAuthoringHelperArguments(helperPath, descriptor.args, args); | ||
| return resolveAuthoringTemplateValue(descriptor.output.template, args); | ||
| return blindCast<TOutput, 'template-output resolves to the declared TOutput by convention'>( | ||
| resolveAuthoringTemplateValue(descriptor.output.template, args), | ||
| ); | ||
| } | ||
@@ -981,0 +1324,0 @@ |
@@ -26,14 +26,2 @@ import type { | ||
| interface DefaultFunctionArgument { | ||
| readonly raw: string; | ||
| readonly span: SourceSpan; | ||
| } | ||
| export interface ParsedDefaultFunctionCall { | ||
| readonly name: string; | ||
| readonly raw: string; | ||
| readonly args: readonly DefaultFunctionArgument[]; | ||
| readonly span: SourceSpan; | ||
| } | ||
| export interface DefaultFunctionLoweringContext { | ||
@@ -54,14 +42,2 @@ readonly sourceId: string; | ||
| export type DefaultFunctionLoweringHandler = (input: { | ||
| readonly call: ParsedDefaultFunctionCall; | ||
| readonly context: DefaultFunctionLoweringContext; | ||
| }) => LoweredDefaultResult; | ||
| export interface DefaultFunctionRegistryEntry { | ||
| readonly lower: DefaultFunctionLoweringHandler; | ||
| readonly usageSignatures?: readonly string[]; | ||
| } | ||
| export type DefaultFunctionRegistry = ReadonlyMap<string, DefaultFunctionRegistryEntry>; | ||
| export interface MutationDefaultGeneratorDescriptor { | ||
@@ -98,5 +74,17 @@ readonly id: string; | ||
| // A default-function call whose arguments the function's `funcCall` signature has already parsed | ||
| // and validated, so the registry lowering reads them directly instead of re-parsing source text. | ||
| export interface TypedDefaultFunctionCall { | ||
| readonly fn: string; | ||
| readonly span: SourceSpan; | ||
| readonly args: Readonly<Record<string, unknown>>; | ||
| } | ||
| export interface ControlMutationDefaultEntry { | ||
| // The function's argument signature. Typed `unknown` because its concrete type (`FuncCallSig`) | ||
| // lives in the authoring layer, which the core framework cannot import; the family that | ||
| // registers the entry narrows it back. | ||
| readonly signature?: unknown; | ||
| readonly lower: (input: { | ||
| readonly call: ParsedDefaultFunctionCall; | ||
| readonly call: TypedDefaultFunctionCall; | ||
| readonly context: DefaultFunctionLoweringContext; | ||
@@ -103,0 +91,0 @@ }) => LoweredDefaultResult; |
@@ -111,3 +111,8 @@ /** | ||
| */ | ||
| | 'PSL_INVALID_EXTENSION_BLOCK_ATTRIBUTE'; | ||
| | 'PSL_INVALID_EXTENSION_BLOCK_ATTRIBUTE' | ||
| /** | ||
| * Duplicate scopes are top level, namespace body, or block fields; diagnostics | ||
| * are first-wins and anchored on later name spans. | ||
| */ | ||
| | 'PSL_DUPLICATE_DECLARATION'; | ||
@@ -241,7 +246,17 @@ /** | ||
| * node, as produced by the generic framework parser and consumed by the | ||
| * validator and lowering factory. | ||
| * validator, printer, and lowering factory. | ||
| * | ||
| * - `kind` is the routing discriminant, equal to the descriptor's | ||
| * `discriminator`. The framework parser sets this to | ||
| * `descriptor.discriminator` for every block it parses. | ||
| * `descriptor.discriminator` for every block it parses. Several keywords | ||
| * may share one discriminator (e.g. `policy_select`/`policy_insert` both | ||
| * route to `kind: 'policy'`) — `kind` identifies the entity/storage kind, | ||
| * not the source syntax. | ||
| * - `keyword` is the source PSL keyword the block was declared with | ||
| * (`policy_select`, `policy_insert`, …) — the parse-dispatch identity. | ||
| * Distinct from `kind` precisely when a discriminator is shared by more | ||
| * than one keyword; a lowering factory that contributes several keywords | ||
| * under one discriminator reads `keyword` to tell its blocks apart, and | ||
| * the printer re-emits each block under its own `keyword` regardless of | ||
| * how many other keywords share its `kind`. | ||
| * - `name` is the block's declared name (the identifier after the keyword). | ||
@@ -262,2 +277,9 @@ * - `parameters` is the descriptor-driven parameter map. Keys are | ||
| readonly kind: string; | ||
| /** | ||
| * The block's parse identity — the source PSL keyword it was declared | ||
| * with. `kind`/`discriminator` is its storage identity; several keywords | ||
| * can share one. E.g. the five `policy_*` keywords all lower to the | ||
| * `policy` entity kind. | ||
| */ | ||
| readonly keyword: string; | ||
| readonly name: string; | ||
@@ -264,0 +286,0 @@ readonly parameters: Record<string, PslExtensionBlockParamValue>; |
| import { JsonValue } from "@prisma-next/contract/types"; | ||
| import { StandardSchemaV1 } from "@standard-schema/spec"; | ||
| //#region src/shared/codec-descriptor.d.ts | ||
| /** | ||
| * Unified codec descriptor. Every codec in the framework registers through this shape — non-parameterized codecs use `P = void` and a constant factory that returns the same shared codec instance for every column; parameterized codecs use a non-empty `P` and a curried higher-order factory that returns a per-instance codec. | ||
| * | ||
| * The descriptor is the codec-id-keyed source of truth for static metadata (`traits`, `targetTypes`, `meta`) and registration concerns (`paramsSchema` for JSON-boundary validation; optional `renderOutputType` for the `contract.d.ts` emit path). The runtime `Codec` instance returned by `factory(params)(ctx)` carries only the conversion behavior. | ||
| * | ||
| * Whether a codec id "is parameterized" stops being a registration-time distinction — it's a property of `P` on the descriptor. The descriptor map indexes every descriptor by `codecId`; both `descriptorFor(codecId)` and `forColumn(table, column)` resolve through the same map without branching on parameterization. | ||
| * | ||
| * @template P - The shape of the params accepted by the factory (`void` for non-parameterized codecs; a record like `{ length: number }` for parameterized codecs). | ||
| * | ||
| * Codec-registry-unification project § Decision. | ||
| */ | ||
| interface CodecDescriptor<P = void> { | ||
| /** The codec ID this descriptor applies to (e.g. `pg/vector@1`, `pg/text@1`). */ | ||
| readonly codecId: string; | ||
| /** Semantic traits for operator gating (e.g. equality, order, numeric). */ | ||
| readonly traits: readonly CodecTrait[]; | ||
| /** Database-native type names this codec handles (e.g. `['timestamptz']`). */ | ||
| readonly targetTypes: readonly string[]; | ||
| /** Optional family-specific metadata (e.g. SQL-side `db.sql.postgres.nativeType`). */ | ||
| readonly meta?: CodecMeta; | ||
| /** Standard Schema validator for the factory's params. Validates JSON-sourced params at the contract boundary (PSL → IR; `contract.json` → runtime). For non-parameterized codecs (`P = void`), the schema validates `void`/`undefined` — the framework supplies no params at the call boundary. */ | ||
| readonly paramsSchema: StandardSchemaV1<P>; | ||
| /** Whether this descriptor is parameterized — i.e. its `paramsSchema` is something other than the singleton `voidParamsSchema`. Consumers that need to gate column-aware dispatch read this directly rather than threading a free-floating `(codecId) => boolean` callback. */ | ||
| readonly isParameterized: boolean; | ||
| /** Emit-path string renderer for `contract.d.ts`. Returns the TypeScript output type expression for given params (e.g. `Vector<1536>`). Optional; absent renderers cause the emitter to fall back to the codec's base output type. Non-parameterized codecs typically omit it. */ | ||
| readonly renderOutputType?: (params: P) => string | undefined; | ||
| /** Emit-path string renderer for the `contract.d.ts` *input* position (create/update values). Returns the TypeScript input type expression for given params. Optional; absent renderers fall back to the codec's base input type. A codec supplies this when its write type is narrower than the generic codec input — e.g. an enum whose input should be the literal member union, not `string`. */ | ||
| readonly renderInputType?: (params: P) => string | undefined; | ||
| /** The curried higher-order codec. For non-parameterized codecs, the factory is constant — every call returns the same shared codec instance. For parameterized codecs, the factory is called once per `storage.types` instance (or once per inline-`typeParams` column), with `ctx` carrying the column set the resulting codec serves. */ | ||
| readonly factory: (params: P) => (ctx: CodecInstanceContext) => Codec; | ||
| } | ||
| /** | ||
| * Variance-erased {@link CodecDescriptor} alias. `CodecDescriptor<P>` is invariant in `P` (the `factory` and `renderOutputType` slots use `P` contravariantly), so `CodecDescriptor<P>` does not extend `CodecDescriptor<unknown>` for specific `P`. Heterogeneous descriptor collections — e.g. `SqlStaticContributions.codecs:` returning a list that mixes parameterized and non-parameterized descriptors — type against this alias and narrow per codec id at the consumer. | ||
| * | ||
| * Codec-registry-unification spec § Decision: every codec resolves through one descriptor map; reads are non-branching. | ||
| */ | ||
| type AnyCodecDescriptor = CodecDescriptor<any>; | ||
| /** | ||
| * Abstract base class for concrete codec descriptors. | ||
| * | ||
| * Codec authors extend this class with their typed `TParams` and declare `codecId`, `traits`, `targetTypes`, `paramsSchema`, the curried `factory(params)`, and (optionally) `renderOutputType`. | ||
| * | ||
| * Implements the {@link CodecDescriptor} interface so a concrete subclass instance is directly usable wherever the framework expects a `CodecDescriptor<P>`. | ||
| */ | ||
| declare abstract class CodecDescriptorImpl<TParams = void> implements CodecDescriptor<TParams> { | ||
| abstract readonly codecId: string; | ||
| abstract readonly traits: readonly CodecTrait[]; | ||
| abstract readonly targetTypes: readonly string[]; | ||
| readonly meta?: CodecMeta; | ||
| abstract readonly paramsSchema: StandardSchemaV1<TParams>; | ||
| /** Boolean derived from `paramsSchema`: `true` whenever the schema is not the singleton `voidParamsSchema`. */ | ||
| get isParameterized(): boolean; | ||
| /** Optional emit-path string renderer for `contract.d.ts`. Returns the TypeScript output type expression for the given params (e.g. `Vector<1536>`). Non-parameterized codecs typically omit it. */ | ||
| renderOutputType?(params: TParams): string | undefined; | ||
| /** Optional emit-path string renderer for the `contract.d.ts` input position. Returns the TypeScript input type expression for the given params; supplied when the write type is narrower than the generic codec input (e.g. an enum's literal member union). */ | ||
| renderInputType?(params: TParams): string | undefined; | ||
| /** | ||
| * Materialize a curried codec factory for the given params. Concrete subclasses override with a typed return type (e.g. `factory<N>(params: { length: N }): (ctx) => VectorCodec<N>`); per-codec helpers read the typed return at the *direct* call site, which is what preserves method-level generics. Type extraction (e.g. `ReturnType<D['factory']>`) widens method generics to their constraint — that's why the column-helper surface is per-codec, not polymorphic. | ||
| */ | ||
| abstract factory(params: TParams): (ctx: CodecInstanceContext) => Codec<string, readonly CodecTrait[], unknown, unknown>; | ||
| } | ||
| //#endregion | ||
| //#region src/shared/codec.d.ts | ||
| /** | ||
| * A codec is the contract between an application value and its on-wire and on-contract-disk representations. | ||
| * | ||
| * The author's mental model is two JS-side types — `TInput` (the application JS type) and `TWire` (the database driver wire format) — plus `JsonValue` for build-time contract artifacts. The codec translates `TInput` to `TWire` on writes and back on reads, and to/from `JsonValue` during contract emission and loading. | ||
| * | ||
| * Three representations participate: | ||
| * - **Input** (`TInput`): the JS type at the application boundary. | ||
| * - **Wire** (`TWire`): the format exchanged with the database driver. | ||
| * - **JSON** (`JsonValue`): a JSON-safe form used in contract artifacts. | ||
| * | ||
| * The runtime instance carries only its `id` (the descriptor's `codecId`, set by the factory) and the four conversion methods. Static metadata (`traits`, `targetTypes`, `meta`) and the build-time `renderOutputType` renderer live on the {@link CodecDescriptor} keyed by `codecId` — the read-surface single source of truth. Consumers that need them resolve through `descriptorFor(codecId)`. | ||
| * | ||
| * Codec methods split into two groups: | ||
| * | ||
| * - **Query-time** methods (`encode`, `decode`) run per row/parameter at the IO boundary; they are required and Promise-returning. The per-family codec factory accepts sync or async author functions and lifts sync ones to Promise-shaped methods automatically. | ||
| * - **Build-time** methods (`encodeJson`, `decodeJson`) run when the contract is serialized or loaded. They stay synchronous so contract validation and client construction are synchronous. | ||
| * | ||
| * Target-family codec interfaces extend this base; family-specific concerns (e.g. the SQL `column?` per-call context) layer on through the `CodecCallContext` extension pattern. | ||
| */ | ||
| interface Codec<Id extends string = string, TTraits extends readonly CodecTrait[] = readonly CodecTrait[], TWire = unknown, TInput = unknown> { | ||
| /** Unique codec identifier in `namespace/name@version` format (e.g. `pg/timestamptz@1`). The factory sets this to the descriptor's `codecId`; consumers use it as a back-reference for descriptor lookups and for decode-error diagnostics. */ | ||
| readonly id: Id; | ||
| /** Phantom carrier for the `TTraits` generic; type-only, undefined at runtime. Runtime traits live on {@link CodecDescriptor.traits}. Implemented as a string-key phantom (`__codecTraits`) rather than `unique symbol` so bundlers that split `.d.ts` chunks do not strand symbol identity on chunk-private paths (the same `TS2742` family that the public re-export of `CodecTypes` works around). */ | ||
| readonly __codecTraits?: TTraits; | ||
| /** Converts a JS value to the wire format expected by the database driver. Always Promise-returning at the boundary. The {@link CodecCallContext} is supplied by the runtime on every call (allocated once per `runtime.execute()`); family layers may narrow the ctx to extend it (e.g. SQL adds `column`). Author-side single-arg `(value) => …` functions remain legal via TypeScript's bivariance for trailing parameters. */ | ||
| encode(value: TInput, ctx: CodecCallContext): Promise<TWire>; | ||
| /** Converts a wire value from the database driver into the JS application type. Always Promise-returning at the boundary. The {@link CodecCallContext} is supplied by the runtime on every call (allocated once per `runtime.execute()`); family layers may narrow the ctx to extend it (e.g. SQL adds `column`). Author-side single-arg `(wire) => …` functions remain legal via TypeScript's bivariance for trailing parameters. */ | ||
| decode(wire: TWire, ctx: CodecCallContext): Promise<TInput>; | ||
| /** Converts a JS value to a JSON-safe representation for contract serialization. Synchronous; called during contract emission. */ | ||
| encodeJson(value: TInput): JsonValue; | ||
| /** Converts a JSON representation back to the JS input type. Synchronous; called during contract loading via `family.deserializeContract`. */ | ||
| decodeJson(json: JsonValue): TInput; | ||
| } | ||
| /** | ||
| * Abstract base class for concrete codec implementations. | ||
| * | ||
| * Codec authors extend this class with their typed `Id`, `TTraits`, `TWire`, `TInput` and override `encode`/`decode` (and optionally `encodeJson`/`decodeJson`). The runtime instance carries only its `id` (proxied through the descriptor so alias subclasses inherit the descriptor's id automatically) and the conversion methods — static metadata lives on the {@link CodecDescriptor}. | ||
| */ | ||
| declare abstract class CodecImpl<Id extends string = string, TTraits extends readonly CodecTrait[] = readonly CodecTrait[], TWire = unknown, TInput = unknown> implements Codec<Id, TTraits, TWire, TInput> { | ||
| readonly descriptor: CodecDescriptor<any>; | ||
| /** | ||
| * Variance-erased descriptor reference. Concrete codec subclasses receive the typed descriptor in their own constructors and forward it via `super(descriptor)`; the variance erasure lives at this base because the abstract surface can't carry the concrete `TParams`. | ||
| */ | ||
| constructor(descriptor: CodecDescriptor<any>); | ||
| get id(): Id; | ||
| abstract encode(value: TInput, ctx: CodecCallContext): Promise<TWire>; | ||
| abstract decode(wire: TWire, ctx: CodecCallContext): Promise<TInput>; | ||
| abstract encodeJson(value: TInput): JsonValue; | ||
| abstract decodeJson(json: JsonValue): TInput; | ||
| } | ||
| //#endregion | ||
| //#region src/shared/codec-types.d.ts | ||
| type CodecTrait = 'equality' | 'order' | 'boolean' | 'numeric' | 'textual'; | ||
| /** | ||
| * Serializable codec identity carried by every codec-bearing AST node. | ||
| * | ||
| * `(codecId, typeParams?)` is the single fact the runtime needs to materialize a codec via `descriptorFor(codecId).factory(typeParams)(ctx)`. The pair is content-keyed: two refs with the same `codecId` and structurally equal `typeParams` (regardless of object key ordering) resolve to the same memoized {@link Codec} instance. | ||
| * | ||
| * `typeParams` is `JsonValue`-constrained so the ref survives JSON serialization (relevant for AST-embedded migration ops). Non-parameterized codecs leave `typeParams` undefined; the descriptor's `paramsSchema` validates the value at the JSON boundary. | ||
| * | ||
| * Family-agnostic by design — both SQL and Mongo AST nodes carry `codec: CodecRef | undefined`, and the resolver is the only dispatch path that survives serialization. | ||
| */ | ||
| interface CodecRef { | ||
| readonly codecId: string; | ||
| readonly typeParams?: JsonValue; | ||
| } | ||
| /** | ||
| * Per-call context the runtime threads to every `codec.encode` / `codec.decode` invocation for a single `runtime.execute()` call. | ||
| * | ||
| * The framework-level shape is family-agnostic and carries one field: | ||
| * | ||
| * - `signal?: AbortSignal` — per-query cancellation. The runtime returns a `RUNTIME.ABORTED` envelope when the signal aborts; codec authors who forward `signal` to their underlying SDK get true cancellation of in-flight network calls. | ||
| * | ||
| * Family layers extend this base with their own shape-of-call metadata: the SQL family adds `column?: SqlColumnRef` via `SqlCodecCallContext` (see `@prisma-next/sql-relational-core`). Mongo currently uses this framework type unchanged. Column metadata is intentionally **not** on the framework type — it is a SQL-family concept rooted in SQL's `(table, column)` addressing model and would not generalise to other families. | ||
| * | ||
| * The interface is named explicitly (not inlined) so future framework fields and family extensions can land additively without breaking codec author signatures. | ||
| */ | ||
| interface CodecCallContext { | ||
| readonly signal?: AbortSignal; | ||
| } | ||
| /** | ||
| * Codec-id-keyed read surface threaded into emit and authoring paths. | ||
| * | ||
| * - `get(id)` returns a representative {@link Codec} instance for the codec id (used by `family.deserializeContract` for `decodeJson` of literal column defaults). For parameterized codecs whose factory requires concrete params, this may return `undefined` — use `CodecRegistry.forCodecRef` instead. | ||
| * - `targetTypesFor(id)` exposes the codec-id-keyed `targetTypes` metadata the runtime instance no longer carries (TML-2357). Returns the same array `CodecDescriptor.targetTypes` would; for Mongo (whose registration doesn't yet resolve through the unified descriptor map — TML-2324) the family-side assembly populates this directly from the contributor's codec metadata. | ||
| * - `metaFor(id)` exposes the codec-id-keyed `meta` (e.g. SQL-side `db.sql.postgres.nativeType`) the runtime instance no longer carries. | ||
| * - `renderOutputTypeFor(id, params)` exposes the codec-id-keyed `renderOutputType` renderer the runtime instance no longer carries. Returns `undefined` when the codec doesn't render a custom type or when the codec id is unknown. | ||
| */ | ||
| interface CodecLookup { | ||
| get(id: string): Codec | undefined; | ||
| targetTypesFor(id: string): readonly string[] | undefined; | ||
| metaFor(id: string): CodecMeta | undefined; | ||
| renderOutputTypeFor(id: string, params: Record<string, unknown>): string | undefined; | ||
| /** Codec-id-keyed `renderInputType` renderer for the `contract.d.ts` input position. Optional so existing lookups need not provide it; returns `undefined` when the codec renders no custom input type or the id is unknown. */ | ||
| renderInputTypeFor?(id: string, params: Record<string, unknown>): string | undefined; | ||
| } | ||
| /** | ||
| * Full codec registry — the read surface of {@link CodecLookup} plus codec resolution by ref or | ||
| * column coordinate. Built once by `extractCodecLookup` and passed by reference to adapters and | ||
| * other consumers that need to materialise codecs at runtime. | ||
| * | ||
| * - `forCodecRef(ref)` materialises a codec from a {@link CodecRef}. Throws | ||
| * `RUNTIME.CODEC_DESCRIPTOR_MISSING` for unknown ids and `RUNTIME.TYPE_PARAMS_INVALID` on param | ||
| * schema rejection. | ||
| * - `forColumn(namespaceId, table, column)` returns the codec for a specific column coordinate, or | ||
| * `undefined` when no column-to-codec mapping is present. This registry is contract-free so it | ||
| * always returns `undefined` — the method exists so the object structurally satisfies the SQL | ||
| * `ContractCodecRegistry` interface. | ||
| */ | ||
| interface CodecRegistry extends CodecLookup { | ||
| forCodecRef(ref: CodecRef): Codec; | ||
| forColumn(namespaceId: string, table: string, column: string): Codec | undefined; | ||
| } | ||
| declare const emptyCodecLookup: CodecLookup; | ||
| /** | ||
| * Family-agnostic per-instance context supplied by the framework when applying a higher-order codec factory. Allows stateful codecs (e.g. column-scoped encryption) to derive per-instance state from the materialization site. | ||
| * | ||
| * - `name` — the family-agnostic instance identity. For SQL, the runtime populates this as the `storage.types` instance name (e.g. `Embedding1536`) for typeRef-shaped columns, an inline-column sentinel (`<col:Document.embedding>`) for inline-`typeParams` columns, a shared codec-id sentinel (`<codec:pg/text@1>`) for non-parameterized codec ids, or the canonical cache key (`<codecId>:<canonicalizeJson(typeParams)>`) for ad-hoc refs the contract walk did not pre-populate. Other families pick the analogous identity for their materialization sites. | ||
| * | ||
| * Family-specific extensions (e.g. {@link import('@prisma-next/sql-relational-core/ast').SqlCodecInstanceContext} in the SQL layer) augment this base with domain-shaped column-set metadata. Codec authors target the base when they don't read family-specific metadata; they target the family extension when they do. | ||
| */ | ||
| interface CodecInstanceContext { | ||
| readonly name: string; | ||
| } | ||
| /** | ||
| * Family-agnostic codec metadata. Family-specific extensions augment the base `db.<family>.<target>` block with native-type information; the base shape is an empty object so non-relational codecs can carry no metadata. | ||
| */ | ||
| interface CodecMeta { | ||
| readonly db?: Record<string, unknown>; | ||
| } | ||
| /** | ||
| * Standard Schema validator for `void` params. Accepts only `undefined` (or absent input); rejects any other value so a contract that tries to thread `typeParams` through a non-parameterized codec id fails fast at the JSON boundary instead of silently coercing the value away. Used by the framework-supplied non-parameterized descriptor synthesizer. | ||
| */ | ||
| declare const voidParamsSchema: StandardSchemaV1<void>; | ||
| //#endregion | ||
| export { CodecRef as a, emptyCodecLookup as c, CodecImpl as d, AnyCodecDescriptor as f, CodecMeta as i, voidParamsSchema as l, CodecDescriptorImpl as m, CodecInstanceContext as n, CodecRegistry as o, CodecDescriptor as p, CodecLookup as r, CodecTrait as s, CodecCallContext as t, Codec as u }; | ||
| //# sourceMappingURL=codec-types-yY3eSmi0.d.mts.map |
| {"version":3,"file":"codec-types-yY3eSmi0.d.mts","names":[],"sources":["../src/shared/codec-descriptor.ts","../src/shared/codec.ts","../src/shared/codec-types.ts"],"mappings":"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"} |
| {"version":3,"file":"components.d.mts","names":[],"sources":["../src/shared/capabilities.ts"],"mappings":";;;;;;AAqEA;;;;;;;;;;;;;;;;;;;AAGwB;;;iBAHR,uBAAA,CACd,IAAA,EAAM,MAAA,SAAe,MAAA,oBACrB,YAAA,EAAc,aAAA;EAAA,SAAyB,YAAA;AAAA,KACtC,MAAA,SAAe,MAAA"} |
| {"version":3,"file":"components.mjs","names":[],"sources":["../src/shared/capabilities.ts"],"sourcesContent":["/**\n * Capability matrix merge primitive shared by emit-time and runtime stack composition.\n *\n * The CLI's `enrichContract` and the SQL runtime's `createExecutionContext` both need\n * to fold a stack of component descriptors' `capabilities` declarations into a single\n * matrix keyed by namespace. Keeping the primitive here lets both call sites stay\n * byte-for-byte consistent without one depending on the other.\n */\n\nimport { blindCast } from '@prisma-next/utils/casts';\n\ntype CapabilityMatrix = Record<string, Record<string, boolean>>;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction sortDeep(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortDeep);\n }\n if (!isPlainObject(value)) {\n return value;\n }\n const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));\n const next: Record<string, unknown> = {};\n for (const [key, child] of entries) {\n next[key] = sortDeep(child);\n }\n return next;\n}\n\nfunction extractCapabilityMatrix(value: unknown): CapabilityMatrix {\n if (!isPlainObject(value)) return {};\n\n const out: CapabilityMatrix = {};\n for (const [namespace, maybeCaps] of Object.entries(value)) {\n if (!isPlainObject(maybeCaps)) continue;\n const caps: Record<string, boolean> = {};\n for (const [key, flag] of Object.entries(maybeCaps)) {\n if (typeof flag === 'boolean') {\n caps[key] = flag;\n }\n }\n if (Object.keys(caps).length > 0) {\n out[namespace] = caps;\n }\n }\n\n return out;\n}\n\n/**\n * Merge an ordered list of contributor capability declarations into a base matrix.\n *\n * Behaviour:\n * - `base` and each contributor's `capabilities` are filtered through the same\n * structural extraction: non-plain-object namespace blocks are dropped,\n * non-boolean leaves inside a namespace block are dropped, and a namespace\n * block that ends up with zero boolean leaves is omitted entirely (so a\n * later contributor with a malformed namespace cannot erase a namespace\n * already present in `base`).\n * - Non-plain-object `capabilities` on a contributor (including `undefined`,\n * `null`, arrays, primitives) are skipped silently — the contributor\n * contributes nothing.\n * - Later contributors win on `(namespace, key)` collisions.\n * - The returned object is fresh — neither `base` nor any contributor is mutated.\n * - Output keys are sorted lexicographically at every plain-object level.\n */\nexport function mergeCapabilityMatrices(\n base: Record<string, Record<string, boolean>>,\n contributors: ReadonlyArray<{ readonly capabilities?: unknown }>,\n): Record<string, Record<string, boolean>> {\n const merged: CapabilityMatrix = extractCapabilityMatrix(base);\n\n for (const contributor of contributors) {\n const extracted = extractCapabilityMatrix(contributor.capabilities);\n for (const [namespace, capabilities] of Object.entries(extracted)) {\n merged[namespace] = {\n ...(merged[namespace] ?? {}),\n ...capabilities,\n };\n }\n }\n\n return blindCast<\n CapabilityMatrix,\n \"sortDeep preserves the matrix shape but the recursive generic relationship can't be expressed to TS\"\n >(sortDeep(merged));\n}\n"],"mappings":";;;;;;;;;;;AAaA,SAAS,cAAc,OAAkD;CACvE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,SAAS,OAAyB;CACzC,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,MAAM,IAAI,QAAQ;CAE3B,IAAI,CAAC,cAAc,KAAK,GACtB,OAAO;CAET,MAAM,UAAU,OAAO,QAAQ,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;CAC3E,MAAM,OAAgC,CAAC;CACvC,KAAK,MAAM,CAAC,KAAK,UAAU,SACzB,KAAK,OAAO,SAAS,KAAK;CAE5B,OAAO;AACT;AAEA,SAAS,wBAAwB,OAAkC;CACjE,IAAI,CAAC,cAAc,KAAK,GAAG,OAAO,CAAC;CAEnC,MAAM,MAAwB,CAAC;CAC/B,KAAK,MAAM,CAAC,WAAW,cAAc,OAAO,QAAQ,KAAK,GAAG;EAC1D,IAAI,CAAC,cAAc,SAAS,GAAG;EAC/B,MAAM,OAAgC,CAAC;EACvC,KAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,SAAS,GAChD,IAAI,OAAO,SAAS,WAClB,KAAK,OAAO;EAGhB,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,GAC7B,IAAI,aAAa;CAErB;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,wBACd,MACA,cACyC;CACzC,MAAM,SAA2B,wBAAwB,IAAI;CAE7D,KAAK,MAAM,eAAe,cAAc;EACtC,MAAM,YAAY,wBAAwB,YAAY,YAAY;EAClE,KAAK,MAAM,CAAC,WAAW,iBAAiB,OAAO,QAAQ,SAAS,GAC9D,OAAO,aAAa;GAClB,GAAI,OAAO,cAAc,CAAC;GAC1B,GAAG;EACL;CAEJ;CAEA,OAAO,UAGL,SAAS,MAAM,CAAC;AACpB"} |
| import { t as TypesImportSpec } from "./types-import-spec-DRKzrJ20.mjs"; | ||
| import { Contract, ContractModelBase } from "@prisma-next/contract/types"; | ||
| //#region src/control/emission-types.d.ts | ||
| interface GenerateContractTypesOptions { | ||
| readonly queryOperationTypeImports?: ReadonlyArray<TypesImportSpec>; | ||
| } | ||
| interface ValidationContext { | ||
| readonly codecTypeImports?: ReadonlyArray<TypesImportSpec>; | ||
| readonly extensionIds?: ReadonlyArray<string>; | ||
| } | ||
| interface EmissionSpi { | ||
| readonly id: string; | ||
| generateStorageType(contract: Contract, storageHashTypeName: string): string; | ||
| generateModelStorageType(modelName: string, model: ContractModelBase): string; | ||
| getFamilyImports(): string[]; | ||
| getFamilyTypeAliases(options?: GenerateContractTypesOptions): string; | ||
| getTypeMapsExpression(): string; | ||
| getContractWrapper(contractBaseName: string, typeMapsName: string): string; | ||
| /** | ||
| * Per-family resolver for typeParams that don't live inline on the | ||
| * framework-domain `ContractField`. Some families (notably SQL) let columns | ||
| * reference a named entry in `storage.types` via `typeRef`; the typeParams | ||
| * live on that named entry rather than on the domain field. The framework | ||
| * emit path consults this hook so the codec's `renderOutputType` can run | ||
| * for typeRef-shaped columns. | ||
| * | ||
| * Inline `field.type.typeParams` always takes precedence; the hook is only | ||
| * consulted when the domain field has no typeParams. Families without | ||
| * named storage types (e.g. mongo) don't implement this hook. | ||
| * | ||
| * Returns `undefined` when the field has no resolvable typeParams. | ||
| */ | ||
| resolveFieldTypeParams?(modelName: string, fieldName: string, model: ContractModelBase, contract: Contract): Record<string, unknown> | undefined; | ||
| } | ||
| //#endregion | ||
| export { GenerateContractTypesOptions as n, ValidationContext as r, EmissionSpi as t }; | ||
| //# sourceMappingURL=emission-types-C561PwcN.d.mts.map |
| {"version":3,"file":"emission-types-C561PwcN.d.mts","names":[],"sources":["../src/control/emission-types.ts"],"mappings":";;;;UAGiB,4BAAA;EAAA,SACN,yBAAA,GAA4B,aAAa,CAAC,eAAA;AAAA;AAAA,UAGpC,iBAAA;EAAA,SACN,gBAAA,GAAmB,aAAA,CAAc,eAAA;EAAA,SACjC,YAAA,GAAe,aAAA;AAAA;AAAA,UAGT,WAAA;EAAA,SACN,EAAA;EAET,mBAAA,CAAoB,QAAA,EAAU,QAAA,EAAU,mBAAA;EAExC,wBAAA,CAAyB,SAAA,UAAmB,KAAA,EAAO,iBAAA;EAEnD,gBAAA;EAEA,oBAAA,CAAqB,OAAA,GAAU,4BAAA;EAE/B,qBAAA;EAEA,kBAAA,CAAmB,gBAAA,UAA0B,YAAA;EAjBjB;;;;;;;;;;AACS;AAGvC;;;EA6BE,sBAAA,EACE,SAAA,UACA,SAAA,UACA,KAAA,EAAO,iBAAA,EACP,QAAA,EAAU,QAAA,GACT,MAAA;AAAA"} |
| import { r as CodecLookup } from "./codec-types-yY3eSmi0.mjs"; | ||
| import { ColumnDefault, ExecutionMutationDefaultPhases } from "@prisma-next/contract/types"; | ||
| import { Type } from "arktype"; | ||
| //#region src/shared/psl-extension-block.d.ts | ||
| /** | ||
| * Shape-only types for the PSL source-position primitives, diagnostic | ||
| * codes, extension-block descriptor vocabulary, and the uniform | ||
| * extension-block AST node base. | ||
| * | ||
| * These live in the shared plane so an extension's authoring descriptor | ||
| * (`AuthoringPslBlockDescriptor` in `framework-authoring`) can reference | ||
| * them without crossing the shared → migration-plane boundary. The | ||
| * migration-plane `psl-ast.ts` re-exports everything here for consumers | ||
| * that import PSL AST types from the control entrypoint. | ||
| */ | ||
| interface PslPosition { | ||
| readonly offset: number; | ||
| readonly line: number; | ||
| readonly column: number; | ||
| } | ||
| interface PslSpan { | ||
| readonly start: PslPosition; | ||
| readonly end: PslPosition; | ||
| } | ||
| type PslDiagnosticCode = 'PSL_UNTERMINATED_BLOCK' | 'PSL_UNSUPPORTED_TOP_LEVEL_BLOCK' | 'PSL_INVALID_NAMESPACE_BLOCK' | 'PSL_INVALID_ATTRIBUTE_SYNTAX' | 'PSL_INVALID_MODEL_MEMBER' | 'PSL_UNSUPPORTED_MODEL_ATTRIBUTE' | 'PSL_UNSUPPORTED_FIELD_ATTRIBUTE' | 'PSL_INVALID_RELATION_ATTRIBUTE' | 'PSL_INVALID_REFERENTIAL_ACTION' | 'PSL_INVALID_DEFAULT_VALUE' | 'PSL_INVALID_ENUM_MEMBER' | 'PSL_INVALID_TYPES_MEMBER' | 'PSL_INVALID_QUALIFIED_TYPE' | ||
| /** | ||
| * A qualified name (e.g. a dotted type or attribute reference) is structurally | ||
| * invalid, such as an over-qualified or trailing-separator name. | ||
| */ | ||
| | 'PSL_INVALID_QUALIFIED_NAME' | ||
| /** | ||
| * A reserved declaration keyword (`model`/`enum`/`namespace`/`type`) that | ||
| * committed the declaration kind on the keyword alone but is missing its name | ||
| * and/or opening brace. The recursive-descent parser produces a best-effort | ||
| * typed node for the malformed header and reports this code rather than | ||
| * `PSL_UNSUPPORTED_TOP_LEVEL_BLOCK`, which is reserved for a genuinely unknown | ||
| * top-level keyword. | ||
| */ | ||
| | 'PSL_INVALID_DECLARATION' | ||
| /** | ||
| * A malformed line inside an extension-contributed top-level block body, or | ||
| * a structurally invalid element inside a `list` parameter value. | ||
| * | ||
| * Replaces the overloaded `PSL_UNSUPPORTED_TOP_LEVEL_BLOCK` code that the | ||
| * generic framework parser previously used for these two parse-error sites | ||
| * inside extension blocks — keeping `PSL_UNSUPPORTED_TOP_LEVEL_BLOCK` for | ||
| * its original meaning (an unknown keyword at the top level) and giving | ||
| * extension-block parse errors their own code. | ||
| */ | ||
| | 'PSL_INVALID_EXTENSION_BLOCK_MEMBER' | ||
| /** | ||
| * A malformed JS-like object literal `{ key: value, … }` in value/argument | ||
| * position — a field missing its `:`, a field missing its value, or an | ||
| * unterminated `{`. The recursive-descent parser still produces a best-effort | ||
| * `ObjectLiteralExpr` node (preserving the lossless round-trip) and reports | ||
| * this code anchored on the offending token. | ||
| */ | ||
| | 'PSL_INVALID_OBJECT_LITERAL' | ||
| /** | ||
| * A string literal with no closing quote — the tokenizer stops the literal at | ||
| * a newline or at EOF when no terminating `"` is found, and the | ||
| * recursive-descent parser still consumes the token (preserving the lossless | ||
| * round-trip) but reports this code anchored on the string token's span. | ||
| */ | ||
| | 'PSL_UNTERMINATED_STRING' | ||
| /** | ||
| * An unknown parameter key in an extension-contributed block — a key present | ||
| * in the source block but absent from the descriptor's `parameters` map. | ||
| */ | ||
| | 'PSL_EXTENSION_UNKNOWN_PARAMETER' | ||
| /** | ||
| * A required parameter declared in the descriptor is absent from the parsed block. | ||
| */ | ||
| | 'PSL_EXTENSION_MISSING_REQUIRED_PARAMETER' | ||
| /** | ||
| * An `option`-kind parameter value is not one of the allowed tokens listed | ||
| * in the descriptor's `values` array. | ||
| */ | ||
| | 'PSL_EXTENSION_OPTION_OUT_OF_SET' | ||
| /** | ||
| * A `value`-kind parameter's raw text is not a valid JSON literal, or the | ||
| * parsed JSON value was rejected by the codec's `decodeJson` method, or the | ||
| * codec id is not registered in the lookup. | ||
| */ | ||
| | 'PSL_EXTENSION_INVALID_VALUE' | ||
| /** | ||
| * A `ref`-kind parameter identifier does not resolve to a declared entity of | ||
| * the required `refKind` within the declared scope. | ||
| */ | ||
| | 'PSL_EXTENSION_UNRESOLVED_REF' | ||
| /** | ||
| * A parameter key appears more than once in an extension block body. | ||
| * The first occurrence is kept; subsequent occurrences emit this diagnostic. | ||
| */ | ||
| | 'PSL_EXTENSION_DUPLICATE_PARAMETER' | ||
| /** | ||
| * A `@@`-prefixed block-attribute line inside an extension block has invalid syntax. | ||
| */ | ||
| | 'PSL_INVALID_EXTENSION_BLOCK_ATTRIBUTE'; | ||
| /** | ||
| * Descriptor vocabulary for a single parameter on a declared block. | ||
| * | ||
| * Four kinds: | ||
| * - `ref` — the parameter value is an identifier that must resolve to a | ||
| * declared entity of `refKind` within the declared `scope`. | ||
| * - `value` — the parameter value is a PSL literal parsed and printed | ||
| * through the codec identified by `codecId`. | ||
| * - `option` — the parameter value is one of the literal tokens in `values`. | ||
| * Not a codec; not persisted data. A closed authoring-time constraint only. | ||
| * - `list` — a bracketed list whose elements each match the `of` descriptor. | ||
| */ | ||
| type PslBlockParam = PslBlockParamRef | PslBlockParamValue | PslBlockParamOption | PslBlockParamList; | ||
| interface PslBlockParamRef { | ||
| readonly kind: 'ref'; | ||
| readonly refKind: string; | ||
| readonly scope: 'same-namespace' | 'same-space' | 'cross-space'; | ||
| readonly required?: boolean; | ||
| } | ||
| interface PslBlockParamValue { | ||
| readonly kind: 'value'; | ||
| readonly codecId: string; | ||
| readonly required?: boolean; | ||
| } | ||
| interface PslBlockParamOption { | ||
| readonly kind: 'option'; | ||
| readonly values: readonly string[]; | ||
| readonly required?: boolean; | ||
| } | ||
| interface PslBlockParamList { | ||
| readonly kind: 'list'; | ||
| readonly of: PslBlockParam; | ||
| readonly required?: boolean; | ||
| } | ||
| /** | ||
| * The parsed representation of a single parameter value on a uniform | ||
| * extension-block AST node. Mirrors the `PslBlockParam` descriptor | ||
| * vocabulary, plus `bare` for keyonly entries: | ||
| * | ||
| * - `ref` → `PslExtensionBlockParamRef` — a raw identifier string | ||
| * (resolution runs in the validator, not the parser). | ||
| * - `value` → `PslExtensionBlockParamScalarValue` — a raw PSL literal string | ||
| * (codec validation runs in the validator). | ||
| * - `option` → `PslExtensionBlockParamOption` — the chosen token. | ||
| * - `list` → `PslExtensionBlockParamList` — ordered list of the above. | ||
| * - `bare` → `PslExtensionBlockParamBare` — a bare identifier line with no | ||
| * `= value` (e.g. `Low` in an enum block). The name is the key in | ||
| * `parameters`; the interpreting consumer decides the default value. | ||
| * | ||
| * These shapes are intentionally minimal. The validator and lowering refine | ||
| * and consume them; the generic framework parser produces them. | ||
| */ | ||
| type PslExtensionBlockParamValue = PslExtensionBlockParamRef | PslExtensionBlockParamScalarValue | PslExtensionBlockParamOption | PslExtensionBlockParamList | PslExtensionBlockParamBare; | ||
| interface PslExtensionBlockParamRef { | ||
| readonly kind: 'ref'; | ||
| readonly identifier: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslExtensionBlockParamScalarValue { | ||
| readonly kind: 'value'; | ||
| readonly raw: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslExtensionBlockParamOption { | ||
| readonly kind: 'option'; | ||
| readonly token: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslExtensionBlockParamList { | ||
| readonly kind: 'list'; | ||
| readonly items: readonly PslExtensionBlockParamValue[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** | ||
| * A bare identifier line inside an extension block — a key with no `= value`. | ||
| * Emitted when a line matches `/^[A-Za-z_]\w*$/` with no assignment. The | ||
| * consumer decides what default value (if any) to apply. | ||
| */ | ||
| interface PslExtensionBlockParamBare { | ||
| readonly kind: 'bare'; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** | ||
| * A positional argument on a block attribute, e.g. the `"pg/text@1"` in | ||
| * `@@type("pg/text@1")`. | ||
| */ | ||
| interface PslExtensionBlockAttributeArg { | ||
| readonly kind: 'positional'; | ||
| readonly value: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** | ||
| * A `@@`-prefixed block-level attribute parsed inside an extension block, | ||
| * e.g. `@@type("pg/text@1")`. Block attributes are captured generically | ||
| * — the parser does not validate attribute names or argument shapes; that | ||
| * is a concern of the block's interpreter. | ||
| */ | ||
| interface PslExtensionBlockAttribute { | ||
| readonly name: string; | ||
| readonly args: readonly PslExtensionBlockAttributeArg[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** | ||
| * Base shape for a uniform extension-contributed top-level PSL block | ||
| * node, as produced by the generic framework parser and consumed by the | ||
| * validator and lowering factory. | ||
| * | ||
| * - `kind` is the routing discriminant, equal to the descriptor's | ||
| * `discriminator`. The framework parser sets this to | ||
| * `descriptor.discriminator` for every block it parses. | ||
| * - `name` is the block's declared name (the identifier after the keyword). | ||
| * - `parameters` is the descriptor-driven parameter map. Keys are | ||
| * parameter names from the descriptor; values are the parsed parameter | ||
| * representations. Only parameters present in the source are included | ||
| * — absence of a required parameter is a validator concern, not a | ||
| * parser concern. Insertion order is preserved; the first occurrence of a | ||
| * duplicate key is retained and subsequent occurrences emit | ||
| * `PSL_EXTENSION_DUPLICATE_PARAMETER`. | ||
| * - `blockAttributes` are `@@`-prefixed attribute lines inside the block, in | ||
| * declaration order. Captured generically — names and args are not validated | ||
| * by the parser. | ||
| * - `span` covers the full block from keyword to closing brace. | ||
| */ | ||
| interface PslExtensionBlock { | ||
| readonly kind: string; | ||
| readonly name: string; | ||
| readonly parameters: Record<string, PslExtensionBlockParamValue>; | ||
| readonly blockAttributes: readonly PslExtensionBlockAttribute[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| //#endregion | ||
| //#region src/shared/framework-authoring.d.ts | ||
| type AuthoringArgRef = { | ||
| readonly kind: 'arg'; | ||
| readonly index: number; | ||
| readonly path?: readonly string[]; | ||
| readonly default?: AuthoringTemplateValue; | ||
| }; | ||
| type AuthoringTemplateValue = string | number | boolean | null | AuthoringArgRef | readonly AuthoringTemplateValue[] | { | ||
| readonly [key: string]: AuthoringTemplateValue; | ||
| }; | ||
| interface AuthoringArgumentDescriptorCommon { | ||
| readonly name?: string; | ||
| readonly optional?: boolean; | ||
| } | ||
| type AuthoringArgumentDescriptor = AuthoringArgumentDescriptorCommon & ({ | ||
| readonly kind: 'string'; | ||
| } | { | ||
| readonly kind: 'boolean'; | ||
| } | { | ||
| readonly kind: 'number'; | ||
| readonly integer?: boolean; | ||
| readonly minimum?: number; | ||
| readonly maximum?: number; | ||
| } | { | ||
| readonly kind: 'stringArray'; | ||
| } | { | ||
| readonly kind: 'object'; | ||
| readonly properties: Record<string, AuthoringArgumentDescriptor>; | ||
| }); | ||
| interface AuthoringStorageTypeTemplate { | ||
| readonly codecId: string; | ||
| readonly nativeType: AuthoringTemplateValue; | ||
| readonly typeParams?: Record<string, AuthoringTemplateValue>; | ||
| } | ||
| interface AuthoringTypeConstructorDescriptor { | ||
| readonly kind: 'typeConstructor'; | ||
| readonly args?: readonly AuthoringArgumentDescriptor[]; | ||
| readonly output: AuthoringStorageTypeTemplate; | ||
| } | ||
| interface AuthoringColumnDefaultTemplateLiteral { | ||
| readonly kind: 'literal'; | ||
| readonly value: AuthoringTemplateValue; | ||
| } | ||
| interface AuthoringColumnDefaultTemplateFunction { | ||
| readonly kind: 'function'; | ||
| readonly expression: AuthoringTemplateValue; | ||
| } | ||
| type AuthoringColumnDefaultTemplate = AuthoringColumnDefaultTemplateLiteral | AuthoringColumnDefaultTemplateFunction; | ||
| interface AuthoringExecutionDefaultsTemplate { | ||
| readonly onCreate?: AuthoringTemplateValue; | ||
| readonly onUpdate?: AuthoringTemplateValue; | ||
| } | ||
| interface AuthoringFieldPresetOutput extends AuthoringStorageTypeTemplate { | ||
| readonly nullable?: boolean; | ||
| readonly default?: AuthoringColumnDefaultTemplate; | ||
| readonly executionDefaults?: AuthoringExecutionDefaultsTemplate; | ||
| readonly id?: boolean; | ||
| readonly unique?: boolean; | ||
| } | ||
| interface AuthoringFieldPresetDescriptor { | ||
| readonly kind: 'fieldPreset'; | ||
| readonly args?: readonly AuthoringArgumentDescriptor[]; | ||
| readonly output: AuthoringFieldPresetOutput; | ||
| } | ||
| type AuthoringTypeNamespace = { | ||
| readonly [name: string]: AuthoringTypeConstructorDescriptor | AuthoringTypeNamespace; | ||
| }; | ||
| type AuthoringFieldNamespace = { | ||
| readonly [name: string]: AuthoringFieldPresetDescriptor | AuthoringFieldNamespace; | ||
| }; | ||
| /** | ||
| * Context surfaced to entity-type factories at call time. Currently a | ||
| * placeholder — sharpened as concrete consumers (enum, namespace, …) | ||
| * discover what the factory actually needs to read (codec lookup, | ||
| * namespace registry, …). | ||
| */ | ||
| /** | ||
| * A write-only sink that a factory may push authoring-time diagnostics into. | ||
| * The concrete type pushed must be structurally compatible with whatever the | ||
| * consumer accumulates (typically `ContractSourceDiagnostic[]`); the framework | ||
| * layer deliberately does not depend on that concrete type. | ||
| */ | ||
| interface AuthoringDiagnosticSink { | ||
| push(d: { | ||
| readonly code: string; | ||
| readonly message: string; | ||
| readonly sourceId: string; | ||
| readonly span?: unknown; | ||
| }): void; | ||
| } | ||
| interface AuthoringEntityContext { | ||
| readonly family: string; | ||
| readonly target: string; | ||
| /** Codec registry available to factories that need to validate or decode values. */ | ||
| readonly codecLookup?: CodecLookup; | ||
| /** Source file identifier threaded into diagnostics emitted by the factory. */ | ||
| readonly sourceId?: string; | ||
| /** Push channel for authoring-time diagnostics emitted by the factory. */ | ||
| readonly diagnostics?: AuthoringDiagnosticSink; | ||
| } | ||
| interface AuthoringEntityTypeTemplateOutput { | ||
| readonly template: AuthoringTemplateValue; | ||
| } | ||
| /** | ||
| * Default `Input = never` is load-bearing for pack-bag-driven type | ||
| * narrowing. Factory parameter positions are contravariant, so a pack | ||
| * literal declaring `factory: (input: DemoEntityInput) => DemoEntity` | ||
| * is only assignable to the base descriptor's factory shape if the | ||
| * base's input is `never` (the bottom of the contravariant position). | ||
| * The concrete input/output types are recovered at the helper-derivation | ||
| * site via `EntityHelperFunction<Descriptor>`'s conditional inference, | ||
| * which reads them from the pack's `as const` literal factory signature | ||
| * — the base widening does not erase the literal because `satisfies` | ||
| * does not widen the declared type. | ||
| */ | ||
| interface AuthoringEntityTypeFactoryOutput<Input = never, Output = unknown> { | ||
| readonly factory: (input: Input, ctx: AuthoringEntityContext) => Output; | ||
| } | ||
| interface AuthoringEntityTypeDescriptor<Input = never, Output = unknown> { | ||
| readonly kind: 'entity'; | ||
| readonly discriminator: string; | ||
| readonly args?: readonly AuthoringArgumentDescriptor[]; | ||
| readonly output: AuthoringEntityTypeTemplateOutput | AuthoringEntityTypeFactoryOutput<Input, Output>; | ||
| /** | ||
| * arktype schema fragment for one entry whose envelope `kind` matches | ||
| * this descriptor's {@link discriminator}. The family validator composes | ||
| * contributed fragments into the per-namespace entry schema at | ||
| * validator construction time so the structural check covers | ||
| * pack-introduced kinds without the family core hard-coding the schema. | ||
| * | ||
| * Hydration uses {@link AuthoringEntityTypeFactoryOutput.factory} | ||
| * directly — the wire shape conforms structurally to the factory's | ||
| * `Input` after `validatorSchema` validates it. | ||
| */ | ||
| readonly validatorSchema?: Type<unknown>; | ||
| } | ||
| type AuthoringEntityTypeNamespace = { | ||
| readonly [name: string]: AuthoringEntityTypeDescriptor | AuthoringEntityTypeNamespace; | ||
| }; | ||
| /** | ||
| * Declarative descriptor for an extension-contributed top-level PSL block. | ||
| * | ||
| * An extension registers one of these per keyword it contributes. The | ||
| * framework owns the generic parser, validator, and printer — no | ||
| * parsing or printing code runs from the extension. | ||
| * | ||
| * - `keyword` is the PSL top-level identifier this descriptor claims | ||
| * (`policy_select`, `role`, …). | ||
| * - `discriminator` is the routing key used by the printer dispatch and | ||
| * the `entityTypes` lowering factory lookup. Convention: | ||
| * `<target-or-family>-<kind>` (`postgres-policy-select`). | ||
| * - `name.required` declares whether the block must have a name token | ||
| * after the keyword. Currently always `true` — anonymous blocks are | ||
| * not part of the closed-grammar premise — but the field is explicit | ||
| * so the type can evolve without a breaking change. | ||
| * - `parameters` maps parameter names to their value-kind descriptors | ||
| * (`ref` / `value` / `option` / `list`). The generic parser and | ||
| * validator interpret these; the extension supplies no parser or | ||
| * printer function. | ||
| */ | ||
| interface AuthoringPslBlockDescriptor { | ||
| readonly kind: 'pslBlock'; | ||
| readonly keyword: string; | ||
| readonly discriminator: string; | ||
| readonly name: { | ||
| readonly required: boolean; | ||
| }; | ||
| readonly parameters: Record<string, PslBlockParam>; | ||
| /** | ||
| * When `true`, the block body accepts a variadic tail of parameters beyond | ||
| * the declared set. The block body may contain: fields (model-style), | ||
| * `key = value` parameters, and `@@` attributes. With `variadicParameters`, | ||
| * bare identifiers (keys without a `= value`) and undeclared `key = value` | ||
| * pairs flow into the variadic tail — their semantics belong to the | ||
| * lowering, not the parser. | ||
| * | ||
| * A key that IS declared in `parameters` must still be supplied as | ||
| * `key = value`; a bare occurrence of a declared key is a diagnostic. | ||
| * | ||
| * When `false` (default), the validator emits `PSL_EXTENSION_UNKNOWN_PARAMETER` | ||
| * for keys absent from `parameters`. | ||
| */ | ||
| readonly variadicParameters?: boolean; | ||
| } | ||
| type AuthoringPslBlockDescriptorNamespace = { | ||
| readonly [name: string]: AuthoringPslBlockDescriptor | AuthoringPslBlockDescriptorNamespace; | ||
| }; | ||
| interface AuthoringContributions { | ||
| readonly type?: AuthoringTypeNamespace; | ||
| readonly field?: AuthoringFieldNamespace; | ||
| readonly entityTypes?: AuthoringEntityTypeNamespace; | ||
| /** | ||
| * Registry of declarative block descriptors this contribution registers, | ||
| * keyed by arbitrary path segments. Each leaf is an | ||
| * {@link AuthoringPslBlockDescriptor} that claims a PSL top-level keyword. | ||
| * The framework owns the generic parser, validator, and printer; the | ||
| * contribution supplies only these declarative descriptors. | ||
| * | ||
| * Contrast with the parsed block nodes themselves, which live in a | ||
| * namespace's `entries` under their discriminator key; this field holds the | ||
| * registry of descriptors that teach the parser how to read those blocks. | ||
| */ | ||
| readonly pslBlockDescriptors?: AuthoringPslBlockDescriptorNamespace; | ||
| } | ||
| declare function isAuthoringArgRef(value: unknown): value is AuthoringArgRef; | ||
| declare function isAuthoringTypeConstructorDescriptor(value: unknown): value is AuthoringTypeConstructorDescriptor; | ||
| declare function isAuthoringFieldPresetDescriptor(value: unknown): value is AuthoringFieldPresetDescriptor; | ||
| declare function isAuthoringEntityTypeDescriptor(value: unknown): value is AuthoringEntityTypeDescriptor; | ||
| declare function isAuthoringPslBlockDescriptor(value: unknown): value is AuthoringPslBlockDescriptor; | ||
| /** | ||
| * Returns true when `namespace` is a non-leaf key in `contributions.field`. | ||
| * | ||
| * `AuthoringFieldNamespace` permits a leaf descriptor at any depth — including | ||
| * the root — so a top-level `field: { Foo: { kind: 'fieldPreset', ... } }` | ||
| * registration must NOT be treated as a "namespace" with sub-paths. Callers | ||
| * use this predicate to gate dot-namespaced lookups (e.g. PSL `@Foo.bar`). | ||
| */ | ||
| declare function hasRegisteredFieldNamespace(contributions: AuthoringContributions | undefined, namespace: string): boolean; | ||
| /** | ||
| * Merges `source` into `target` recursively at the descriptor-namespace | ||
| * level. `isLeafDescriptor` decides which values are descriptors (terminal | ||
| * merge points; same-path registrations across components are reported | ||
| * as duplicates) versus sub-namespaces (recursion targets). | ||
| * | ||
| * Path segments are validated against prototype-pollution names | ||
| * (`__proto__`, `constructor`, `prototype`). A value that is neither a | ||
| * recognized leaf nor a plain object — e.g. a malformed descriptor | ||
| * where the canonical leaf guard rejected it for missing `output` — | ||
| * is reported as an invalid contribution rather than recursed into, | ||
| * which would either silently mangle state or infinite-loop on | ||
| * primitive properties. | ||
| * | ||
| * Within-registry duplicate detection is this walker's job; | ||
| * cross-registry detection runs separately via | ||
| * `assertNoCrossRegistryCollisions` after merging completes. | ||
| */ | ||
| declare function mergeAuthoringNamespaces(target: Record<string, unknown>, source: Record<string, unknown>, path: readonly string[], isLeafDescriptor: (value: unknown) => boolean, label: string): void; | ||
| declare function assertNoCrossRegistryCollisions(typeNamespace: AuthoringTypeNamespace, fieldNamespace: AuthoringFieldNamespace, entityTypeNamespace?: AuthoringEntityTypeNamespace, pslBlockNamespace?: AuthoringPslBlockDescriptorNamespace): void; | ||
| declare function resolveAuthoringTemplateValue(template: AuthoringTemplateValue, args: readonly unknown[]): unknown; | ||
| declare function validateAuthoringHelperArguments(helperPath: string, descriptors: readonly AuthoringArgumentDescriptor[] | undefined, args: readonly unknown[]): void; | ||
| declare function instantiateAuthoringTypeConstructor(descriptor: AuthoringTypeConstructorDescriptor, args: readonly unknown[]): { | ||
| readonly codecId: string; | ||
| readonly nativeType: string; | ||
| readonly typeParams?: Record<string, unknown>; | ||
| }; | ||
| declare function instantiateAuthoringEntityType(helperPath: string, descriptor: AuthoringEntityTypeDescriptor, args: readonly unknown[], ctx: AuthoringEntityContext): unknown; | ||
| declare function instantiateAuthoringFieldPreset(descriptor: AuthoringFieldPresetDescriptor, args: readonly unknown[]): { | ||
| readonly descriptor: { | ||
| readonly codecId: string; | ||
| readonly nativeType: string; | ||
| readonly typeParams?: Record<string, unknown>; | ||
| }; | ||
| readonly nullable: boolean; | ||
| readonly default?: ColumnDefault; | ||
| readonly executionDefaults?: ExecutionMutationDefaultPhases; | ||
| readonly id: boolean; | ||
| readonly unique: boolean; | ||
| }; | ||
| //#endregion | ||
| export { mergeAuthoringNamespaces as A, PslExtensionBlockAttribute as B, instantiateAuthoringFieldPreset as C, isAuthoringFieldPresetDescriptor as D, isAuthoringEntityTypeDescriptor as E, PslBlockParamOption as F, PslExtensionBlockParamRef as G, PslExtensionBlockParamBare as H, PslBlockParamRef as I, PslPosition as J, PslExtensionBlockParamScalarValue as K, PslBlockParamValue as L, validateAuthoringHelperArguments as M, PslBlockParam as N, isAuthoringPslBlockDescriptor as O, PslBlockParamList as P, PslDiagnosticCode as R, instantiateAuthoringEntityType as S, isAuthoringArgRef as T, PslExtensionBlockParamList as U, PslExtensionBlockAttributeArg as V, PslExtensionBlockParamOption as W, PslSpan as Y, AuthoringTemplateValue as _, AuthoringDiagnosticSink as a, assertNoCrossRegistryCollisions as b, AuthoringEntityTypeFactoryOutput as c, AuthoringFieldNamespace as d, AuthoringFieldPresetDescriptor as f, AuthoringStorageTypeTemplate as g, AuthoringPslBlockDescriptorNamespace as h, AuthoringContributions as i, resolveAuthoringTemplateValue as j, isAuthoringTypeConstructorDescriptor as k, AuthoringEntityTypeNamespace as l, AuthoringPslBlockDescriptor as m, AuthoringArgumentDescriptor as n, AuthoringEntityContext as o, AuthoringFieldPresetOutput as p, PslExtensionBlockParamValue as q, AuthoringColumnDefaultTemplate as r, AuthoringEntityTypeDescriptor as s, AuthoringArgRef as t, AuthoringEntityTypeTemplateOutput as u, AuthoringTypeConstructorDescriptor as v, instantiateAuthoringTypeConstructor as w, hasRegisteredFieldNamespace as x, AuthoringTypeNamespace as y, PslExtensionBlock as z }; | ||
| //# sourceMappingURL=framework-authoring-CJC4jwGo.d.mts.map |
| {"version":3,"file":"framework-authoring-CJC4jwGo.d.mts","names":[],"sources":["../src/shared/psl-extension-block.ts","../src/shared/framework-authoring.ts"],"mappings":";;;;;;;;;;AAYA;;;;;;UAAiB,WAAA;EAAA,SACN,MAAA;EAAA,SACA,IAAA;EAAA,SACA,MAAA;AAAA;AAAA,UAGM,OAAA;EAAA,SACN,KAAA,EAAO,WAAA;EAAA,SACP,GAAA,EAAK,WAAW;AAAA;AAAA,KAGf,iBAAA;;;AAHe;AAG3B;;;;AAA6B;AAqG7B;;;;;;;;;;;;;;AAIqB;AAErB;;;;;;;;;;AAOA;;;;;;AAAA;;AAGmB;AAGnB;;;;;;;;AAGmB;AAGnB;;;;;;;;;AAGmB;AAqBnB;;;AArBmB;;;;;;;;;;;;;AA0BW;AAE9B;;;;;;;;KAxDY,aAAA,GACR,gBAAA,GACA,kBAAA,GACA,mBAAA,GACA,iBAAA;AAAA,UAEa,gBAAA;EAAA,SACN,IAAA;EAAA,SACA,OAAA;EAAA,SACA,KAAA;EAAA,SACA,QAAA;AAAA;AAAA,UAGM,kBAAA;EAAA,SACN,IAAA;EAAA,SACA,OAAA;EAAA,SACA,QAAA;AAAA;AAAA,UAGM,mBAAA;EAAA,SACN,IAAA;EAAA,SACA,MAAA;EAAA,SACA,QAAA;AAAA;AAAA,UAGM,iBAAA;EAAA,SACN,IAAA;EAAA,SACA,EAAA,EAAI,aAAa;EAAA,SACjB,QAAA;AAAA;AA8CX;;;;;;;;;;AAGwB;AAQxB;;;;;;;AAXA,KAzBY,2BAAA,GACR,yBAAA,GACA,iCAAA,GACA,4BAAA,GACA,0BAAA,GACA,0BAAA;AAAA,UAEa,yBAAA;EAAA,SACN,IAAA;EAAA,SACA,UAAA;EAAA,SACA,IAAA,EAAM,OAAO;AAAA;AAAA,UAGP,iCAAA;EAAA,SACN,IAAA;EAAA,SACA,GAAA;EAAA,SACA,IAAA,EAAM,OAAO;AAAA;AAAA,UAGP,4BAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA;EAAA,SACA,IAAA,EAAM,OAAO;AAAA;AAAA,UAGP,0BAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA,WAAgB,2BAAA;EAAA,SAChB,IAAA,EAAM,OAAO;AAAA;;AAgCA;AAwBxB;;;UAhDiB,0BAAA;EAAA,SACN,IAAA;EAAA,SACA,IAAA,EAAM,OAAO;AAAA;;;;;UAOP,6BAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA;EAAA,SACA,IAAA,EAAM,OAAO;AAAA;;;;AAyCA;;;UAhCP,0BAAA;EAAA,SACN,IAAA;EAAA,SACA,IAAA,WAAe,6BAAA;EAAA,SACf,IAAA,EAAM,OAAO;AAAA;;;;;;;ACtNmB;AAG3C;;;;;;;;;;;;;AAOoD;UDoOnC,iBAAA;EAAA,SACN,IAAA;EAAA,SACA,IAAA;EAAA,SACA,UAAA,EAAY,MAAA,SAAe,2BAAA;EAAA,SAC3B,eAAA,WAA0B,0BAAA;EAAA,SAC1B,IAAA,EAAM,OAAA;AAAA;;;KCvPL,eAAA;EAAA,SACD,IAAA;EAAA,SACA,KAAA;EAAA,SACA,IAAA;EAAA,SACA,OAAA,GAAU,sBAAsB;AAAA;AAAA,KAG/B,sBAAA,sCAKR,eAAA,YACS,sBAAA;EAAA,UACG,GAAA,WAAc,sBAAA;AAAA;AAAA,UAEpB,iCAAA;EAAA,SACC,IAAA;EAAA,SACA,QAAQ;AAAA;AAAA,KAGP,2BAAA,GAA8B,iCAAA;EAAA,SAEzB,IAAA;AAAA;EAAA,SACA,IAAA;AAAA;EAAA,SAEA,IAAA;EAAA,SACA,OAAA;EAAA,SACA,OAAA;EAAA,SACA,OAAA;AAAA;EAAA,SAEA,IAAA;AAAA;EAAA,SAEA,IAAA;EAAA,SACA,UAAA,EAAY,MAAA,SAAe,2BAAA;AAAA;AAAA,UAI3B,4BAAA;EAAA,SACN,OAAA;EAAA,SACA,UAAA,EAAY,sBAAA;EAAA,SACZ,UAAA,GAAa,MAAA,SAAe,sBAAA;AAAA;AAAA,UAGtB,kCAAA;EAAA,SACN,IAAA;EAAA,SACA,IAAA,YAAgB,2BAAA;EAAA,SAChB,MAAA,EAAQ,4BAA4B;AAAA;AAAA,UAG9B,qCAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA,EAAO,sBAAsB;AAAA;AAAA,UAGvB,sCAAA;EAAA,SACN,IAAA;EAAA,SACA,UAAA,EAAY,sBAAsB;AAAA;AAAA,KAGjC,8BAAA,GACR,qCAAA,GACA,sCAAsC;AAAA,UAEzB,kCAAA;EAAA,SACN,QAAA,GAAW,sBAAA;EAAA,SACX,QAAA,GAAW,sBAAsB;AAAA;AAAA,UAG3B,0BAAA,SAAmC,4BAAA;EAAA,SACzC,QAAA;EAAA,SACA,OAAA,GAAU,8BAAA;EAAA,SACV,iBAAA,GAAoB,kCAAA;EAAA,SACpB,EAAA;EAAA,SACA,MAAA;AAAA;AAAA,UAGM,8BAAA;EAAA,SACN,IAAA;EAAA,SACA,IAAA,YAAgB,2BAAA;EAAA,SAChB,MAAA,EAAQ,0BAA0B;AAAA;AAAA,KAGjC,sBAAA;EAAA,UACA,IAAA,WAAe,kCAAA,GAAqC,sBAAsB;AAAA;AAAA,KAG1E,uBAAA;EAAA,UACA,IAAA,WAAe,8BAAA,GAAiC,uBAAuB;AAAA;;;;;;;;;ADiDhE;AAqBnB;;;UCvDiB,uBAAA;EACf,IAAA,CAAK,CAAA;IAAA,SACM,IAAA;IAAA,SACA,OAAA;IAAA,SACA,QAAA;IAAA,SACA,IAAA;EAAA;AAAA;AAAA,UAII,sBAAA;EAAA,SACN,MAAA;EAAA,SACA,MAAA;EDiDP;EAAA,SC/CO,WAAA,GAAc,WAAA;ED+CK;EAAA,SC7CnB,QAAA;ED+C+B;EAAA,SC7C/B,WAAA,GAAc,uBAAuB;AAAA;AAAA,UAG/B,iCAAA;EAAA,SACN,QAAA,EAAU,sBAAsB;AAAA;;;AD4CnB;AAGxB;;;;;;;;;UChCiB,gCAAA;EAAA,SACN,OAAA,GAAU,KAAA,EAAO,KAAA,EAAO,GAAA,EAAK,sBAAA,KAA2B,MAAA;AAAA;AAAA,UAGlD,6BAAA;EAAA,SACN,IAAA;EAAA,SACA,aAAA;EAAA,SACA,IAAA,YAAgB,2BAAA;EAAA,SAChB,MAAA,EACL,iCAAA,GACA,gCAAA,CAAiC,KAAA,EAAO,MAAA;ED+B7B;;AAAO;AAGxB;;;;;;;;EAHiB,SCnBN,eAAA,GAAkB,IAAA;AAAA;AAAA,KAGjB,4BAAA;EAAA,UACA,IAAA,WAAe,6BAAA,GAAgC,4BAA4B;AAAA;;;;;;;AD+B/D;AAOxB;;;;;;;;;AAGwB;AASxB;;;;UC1BiB,2BAAA;EAAA,SACN,IAAA;EAAA,SACA,OAAA;EAAA,SACA,aAAA;EAAA,SACA,IAAA;IAAA,SAAiB,QAAA;EAAA;EAAA,SACjB,UAAA,EAAY,MAAM,SAAS,aAAA;EDgDJ;;;;;;;;;;;;;;EAAA,SCjCvB,kBAAA;AAAA;AAAA,KAGC,oCAAA;EAAA,UACA,IAAA,WAAe,2BAAA,GAA8B,oCAAoC;AAAA;AAAA,UAG5E,sBAAA;EAAA,SACN,IAAA,GAAO,sBAAA;EAAA,SACP,KAAA,GAAQ,uBAAA;EAAA,SACR,WAAA,GAAc,4BAAA;EA3NE;;;;;;;;;AAIgB;AAG3C;EAP2B,SAuOhB,mBAAA,GAAsB,oCAAA;AAAA;AAAA,iBAGjB,iBAAA,CAAkB,KAAA,YAAiB,KAAA,IAAS,eAAe;AAAA,iBAkB3D,oCAAA,CACd,KAAA,YACC,KAAA,IAAS,kCAAkC;AAAA,iBAU9B,gCAAA,CACd,KAAA,YACC,KAAA,IAAS,8BAA8B;AAAA,iBAU1B,+BAAA,CACd,KAAA,YACC,KAAA,IAAS,6BAA6B;AAAA,iBAqBzB,6BAAA,CACd,KAAA,YACC,KAAA,IAAS,2BAA2B;;;;;;AA/Ra;AAAG;;iBAyUvC,2BAAA,CACd,aAAA,EAAe,sBAAsB,cACrC,SAAA;;AAvUiB;AAGnB;;;;;;;;;;;;;;;;iBAkXgB,wBAAA,CACd,MAAA,EAAQ,MAAA,mBACR,MAAA,EAAQ,MAAM,mBACd,IAAA,qBACA,gBAAA,GAAmB,KAAA,uBACnB,KAAA;AAAA,iBAsNc,+BAAA,CACd,aAAA,EAAe,sBAAA,EACf,cAAA,EAAgB,uBAAA,EAChB,mBAAA,GAAqB,4BAAA,EACrB,iBAAA,GAAmB,oCAAA;AAAA,iBA6CL,6BAAA,CACd,QAAA,EAAU,sBAAsB,EAChC,IAAA;AAAA,iBAiHc,gCAAA,CACd,UAAA,UACA,WAAA,WAAsB,2BAA2B,gBACjD,IAAA;AAAA,iBAmHc,mCAAA,CACd,UAAA,EAAY,kCAAA,EACZ,IAAA;EAAA,SAES,OAAA;EAAA,SACA,UAAA;EAAA,SACA,UAAA,GAAa,MAAM;AAAA;AAAA,iBAKd,8BAAA,CACd,UAAA,UACA,UAAA,EAAY,6BAAA,EACZ,IAAA,sBACA,GAAA,EAAK,sBAAsB;AAAA,iBA0Bb,+BAAA,CACd,UAAA,EAAY,8BAAA,EACZ,IAAA;EAAA,SAES,UAAA;IAAA,SACE,OAAA;IAAA,SACA,UAAA;IAAA,SACA,UAAA,GAAa,MAAA;EAAA;EAAA,SAEf,QAAA;EAAA,SACA,OAAA,GAAU,aAAA;EAAA,SACV,iBAAA,GAAoB,8BAAA;EAAA,SACpB,EAAA;EAAA,SACA,MAAA;AAAA"} |
| import { blindCast } from "@prisma-next/utils/casts"; | ||
| import { isColumnDefaultLiteralInputValue, isExecutionMutationDefaultValue } from "@prisma-next/contract/types"; | ||
| import { ifDefined } from "@prisma-next/utils/defined"; | ||
| //#region src/shared/framework-authoring.ts | ||
| function isAuthoringArgRef(value) { | ||
| if (typeof value !== "object" || value === null || value.kind !== "arg") return false; | ||
| const { index, path } = value; | ||
| if (typeof index !== "number" || !Number.isInteger(index) || index < 0) return false; | ||
| if (path !== void 0 && (!Array.isArray(path) || path.some((s) => typeof s !== "string"))) return false; | ||
| return true; | ||
| } | ||
| function isAuthoringTemplateRecord(value) { | ||
| return typeof value === "object" && value !== null && !Array.isArray(value); | ||
| } | ||
| function isAuthoringTypeConstructorDescriptor(value) { | ||
| return typeof value === "object" && value !== null && value.kind === "typeConstructor" && typeof value.output === "object" && value.output !== null; | ||
| } | ||
| function isAuthoringFieldPresetDescriptor(value) { | ||
| return typeof value === "object" && value !== null && value.kind === "fieldPreset" && typeof value.output === "object" && value.output !== null; | ||
| } | ||
| function isAuthoringEntityTypeDescriptor(value) { | ||
| if (typeof value !== "object" || value === null || value.kind !== "entity") return false; | ||
| const discriminator = value.discriminator; | ||
| if (typeof discriminator !== "string" || discriminator.length === 0) return false; | ||
| const output = value.output; | ||
| if (typeof output !== "object" || output === null) return false; | ||
| const factory = output.factory; | ||
| const template = output.template; | ||
| return typeof factory === "function" || template !== void 0; | ||
| } | ||
| function isAuthoringPslBlockDescriptor(value) { | ||
| if (typeof value !== "object" || value === null) return false; | ||
| const record = blindCast(value); | ||
| if (record["kind"] !== "pslBlock") return false; | ||
| const keyword = record["keyword"]; | ||
| if (typeof keyword !== "string" || keyword.length === 0) return false; | ||
| const discriminator = record["discriminator"]; | ||
| if (typeof discriminator !== "string" || discriminator.length === 0) return false; | ||
| const name = record["name"]; | ||
| if (typeof name !== "object" || name === null) return false; | ||
| if (typeof blindCast(name)["required"] !== "boolean") return false; | ||
| const parameters = record["parameters"]; | ||
| return typeof parameters === "object" && parameters !== null && !Array.isArray(parameters); | ||
| } | ||
| /** | ||
| * Returns true when `namespace` is a non-leaf key in `contributions.field`. | ||
| * | ||
| * `AuthoringFieldNamespace` permits a leaf descriptor at any depth — including | ||
| * the root — so a top-level `field: { Foo: { kind: 'fieldPreset', ... } }` | ||
| * registration must NOT be treated as a "namespace" with sub-paths. Callers | ||
| * use this predicate to gate dot-namespaced lookups (e.g. PSL `@Foo.bar`). | ||
| */ | ||
| function hasRegisteredFieldNamespace(contributions, namespace) { | ||
| if (contributions?.field === void 0 || !Object.hasOwn(contributions.field, namespace)) return false; | ||
| return !isAuthoringFieldPresetDescriptor(contributions.field[namespace]); | ||
| } | ||
| function isCopyableNamespaceObject(value) { | ||
| if (typeof value !== "object" || value === null || Array.isArray(value)) return false; | ||
| const proto = Object.getPrototypeOf(value); | ||
| return proto === Object.prototype || proto === null; | ||
| } | ||
| function deepCopyNamespace(source, isLeafDescriptor) { | ||
| const copy = {}; | ||
| for (const [key, value] of Object.entries(source)) copy[key] = isCopyableNamespaceObject(value) && !isLeafDescriptor(value) ? deepCopyNamespace(value, isLeafDescriptor) : value; | ||
| return copy; | ||
| } | ||
| /** | ||
| * Merges `source` into `target` recursively at the descriptor-namespace | ||
| * level. `isLeafDescriptor` decides which values are descriptors (terminal | ||
| * merge points; same-path registrations across components are reported | ||
| * as duplicates) versus sub-namespaces (recursion targets). | ||
| * | ||
| * Path segments are validated against prototype-pollution names | ||
| * (`__proto__`, `constructor`, `prototype`). A value that is neither a | ||
| * recognized leaf nor a plain object — e.g. a malformed descriptor | ||
| * where the canonical leaf guard rejected it for missing `output` — | ||
| * is reported as an invalid contribution rather than recursed into, | ||
| * which would either silently mangle state or infinite-loop on | ||
| * primitive properties. | ||
| * | ||
| * Within-registry duplicate detection is this walker's job; | ||
| * cross-registry detection runs separately via | ||
| * `assertNoCrossRegistryCollisions` after merging completes. | ||
| */ | ||
| function mergeAuthoringNamespaces(target, source, path, isLeafDescriptor, label) { | ||
| const assertSafePath = (currentPath) => { | ||
| const blockedSegment = currentPath.find((segment) => segment === "__proto__" || segment === "constructor" || segment === "prototype"); | ||
| if (blockedSegment) throw new Error(`Invalid authoring ${label} helper "${currentPath.join(".")}". Helper path segments must not use "${blockedSegment}".`); | ||
| }; | ||
| for (const [key, sourceValue] of Object.entries(source)) { | ||
| const currentPath = [...path, key]; | ||
| assertSafePath(currentPath); | ||
| const hasExistingValue = Object.hasOwn(target, key); | ||
| const existingValue = hasExistingValue ? target[key] : void 0; | ||
| if (!hasExistingValue) { | ||
| target[key] = isCopyableNamespaceObject(sourceValue) && !isLeafDescriptor(sourceValue) ? deepCopyNamespace(sourceValue, isLeafDescriptor) : sourceValue; | ||
| continue; | ||
| } | ||
| const existingIsLeaf = isLeafDescriptor(existingValue); | ||
| const sourceIsLeaf = isLeafDescriptor(sourceValue); | ||
| if (existingIsLeaf || sourceIsLeaf) throw new Error(`Duplicate authoring ${label} helper "${currentPath.join(".")}". Helper names must be unique across composed packs.`); | ||
| if (!isCopyableNamespaceObject(existingValue) || !isCopyableNamespaceObject(sourceValue)) throw new Error(`Invalid authoring ${label} helper "${currentPath.join(".")}". Expected a sub-namespace object or a recognized descriptor; received a malformed value.`); | ||
| mergeAuthoringNamespaces(existingValue, sourceValue, currentPath, isLeafDescriptor, label); | ||
| } | ||
| } | ||
| function collectDescriptorPaths(namespace, isLeaf, path = []) { | ||
| const paths = []; | ||
| for (const [key, value] of Object.entries(namespace)) { | ||
| const currentPath = [...path, key]; | ||
| if (isLeaf(value)) { | ||
| paths.push(currentPath.join(".")); | ||
| continue; | ||
| } | ||
| if (typeof value === "object" && value !== null && !Array.isArray(value)) paths.push(...collectDescriptorPaths(value, isLeaf, currentPath)); | ||
| } | ||
| return paths; | ||
| } | ||
| function collectDescriptorEntries(namespace, isLeaf, label, path = []) { | ||
| const entries = []; | ||
| for (const [key, value] of Object.entries(namespace)) { | ||
| const currentPath = [...path, key]; | ||
| if (isLeaf(value)) { | ||
| const discriminator = blindCast(value)["discriminator"]; | ||
| if (typeof discriminator === "string" && discriminator.length > 0) entries.push({ | ||
| path: currentPath.join("."), | ||
| discriminator | ||
| }); | ||
| continue; | ||
| } | ||
| if (typeof value === "object" && value !== null && !Array.isArray(value)) { | ||
| const record = blindCast(value); | ||
| if ((record["kind"] !== void 0 || record["keyword"] !== void 0 || record["discriminator"] !== void 0) && !isLeaf(value)) { | ||
| const hasKind = record["kind"] === "pslBlock"; | ||
| const hasKeyword = typeof record["keyword"] === "string"; | ||
| const hasDiscriminator = typeof record["discriminator"] === "string"; | ||
| if (hasKind || hasKeyword && hasDiscriminator) throw new Error(`Malformed authoring ${label} contribution at "${currentPath.join(".")}". The value carries descriptor keys (kind/keyword/discriminator) but does not satisfy the ${label} descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`); | ||
| } | ||
| entries.push(...collectDescriptorEntries(record, isLeaf, label, currentPath)); | ||
| } | ||
| } | ||
| return entries; | ||
| } | ||
| /** | ||
| * Throws when two or more entries in the same namespace share a discriminator. | ||
| * Duplicate discriminators within a namespace make dispatch ambiguous — the | ||
| * lowering factory lookup dispatches by discriminator, so one would silently | ||
| * shadow the other. Catch duplicates before building any dispatch map. | ||
| */ | ||
| function assertUniqueDiscriminators(entries, label) { | ||
| const seen = /* @__PURE__ */ new Map(); | ||
| for (const { path, discriminator } of entries) { | ||
| const existing = seen.get(discriminator); | ||
| if (existing !== void 0) throw new Error(`Duplicate ${label} discriminator "${discriminator}" registered at both "${existing}" and "${path}". Each ${label} contribution must use a unique discriminator.`); | ||
| seen.set(discriminator, path); | ||
| } | ||
| } | ||
| function collectPslBlockDescriptorEntries(namespace, path = []) { | ||
| const entries = []; | ||
| for (const [key, value] of Object.entries(namespace)) { | ||
| const currentPath = [...path, key]; | ||
| if (isAuthoringPslBlockDescriptor(value)) { | ||
| entries.push({ | ||
| path: currentPath.join("."), | ||
| discriminator: value.discriminator | ||
| }); | ||
| continue; | ||
| } | ||
| if (typeof value === "object" && value !== null && !Array.isArray(value)) { | ||
| const record = blindCast(value); | ||
| const hasKind = record["kind"] === "pslBlock"; | ||
| const hasKeyword = typeof record["keyword"] === "string"; | ||
| const hasDiscriminator = typeof record["discriminator"] === "string"; | ||
| if (hasKind || hasKeyword && hasDiscriminator) throw new Error(`Malformed authoring pslBlock contribution at "${currentPath.join(".")}". The value carries descriptor keys (kind/keyword/discriminator) but does not satisfy the pslBlock descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`); | ||
| entries.push(...collectPslBlockDescriptorEntries(record, currentPath)); | ||
| } | ||
| } | ||
| return entries; | ||
| } | ||
| /** | ||
| * Every `pslBlockDescriptors` entry requires a matching `entityTypes` factory | ||
| * with the same discriminator. An `entityTypes` factory may stand alone (e.g. | ||
| * `enum`, reachable from the TypeScript builder without any PSL block). | ||
| */ | ||
| function assertPslBlocksHaveFactories(entityTypeNamespace, pslBlockNamespace) { | ||
| const blockEntries = collectPslBlockDescriptorEntries(pslBlockNamespace); | ||
| const entityEntries = collectDescriptorEntries(entityTypeNamespace, isAuthoringEntityTypeDescriptor, "entityType"); | ||
| assertUniqueDiscriminators(blockEntries, "pslBlock"); | ||
| assertUniqueDiscriminators(entityEntries, "entityType"); | ||
| const entityDiscriminators = new Set(entityEntries.map((entry) => entry.discriminator)); | ||
| for (const block of blockEntries) if (!entityDiscriminators.has(block.discriminator)) throw new Error(`Incomplete extension contribution: pslBlock helper "${block.path}" registers discriminator "${block.discriminator}" but no entityType contribution shares that discriminator. An extension-contributed PSL block requires a matching entityType factory so the parsed AST node can lower to an IR class instance; add an entityType helper with discriminator "${block.discriminator}".`); | ||
| } | ||
| function assertNoCrossRegistryCollisions(typeNamespace, fieldNamespace, entityTypeNamespace = {}, pslBlockNamespace = {}) { | ||
| const typePaths = new Set(collectDescriptorPaths(typeNamespace, isAuthoringTypeConstructorDescriptor)); | ||
| const fieldPaths = new Set(collectDescriptorPaths(fieldNamespace, isAuthoringFieldPresetDescriptor)); | ||
| const entityPaths = new Set(collectDescriptorPaths(entityTypeNamespace, isAuthoringEntityTypeDescriptor)); | ||
| const ambiguityHint = "Register each path in only one of authoringContributions.field / authoringContributions.type / authoringContributions.entityTypes."; | ||
| for (const fieldPath of fieldPaths) if (typePaths.has(fieldPath)) throw new Error(`Ambiguous authoring registry path "${fieldPath}". The same path is registered as both a type constructor and a field preset; PSL resolution would be ambiguous. ${ambiguityHint}`); | ||
| for (const entityPath of entityPaths) if (typePaths.has(entityPath) || fieldPaths.has(entityPath)) throw new Error(`Ambiguous authoring registry path "${entityPath}". The same path is registered as an entity contribution AND as a type constructor or field preset; PSL resolution would be ambiguous. ${ambiguityHint}`); | ||
| assertPslBlocksHaveFactories(entityTypeNamespace, pslBlockNamespace); | ||
| } | ||
| function resolveAuthoringTemplateValue(template, args) { | ||
| if (isAuthoringArgRef(template)) { | ||
| let value = args[template.index]; | ||
| for (const segment of template.path ?? []) { | ||
| if (!isAuthoringTemplateRecord(value) || !Object.hasOwn(value, segment)) { | ||
| value = void 0; | ||
| break; | ||
| } | ||
| value = value[segment]; | ||
| } | ||
| if (value === void 0 && template.default !== void 0) return resolveAuthoringTemplateValue(template.default, args); | ||
| return value; | ||
| } | ||
| if (Array.isArray(template)) return template.map((value) => resolveAuthoringTemplateValue(value, args)); | ||
| if (typeof template === "object" && template !== null) { | ||
| const resolved = {}; | ||
| for (const [key, value] of Object.entries(template)) { | ||
| const resolvedValue = resolveAuthoringTemplateValue(value, args); | ||
| if (resolvedValue !== void 0) resolved[key] = resolvedValue; | ||
| } | ||
| return resolved; | ||
| } | ||
| return template; | ||
| } | ||
| function validateAuthoringArgument(descriptor, value, path) { | ||
| if (value === void 0) { | ||
| if (descriptor.optional) return; | ||
| throw new Error(`Missing required authoring helper argument at ${path}`); | ||
| } | ||
| if (descriptor.kind === "string") { | ||
| if (typeof value !== "string") throw new Error(`Authoring helper argument at ${path} must be a string`); | ||
| return; | ||
| } | ||
| if (descriptor.kind === "boolean") { | ||
| if (typeof value !== "boolean") throw new Error(`Authoring helper argument at ${path} must be a boolean`); | ||
| return; | ||
| } | ||
| if (descriptor.kind === "stringArray") { | ||
| if (!Array.isArray(value)) throw new Error(`Authoring helper argument at ${path} must be an array of strings`); | ||
| for (const entry of value) if (typeof entry !== "string") throw new Error(`Authoring helper argument at ${path} must be an array of strings`); | ||
| return; | ||
| } | ||
| if (descriptor.kind === "object") { | ||
| if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`Authoring helper argument at ${path} must be an object`); | ||
| const input = value; | ||
| const expectedKeys = new Set(Object.keys(descriptor.properties)); | ||
| for (const key of Object.keys(input)) if (!expectedKeys.has(key)) throw new Error(`Authoring helper argument at ${path} contains unknown property "${key}"`); | ||
| for (const [key, propertyDescriptor] of Object.entries(descriptor.properties)) validateAuthoringArgument(propertyDescriptor, input[key], `${path}.${key}`); | ||
| return; | ||
| } | ||
| if (typeof value !== "number" || Number.isNaN(value)) throw new Error(`Authoring helper argument at ${path} must be a number`); | ||
| if (descriptor.integer && !Number.isInteger(value)) throw new Error(`Authoring helper argument at ${path} must be an integer`); | ||
| if (descriptor.minimum !== void 0 && value < descriptor.minimum) throw new Error(`Authoring helper argument at ${path} must be >= ${descriptor.minimum}, received ${value}`); | ||
| if (descriptor.maximum !== void 0 && value > descriptor.maximum) throw new Error(`Authoring helper argument at ${path} must be <= ${descriptor.maximum}, received ${value}`); | ||
| } | ||
| function validateAuthoringHelperArguments(helperPath, descriptors, args) { | ||
| const expected = descriptors ?? []; | ||
| const minimumArgs = expected.reduce((count, descriptor, index) => descriptor.optional ? count : index + 1, 0); | ||
| if (args.length < minimumArgs || args.length > expected.length) throw new Error(`${helperPath} expects ${minimumArgs === expected.length ? expected.length : `${minimumArgs}-${expected.length}`} argument(s), received ${args.length}`); | ||
| expected.forEach((descriptor, index) => { | ||
| validateAuthoringArgument(descriptor, args[index], `${helperPath}[${index}]`); | ||
| }); | ||
| } | ||
| function resolveAuthoringStorageTypeTemplate(template, args) { | ||
| const nativeType = resolveAuthoringTemplateValue(template.nativeType, args); | ||
| if (typeof nativeType !== "string") throw new Error(`Resolved authoring nativeType must be a string for codec "${template.codecId}", received ${String(nativeType)}`); | ||
| const typeParams = template.typeParams === void 0 ? void 0 : resolveAuthoringTemplateValue(template.typeParams, args); | ||
| if (typeParams !== void 0 && !isAuthoringTemplateRecord(typeParams)) throw new Error(`Resolved authoring typeParams must be an object for codec "${template.codecId}", received ${String(typeParams)}`); | ||
| return { | ||
| codecId: template.codecId, | ||
| nativeType, | ||
| ...typeParams === void 0 ? {} : { typeParams } | ||
| }; | ||
| } | ||
| function resolveAuthoringColumnDefaultTemplate(template, args) { | ||
| if (template.kind === "literal") { | ||
| const value = resolveAuthoringTemplateValue(template.value, args); | ||
| if (value === void 0) throw new Error("Resolved authoring literal default must not be undefined"); | ||
| if (!isColumnDefaultLiteralInputValue(value)) throw new Error(`Resolved authoring literal default must be a JSON-serializable value or Date, received ${String(value)}`); | ||
| return { | ||
| kind: "literal", | ||
| value | ||
| }; | ||
| } | ||
| const expression = resolveAuthoringTemplateValue(template.expression, args); | ||
| if (expression === void 0 || typeof expression === "object" && expression !== null) throw new Error(`Resolved authoring function default expression must resolve to a primitive, received ${String(expression)}`); | ||
| return { | ||
| kind: "function", | ||
| expression: String(expression) | ||
| }; | ||
| } | ||
| function resolveExecutionMutationDefaultPhase(phase, template, args) { | ||
| const value = resolveAuthoringTemplateValue(template, args); | ||
| if (!isExecutionMutationDefaultValue(value)) throw new Error(`Authoring preset executionDefaults.${phase} did not resolve to a valid generator descriptor (kind: 'generator', id: string).`); | ||
| return value; | ||
| } | ||
| function resolveAuthoringExecutionDefaultsTemplate(template, args) { | ||
| return { | ||
| ...ifDefined("onCreate", template.onCreate !== void 0 ? resolveExecutionMutationDefaultPhase("onCreate", template.onCreate, args) : void 0), | ||
| ...ifDefined("onUpdate", template.onUpdate !== void 0 ? resolveExecutionMutationDefaultPhase("onUpdate", template.onUpdate, args) : void 0) | ||
| }; | ||
| } | ||
| function instantiateAuthoringTypeConstructor(descriptor, args) { | ||
| return resolveAuthoringStorageTypeTemplate(descriptor.output, args); | ||
| } | ||
| function instantiateAuthoringEntityType(helperPath, descriptor, args, ctx) { | ||
| if ("factory" in descriptor.output) { | ||
| const input = args[0]; | ||
| const factory = descriptor.output.factory; | ||
| return factory(input, ctx); | ||
| } | ||
| validateAuthoringHelperArguments(helperPath, descriptor.args, args); | ||
| return resolveAuthoringTemplateValue(descriptor.output.template, args); | ||
| } | ||
| function instantiateAuthoringFieldPreset(descriptor, args) { | ||
| return { | ||
| descriptor: resolveAuthoringStorageTypeTemplate(descriptor.output, args), | ||
| nullable: descriptor.output.nullable ?? false, | ||
| ...ifDefined("default", descriptor.output.default !== void 0 ? resolveAuthoringColumnDefaultTemplate(descriptor.output.default, args) : void 0), | ||
| ...ifDefined("executionDefaults", descriptor.output.executionDefaults !== void 0 ? resolveAuthoringExecutionDefaultsTemplate(descriptor.output.executionDefaults, args) : void 0), | ||
| id: descriptor.output.id ?? false, | ||
| unique: descriptor.output.unique ?? false | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { instantiateAuthoringTypeConstructor as a, isAuthoringFieldPresetDescriptor as c, mergeAuthoringNamespaces as d, resolveAuthoringTemplateValue as f, instantiateAuthoringFieldPreset as i, isAuthoringPslBlockDescriptor as l, hasRegisteredFieldNamespace as n, isAuthoringArgRef as o, validateAuthoringHelperArguments as p, instantiateAuthoringEntityType as r, isAuthoringEntityTypeDescriptor as s, assertNoCrossRegistryCollisions as t, isAuthoringTypeConstructorDescriptor as u }; | ||
| //# sourceMappingURL=framework-authoring-Dv5F3EFC.mjs.map |
| {"version":3,"file":"framework-authoring-Dv5F3EFC.mjs","names":[],"sources":["../src/shared/framework-authoring.ts"],"sourcesContent":["import type {\n ColumnDefault,\n ExecutionMutationDefaultPhases,\n ExecutionMutationDefaultValue,\n} from '@prisma-next/contract/types';\nimport {\n isColumnDefaultLiteralInputValue,\n isExecutionMutationDefaultValue,\n} from '@prisma-next/contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { Type } from 'arktype';\nimport type { CodecLookup } from './codec-types';\nimport type { PslBlockParam } from './psl-extension-block';\n\nexport type AuthoringArgRef = {\n readonly kind: 'arg';\n readonly index: number;\n readonly path?: readonly string[];\n readonly default?: AuthoringTemplateValue;\n};\n\nexport type AuthoringTemplateValue =\n | string\n | number\n | boolean\n | null\n | AuthoringArgRef\n | readonly AuthoringTemplateValue[]\n | { readonly [key: string]: AuthoringTemplateValue };\n\ninterface AuthoringArgumentDescriptorCommon {\n readonly name?: string;\n readonly optional?: boolean;\n}\n\nexport type AuthoringArgumentDescriptor = AuthoringArgumentDescriptorCommon &\n (\n | { readonly kind: 'string' }\n | { readonly kind: 'boolean' }\n | {\n readonly kind: 'number';\n readonly integer?: boolean;\n readonly minimum?: number;\n readonly maximum?: number;\n }\n | { readonly kind: 'stringArray' }\n | {\n readonly kind: 'object';\n readonly properties: Record<string, AuthoringArgumentDescriptor>;\n }\n );\n\nexport interface AuthoringStorageTypeTemplate {\n readonly codecId: string;\n readonly nativeType: AuthoringTemplateValue;\n readonly typeParams?: Record<string, AuthoringTemplateValue>;\n}\n\nexport interface AuthoringTypeConstructorDescriptor {\n readonly kind: 'typeConstructor';\n readonly args?: readonly AuthoringArgumentDescriptor[];\n readonly output: AuthoringStorageTypeTemplate;\n}\n\nexport interface AuthoringColumnDefaultTemplateLiteral {\n readonly kind: 'literal';\n readonly value: AuthoringTemplateValue;\n}\n\nexport interface AuthoringColumnDefaultTemplateFunction {\n readonly kind: 'function';\n readonly expression: AuthoringTemplateValue;\n}\n\nexport type AuthoringColumnDefaultTemplate =\n | AuthoringColumnDefaultTemplateLiteral\n | AuthoringColumnDefaultTemplateFunction;\n\nexport interface AuthoringExecutionDefaultsTemplate {\n readonly onCreate?: AuthoringTemplateValue;\n readonly onUpdate?: AuthoringTemplateValue;\n}\n\nexport interface AuthoringFieldPresetOutput extends AuthoringStorageTypeTemplate {\n readonly nullable?: boolean;\n readonly default?: AuthoringColumnDefaultTemplate;\n readonly executionDefaults?: AuthoringExecutionDefaultsTemplate;\n readonly id?: boolean;\n readonly unique?: boolean;\n}\n\nexport interface AuthoringFieldPresetDescriptor {\n readonly kind: 'fieldPreset';\n readonly args?: readonly AuthoringArgumentDescriptor[];\n readonly output: AuthoringFieldPresetOutput;\n}\n\nexport type AuthoringTypeNamespace = {\n readonly [name: string]: AuthoringTypeConstructorDescriptor | AuthoringTypeNamespace;\n};\n\nexport type AuthoringFieldNamespace = {\n readonly [name: string]: AuthoringFieldPresetDescriptor | AuthoringFieldNamespace;\n};\n\n/**\n * Context surfaced to entity-type factories at call time. Currently a\n * placeholder — sharpened as concrete consumers (enum, namespace, …)\n * discover what the factory actually needs to read (codec lookup,\n * namespace registry, …).\n */\n/**\n * A write-only sink that a factory may push authoring-time diagnostics into.\n * The concrete type pushed must be structurally compatible with whatever the\n * consumer accumulates (typically `ContractSourceDiagnostic[]`); the framework\n * layer deliberately does not depend on that concrete type.\n */\nexport interface AuthoringDiagnosticSink {\n push(d: {\n readonly code: string;\n readonly message: string;\n readonly sourceId: string;\n readonly span?: unknown;\n }): void;\n}\n\nexport interface AuthoringEntityContext {\n readonly family: string;\n readonly target: string;\n /** Codec registry available to factories that need to validate or decode values. */\n readonly codecLookup?: CodecLookup;\n /** Source file identifier threaded into diagnostics emitted by the factory. */\n readonly sourceId?: string;\n /** Push channel for authoring-time diagnostics emitted by the factory. */\n readonly diagnostics?: AuthoringDiagnosticSink;\n}\n\nexport interface AuthoringEntityTypeTemplateOutput {\n readonly template: AuthoringTemplateValue;\n}\n\n/**\n * Default `Input = never` is load-bearing for pack-bag-driven type\n * narrowing. Factory parameter positions are contravariant, so a pack\n * literal declaring `factory: (input: DemoEntityInput) => DemoEntity`\n * is only assignable to the base descriptor's factory shape if the\n * base's input is `never` (the bottom of the contravariant position).\n * The concrete input/output types are recovered at the helper-derivation\n * site via `EntityHelperFunction<Descriptor>`'s conditional inference,\n * which reads them from the pack's `as const` literal factory signature\n * — the base widening does not erase the literal because `satisfies`\n * does not widen the declared type.\n */\nexport interface AuthoringEntityTypeFactoryOutput<Input = never, Output = unknown> {\n readonly factory: (input: Input, ctx: AuthoringEntityContext) => Output;\n}\n\nexport interface AuthoringEntityTypeDescriptor<Input = never, Output = unknown> {\n readonly kind: 'entity';\n readonly discriminator: string;\n readonly args?: readonly AuthoringArgumentDescriptor[];\n readonly output:\n | AuthoringEntityTypeTemplateOutput\n | AuthoringEntityTypeFactoryOutput<Input, Output>;\n /**\n * arktype schema fragment for one entry whose envelope `kind` matches\n * this descriptor's {@link discriminator}. The family validator composes\n * contributed fragments into the per-namespace entry schema at\n * validator construction time so the structural check covers\n * pack-introduced kinds without the family core hard-coding the schema.\n *\n * Hydration uses {@link AuthoringEntityTypeFactoryOutput.factory}\n * directly — the wire shape conforms structurally to the factory's\n * `Input` after `validatorSchema` validates it.\n */\n readonly validatorSchema?: Type<unknown>;\n}\n\nexport type AuthoringEntityTypeNamespace = {\n readonly [name: string]: AuthoringEntityTypeDescriptor | AuthoringEntityTypeNamespace;\n};\n\n/**\n * Declarative descriptor for an extension-contributed top-level PSL block.\n *\n * An extension registers one of these per keyword it contributes. The\n * framework owns the generic parser, validator, and printer — no\n * parsing or printing code runs from the extension.\n *\n * - `keyword` is the PSL top-level identifier this descriptor claims\n * (`policy_select`, `role`, …).\n * - `discriminator` is the routing key used by the printer dispatch and\n * the `entityTypes` lowering factory lookup. Convention:\n * `<target-or-family>-<kind>` (`postgres-policy-select`).\n * - `name.required` declares whether the block must have a name token\n * after the keyword. Currently always `true` — anonymous blocks are\n * not part of the closed-grammar premise — but the field is explicit\n * so the type can evolve without a breaking change.\n * - `parameters` maps parameter names to their value-kind descriptors\n * (`ref` / `value` / `option` / `list`). The generic parser and\n * validator interpret these; the extension supplies no parser or\n * printer function.\n */\nexport interface AuthoringPslBlockDescriptor {\n readonly kind: 'pslBlock';\n readonly keyword: string;\n readonly discriminator: string;\n readonly name: { readonly required: boolean };\n readonly parameters: Record<string, PslBlockParam>;\n /**\n * When `true`, the block body accepts a variadic tail of parameters beyond\n * the declared set. The block body may contain: fields (model-style),\n * `key = value` parameters, and `@@` attributes. With `variadicParameters`,\n * bare identifiers (keys without a `= value`) and undeclared `key = value`\n * pairs flow into the variadic tail — their semantics belong to the\n * lowering, not the parser.\n *\n * A key that IS declared in `parameters` must still be supplied as\n * `key = value`; a bare occurrence of a declared key is a diagnostic.\n *\n * When `false` (default), the validator emits `PSL_EXTENSION_UNKNOWN_PARAMETER`\n * for keys absent from `parameters`.\n */\n readonly variadicParameters?: boolean;\n}\n\nexport type AuthoringPslBlockDescriptorNamespace = {\n readonly [name: string]: AuthoringPslBlockDescriptor | AuthoringPslBlockDescriptorNamespace;\n};\n\nexport interface AuthoringContributions {\n readonly type?: AuthoringTypeNamespace;\n readonly field?: AuthoringFieldNamespace;\n readonly entityTypes?: AuthoringEntityTypeNamespace;\n /**\n * Registry of declarative block descriptors this contribution registers,\n * keyed by arbitrary path segments. Each leaf is an\n * {@link AuthoringPslBlockDescriptor} that claims a PSL top-level keyword.\n * The framework owns the generic parser, validator, and printer; the\n * contribution supplies only these declarative descriptors.\n *\n * Contrast with the parsed block nodes themselves, which live in a\n * namespace's `entries` under their discriminator key; this field holds the\n * registry of descriptors that teach the parser how to read those blocks.\n */\n readonly pslBlockDescriptors?: AuthoringPslBlockDescriptorNamespace;\n}\n\nexport function isAuthoringArgRef(value: unknown): value is AuthoringArgRef {\n if (typeof value !== 'object' || value === null || (value as { kind?: unknown }).kind !== 'arg') {\n return false;\n }\n const { index, path } = value as { index?: unknown; path?: unknown };\n if (typeof index !== 'number' || !Number.isInteger(index) || index < 0) {\n return false;\n }\n if (path !== undefined && (!Array.isArray(path) || path.some((s) => typeof s !== 'string'))) {\n return false;\n }\n return true;\n}\n\nfunction isAuthoringTemplateRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isAuthoringTypeConstructorDescriptor(\n value: unknown,\n): value is AuthoringTypeConstructorDescriptor {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { kind?: unknown }).kind === 'typeConstructor' &&\n typeof (value as { output?: unknown }).output === 'object' &&\n (value as { output?: unknown }).output !== null\n );\n}\n\nexport function isAuthoringFieldPresetDescriptor(\n value: unknown,\n): value is AuthoringFieldPresetDescriptor {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { kind?: unknown }).kind === 'fieldPreset' &&\n typeof (value as { output?: unknown }).output === 'object' &&\n (value as { output?: unknown }).output !== null\n );\n}\n\nexport function isAuthoringEntityTypeDescriptor(\n value: unknown,\n): value is AuthoringEntityTypeDescriptor {\n if (\n typeof value !== 'object' ||\n value === null ||\n (value as { kind?: unknown }).kind !== 'entity'\n ) {\n return false;\n }\n const discriminator = (value as { discriminator?: unknown }).discriminator;\n if (typeof discriminator !== 'string' || discriminator.length === 0) {\n return false;\n }\n const output = (value as { output?: unknown }).output;\n if (typeof output !== 'object' || output === null) {\n return false;\n }\n const factory = (output as { factory?: unknown }).factory;\n const template = (output as { template?: unknown }).template;\n return typeof factory === 'function' || template !== undefined;\n}\n\nexport function isAuthoringPslBlockDescriptor(\n value: unknown,\n): value is AuthoringPslBlockDescriptor {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n const record = blindCast<\n Record<string, unknown>,\n 'type-guard probing an unknown candidate-descriptor object for known property names'\n >(value);\n if (record['kind'] !== 'pslBlock') {\n return false;\n }\n const keyword = record['keyword'];\n if (typeof keyword !== 'string' || keyword.length === 0) {\n return false;\n }\n const discriminator = record['discriminator'];\n if (typeof discriminator !== 'string' || discriminator.length === 0) {\n return false;\n }\n const name = record['name'];\n if (typeof name !== 'object' || name === null) {\n return false;\n }\n const nameRecord = blindCast<\n Record<string, unknown>,\n 'type-guard probing the name property of a candidate pslBlock descriptor'\n >(name);\n if (typeof nameRecord['required'] !== 'boolean') {\n return false;\n }\n const parameters = record['parameters'];\n return typeof parameters === 'object' && parameters !== null && !Array.isArray(parameters);\n}\n\n/**\n * Returns true when `namespace` is a non-leaf key in `contributions.field`.\n *\n * `AuthoringFieldNamespace` permits a leaf descriptor at any depth — including\n * the root — so a top-level `field: { Foo: { kind: 'fieldPreset', ... } }`\n * registration must NOT be treated as a \"namespace\" with sub-paths. Callers\n * use this predicate to gate dot-namespaced lookups (e.g. PSL `@Foo.bar`).\n */\nexport function hasRegisteredFieldNamespace(\n contributions: AuthoringContributions | undefined,\n namespace: string,\n): boolean {\n if (contributions?.field === undefined || !Object.hasOwn(contributions.field, namespace)) {\n return false;\n }\n return !isAuthoringFieldPresetDescriptor(contributions.field[namespace]);\n}\n\nfunction isCopyableNamespaceObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction deepCopyNamespace(\n source: Record<string, unknown>,\n isLeafDescriptor: (value: unknown) => boolean,\n): Record<string, unknown> {\n const copy: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(source)) {\n copy[key] =\n isCopyableNamespaceObject(value) && !isLeafDescriptor(value)\n ? deepCopyNamespace(value, isLeafDescriptor)\n : value;\n }\n return copy;\n}\n\n/**\n * Merges `source` into `target` recursively at the descriptor-namespace\n * level. `isLeafDescriptor` decides which values are descriptors (terminal\n * merge points; same-path registrations across components are reported\n * as duplicates) versus sub-namespaces (recursion targets).\n *\n * Path segments are validated against prototype-pollution names\n * (`__proto__`, `constructor`, `prototype`). A value that is neither a\n * recognized leaf nor a plain object — e.g. a malformed descriptor\n * where the canonical leaf guard rejected it for missing `output` —\n * is reported as an invalid contribution rather than recursed into,\n * which would either silently mangle state or infinite-loop on\n * primitive properties.\n *\n * Within-registry duplicate detection is this walker's job;\n * cross-registry detection runs separately via\n * `assertNoCrossRegistryCollisions` after merging completes.\n */\nexport function mergeAuthoringNamespaces(\n target: Record<string, unknown>,\n source: Record<string, unknown>,\n path: readonly string[],\n isLeafDescriptor: (value: unknown) => boolean,\n label: string,\n): void {\n const assertSafePath = (currentPath: readonly string[]) => {\n const blockedSegment = currentPath.find(\n (segment) => segment === '__proto__' || segment === 'constructor' || segment === 'prototype',\n );\n if (blockedSegment) {\n throw new Error(\n `Invalid authoring ${label} helper \"${currentPath.join('.')}\". Helper path segments must not use \"${blockedSegment}\".`,\n );\n }\n };\n\n for (const [key, sourceValue] of Object.entries(source)) {\n const currentPath = [...path, key];\n assertSafePath(currentPath);\n const hasExistingValue = Object.hasOwn(target, key);\n const existingValue = hasExistingValue ? target[key] : undefined;\n\n if (!hasExistingValue) {\n // Deep-copy plain-object sub-namespaces so subsequent merges don't mutate\n // objects owned by source packs. Leaf descriptors and class instances are\n // passed by reference — leaves are identity values; class instances carry\n // prototype getters that spread would destroy.\n target[key] =\n isCopyableNamespaceObject(sourceValue) && !isLeafDescriptor(sourceValue)\n ? deepCopyNamespace(sourceValue, isLeafDescriptor)\n : sourceValue;\n continue;\n }\n\n const existingIsLeaf = isLeafDescriptor(existingValue);\n const sourceIsLeaf = isLeafDescriptor(sourceValue);\n\n if (existingIsLeaf || sourceIsLeaf) {\n throw new Error(\n `Duplicate authoring ${label} helper \"${currentPath.join('.')}\". Helper names must be unique across composed packs.`,\n );\n }\n\n if (!isCopyableNamespaceObject(existingValue) || !isCopyableNamespaceObject(sourceValue)) {\n throw new Error(\n `Invalid authoring ${label} helper \"${currentPath.join('.')}\". Expected a sub-namespace object or a recognized descriptor; received a malformed value.`,\n );\n }\n\n mergeAuthoringNamespaces(existingValue, sourceValue, currentPath, isLeafDescriptor, label);\n }\n}\n\nfunction collectDescriptorPaths(\n namespace: Readonly<Record<string, unknown>>,\n isLeaf: (value: unknown) => boolean,\n path: readonly string[] = [],\n): string[] {\n const paths: string[] = [];\n for (const [key, value] of Object.entries(namespace)) {\n const currentPath = [...path, key];\n if (isLeaf(value)) {\n paths.push(currentPath.join('.'));\n continue;\n }\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n paths.push(\n ...collectDescriptorPaths(value as Readonly<Record<string, unknown>>, isLeaf, currentPath),\n );\n }\n }\n return paths;\n}\n\ninterface DescriptorEntry {\n readonly path: string;\n readonly discriminator: string;\n}\n\nfunction collectDescriptorEntries(\n namespace: Readonly<Record<string, unknown>>,\n isLeaf: (value: unknown) => boolean,\n label: string,\n path: readonly string[] = [],\n): DescriptorEntry[] {\n const entries: DescriptorEntry[] = [];\n for (const [key, value] of Object.entries(namespace)) {\n const currentPath = [...path, key];\n if (isLeaf(value)) {\n const record = blindCast<\n Record<string, unknown>,\n 'discriminator extraction from a leaf already validated by isLeaf'\n >(value);\n const discriminator = record['discriminator'];\n if (typeof discriminator === 'string' && discriminator.length > 0) {\n entries.push({ path: currentPath.join('.'), discriminator });\n }\n continue;\n }\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n const record = blindCast<\n Readonly<Record<string, unknown>>,\n 'walker inspects a non-leaf value for descriptor-shaped keys before recursing'\n >(value);\n // A value carrying descriptor-shaped keys (`kind`/`keyword`/`discriminator`)\n // but failing `isAuthoringPslBlockDescriptor` (e.g. missing `parameters`) is\n // a malformed declarative descriptor. Descending into it as a sub-namespace\n // would silently skip it, so a half-built contribution would pass validation.\n // Reject it at load time instead, naming the path and what's wrong.\n //\n // A valid sub-namespace whose key happens to be named `kind`, `keyword`, or\n // `discriminator` (but which does not look like a descriptor overall) must\n // still descend normally — the check requires descriptor-shaped keys present\n // AND the leaf guard rejecting it.\n if (\n (record['kind'] !== undefined ||\n record['keyword'] !== undefined ||\n record['discriminator'] !== undefined) &&\n !isLeaf(value)\n ) {\n const hasKind = record['kind'] === 'pslBlock';\n const hasKeyword = typeof record['keyword'] === 'string';\n const hasDiscriminator = typeof record['discriminator'] === 'string';\n if (hasKind || (hasKeyword && hasDiscriminator)) {\n throw new Error(\n `Malformed authoring ${label} contribution at \"${currentPath.join('.')}\". The value carries descriptor keys (kind/keyword/discriminator) but does not satisfy the ${label} descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`,\n );\n }\n }\n entries.push(...collectDescriptorEntries(record, isLeaf, label, currentPath));\n }\n }\n return entries;\n}\n\n/**\n * Throws when two or more entries in the same namespace share a discriminator.\n * Duplicate discriminators within a namespace make dispatch ambiguous — the\n * lowering factory lookup dispatches by discriminator, so one would silently\n * shadow the other. Catch duplicates before building any dispatch map.\n */\nfunction assertUniqueDiscriminators(entries: readonly DescriptorEntry[], label: string): void {\n const seen = new Map<string, string>();\n for (const { path, discriminator } of entries) {\n const existing = seen.get(discriminator);\n if (existing !== undefined) {\n throw new Error(\n `Duplicate ${label} discriminator \"${discriminator}\" registered at both \"${existing}\" and \"${path}\". Each ${label} contribution must use a unique discriminator.`,\n );\n }\n seen.set(discriminator, path);\n }\n}\n\nfunction collectPslBlockDescriptorEntries(\n namespace: Readonly<Record<string, unknown>>,\n path: readonly string[] = [],\n): DescriptorEntry[] {\n const entries: DescriptorEntry[] = [];\n for (const [key, value] of Object.entries(namespace)) {\n const currentPath = [...path, key];\n if (isAuthoringPslBlockDescriptor(value)) {\n entries.push({\n path: currentPath.join('.'),\n discriminator: value.discriminator,\n });\n continue;\n }\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n const record = blindCast<\n Readonly<Record<string, unknown>>,\n 'walker descends into psl block namespace'\n >(value);\n const hasKind = record['kind'] === 'pslBlock';\n const hasKeyword = typeof record['keyword'] === 'string';\n const hasDiscriminator = typeof record['discriminator'] === 'string';\n if (hasKind || (hasKeyword && hasDiscriminator)) {\n throw new Error(\n `Malformed authoring pslBlock contribution at \"${currentPath.join('.')}\". The value carries descriptor keys (kind/keyword/discriminator) but does not satisfy the pslBlock descriptor shape. Fix the contribution so it is a complete descriptor, or remove the stray keys if it was meant to be a sub-namespace.`,\n );\n }\n entries.push(...collectPslBlockDescriptorEntries(record, currentPath));\n }\n }\n return entries;\n}\n\n/**\n * Every `pslBlockDescriptors` entry requires a matching `entityTypes` factory\n * with the same discriminator. An `entityTypes` factory may stand alone (e.g.\n * `enum`, reachable from the TypeScript builder without any PSL block).\n */\nfunction assertPslBlocksHaveFactories(\n entityTypeNamespace: AuthoringEntityTypeNamespace,\n pslBlockNamespace: AuthoringPslBlockDescriptorNamespace,\n): void {\n const blockEntries = collectPslBlockDescriptorEntries(pslBlockNamespace);\n const entityEntries = collectDescriptorEntries(\n entityTypeNamespace,\n isAuthoringEntityTypeDescriptor,\n 'entityType',\n );\n\n assertUniqueDiscriminators(blockEntries, 'pslBlock');\n assertUniqueDiscriminators(entityEntries, 'entityType');\n\n const entityDiscriminators = new Set(entityEntries.map((entry) => entry.discriminator));\n\n for (const block of blockEntries) {\n if (!entityDiscriminators.has(block.discriminator)) {\n throw new Error(\n `Incomplete extension contribution: pslBlock helper \"${block.path}\" registers discriminator \"${block.discriminator}\" but no entityType contribution shares that discriminator. An extension-contributed PSL block requires a matching entityType factory so the parsed AST node can lower to an IR class instance; add an entityType helper with discriminator \"${block.discriminator}\".`,\n );\n }\n }\n}\n\nexport function assertNoCrossRegistryCollisions(\n typeNamespace: AuthoringTypeNamespace,\n fieldNamespace: AuthoringFieldNamespace,\n entityTypeNamespace: AuthoringEntityTypeNamespace = {},\n pslBlockNamespace: AuthoringPslBlockDescriptorNamespace = {},\n): void {\n const typePaths = new Set(\n collectDescriptorPaths(typeNamespace, isAuthoringTypeConstructorDescriptor),\n );\n const fieldPaths = new Set(\n collectDescriptorPaths(fieldNamespace, isAuthoringFieldPresetDescriptor),\n );\n const entityPaths = new Set(\n collectDescriptorPaths(entityTypeNamespace, isAuthoringEntityTypeDescriptor),\n );\n // Within-registry duplicate detection is handled upstream by the merge\n // walker (`mergeAuthoringNamespaces` in control-stack.ts and\n // `mergeHelperNamespaces` in composed-authoring-helpers.ts), which throws\n // on same-path registrations within any single registry before this check\n // runs. This function only handles the cross-registry case.\n //\n // Cross-registry collisions are checked among `type` / `field` /\n // `entityTypes` only — these three are user-facing helper paths that PSL\n // must resolve unambiguously. `pslBlockDescriptors` is an internal\n // framework index consumed by parser and printer dispatch, not a\n // user-facing helper path; the natural authoring pattern is the same\n // path key in `entityTypes` and `pslBlockDescriptors` for a single\n // contribution. The block→factory link is enforced by\n // `assertPslBlocksHaveFactories` via the discriminator string, not by path.\n const ambiguityHint =\n 'Register each path in only one of authoringContributions.field / authoringContributions.type / authoringContributions.entityTypes.';\n for (const fieldPath of fieldPaths) {\n if (typePaths.has(fieldPath)) {\n throw new Error(\n `Ambiguous authoring registry path \"${fieldPath}\". The same path is registered as both a type constructor and a field preset; PSL resolution would be ambiguous. ${ambiguityHint}`,\n );\n }\n }\n for (const entityPath of entityPaths) {\n if (typePaths.has(entityPath) || fieldPaths.has(entityPath)) {\n throw new Error(\n `Ambiguous authoring registry path \"${entityPath}\". The same path is registered as an entity contribution AND as a type constructor or field preset; PSL resolution would be ambiguous. ${ambiguityHint}`,\n );\n }\n }\n\n assertPslBlocksHaveFactories(entityTypeNamespace, pslBlockNamespace);\n}\n\nexport function resolveAuthoringTemplateValue(\n template: AuthoringTemplateValue,\n args: readonly unknown[],\n): unknown {\n if (isAuthoringArgRef(template)) {\n let value = args[template.index];\n\n for (const segment of template.path ?? []) {\n if (!isAuthoringTemplateRecord(value) || !Object.hasOwn(value, segment)) {\n value = undefined;\n break;\n }\n value = (value as Record<string, unknown>)[segment];\n }\n\n if (value === undefined && template.default !== undefined) {\n return resolveAuthoringTemplateValue(template.default, args);\n }\n\n return value;\n }\n if (Array.isArray(template)) {\n return template.map((value) => resolveAuthoringTemplateValue(value, args));\n }\n if (typeof template === 'object' && template !== null) {\n const resolved: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(template)) {\n const resolvedValue = resolveAuthoringTemplateValue(value, args);\n if (resolvedValue !== undefined) {\n resolved[key] = resolvedValue;\n }\n }\n return resolved;\n }\n return template;\n}\n\nfunction validateAuthoringArgument(\n descriptor: AuthoringArgumentDescriptor,\n value: unknown,\n path: string,\n): void {\n if (value === undefined) {\n if (descriptor.optional) {\n return;\n }\n throw new Error(`Missing required authoring helper argument at ${path}`);\n }\n\n if (descriptor.kind === 'string') {\n if (typeof value !== 'string') {\n throw new Error(`Authoring helper argument at ${path} must be a string`);\n }\n return;\n }\n\n if (descriptor.kind === 'boolean') {\n if (typeof value !== 'boolean') {\n throw new Error(`Authoring helper argument at ${path} must be a boolean`);\n }\n return;\n }\n\n if (descriptor.kind === 'stringArray') {\n if (!Array.isArray(value)) {\n throw new Error(`Authoring helper argument at ${path} must be an array of strings`);\n }\n for (const entry of value) {\n if (typeof entry !== 'string') {\n throw new Error(`Authoring helper argument at ${path} must be an array of strings`);\n }\n }\n return;\n }\n\n if (descriptor.kind === 'object') {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new Error(`Authoring helper argument at ${path} must be an object`);\n }\n\n const input = value as Record<string, unknown>;\n const expectedKeys = new Set(Object.keys(descriptor.properties));\n\n for (const key of Object.keys(input)) {\n if (!expectedKeys.has(key)) {\n throw new Error(`Authoring helper argument at ${path} contains unknown property \"${key}\"`);\n }\n }\n\n for (const [key, propertyDescriptor] of Object.entries(descriptor.properties)) {\n validateAuthoringArgument(propertyDescriptor, input[key], `${path}.${key}`);\n }\n\n return;\n }\n\n if (typeof value !== 'number' || Number.isNaN(value)) {\n throw new Error(`Authoring helper argument at ${path} must be a number`);\n }\n\n if (descriptor.integer && !Number.isInteger(value)) {\n throw new Error(`Authoring helper argument at ${path} must be an integer`);\n }\n if (descriptor.minimum !== undefined && value < descriptor.minimum) {\n throw new Error(\n `Authoring helper argument at ${path} must be >= ${descriptor.minimum}, received ${value}`,\n );\n }\n if (descriptor.maximum !== undefined && value > descriptor.maximum) {\n throw new Error(\n `Authoring helper argument at ${path} must be <= ${descriptor.maximum}, received ${value}`,\n );\n }\n}\n\nexport function validateAuthoringHelperArguments(\n helperPath: string,\n descriptors: readonly AuthoringArgumentDescriptor[] | undefined,\n args: readonly unknown[],\n): void {\n const expected = descriptors ?? [];\n const minimumArgs = expected.reduce(\n (count, descriptor, index) => (descriptor.optional ? count : index + 1),\n 0,\n );\n if (args.length < minimumArgs || args.length > expected.length) {\n throw new Error(\n `${helperPath} expects ${minimumArgs === expected.length ? expected.length : `${minimumArgs}-${expected.length}`} argument(s), received ${args.length}`,\n );\n }\n\n expected.forEach((descriptor, index) => {\n validateAuthoringArgument(descriptor, args[index], `${helperPath}[${index}]`);\n });\n}\n\nfunction resolveAuthoringStorageTypeTemplate(\n template: AuthoringStorageTypeTemplate,\n args: readonly unknown[],\n): {\n readonly codecId: string;\n readonly nativeType: string;\n readonly typeParams?: Record<string, unknown>;\n} {\n const nativeType = resolveAuthoringTemplateValue(template.nativeType, args);\n if (typeof nativeType !== 'string') {\n throw new Error(\n `Resolved authoring nativeType must be a string for codec \"${template.codecId}\", received ${String(nativeType)}`,\n );\n }\n const typeParams =\n template.typeParams === undefined\n ? undefined\n : resolveAuthoringTemplateValue(template.typeParams, args);\n if (typeParams !== undefined && !isAuthoringTemplateRecord(typeParams)) {\n throw new Error(\n `Resolved authoring typeParams must be an object for codec \"${template.codecId}\", received ${String(typeParams)}`,\n );\n }\n\n return {\n codecId: template.codecId,\n nativeType,\n ...(typeParams === undefined ? {} : { typeParams }),\n };\n}\n\nfunction resolveAuthoringColumnDefaultTemplate(\n template: AuthoringColumnDefaultTemplate,\n args: readonly unknown[],\n): ColumnDefault {\n if (template.kind === 'literal') {\n const value = resolveAuthoringTemplateValue(template.value, args);\n if (value === undefined) {\n throw new Error('Resolved authoring literal default must not be undefined');\n }\n if (!isColumnDefaultLiteralInputValue(value)) {\n throw new Error(\n `Resolved authoring literal default must be a JSON-serializable value or Date, received ${String(value)}`,\n );\n }\n return {\n kind: 'literal',\n value,\n };\n }\n\n const expression = resolveAuthoringTemplateValue(template.expression, args);\n if (expression === undefined || (typeof expression === 'object' && expression !== null)) {\n throw new Error(\n `Resolved authoring function default expression must resolve to a primitive, received ${String(expression)}`,\n );\n }\n return {\n kind: 'function',\n expression: String(expression),\n };\n}\n\nfunction resolveExecutionMutationDefaultPhase(\n phase: 'onCreate' | 'onUpdate',\n template: AuthoringTemplateValue,\n args: readonly unknown[],\n): ExecutionMutationDefaultValue {\n const value = resolveAuthoringTemplateValue(template, args);\n if (!isExecutionMutationDefaultValue(value)) {\n throw new Error(\n `Authoring preset executionDefaults.${phase} did not resolve to a valid generator descriptor (kind: 'generator', id: string).`,\n );\n }\n return value;\n}\n\nfunction resolveAuthoringExecutionDefaultsTemplate(\n template: AuthoringExecutionDefaultsTemplate,\n args: readonly unknown[],\n): ExecutionMutationDefaultPhases {\n return {\n ...ifDefined(\n 'onCreate',\n template.onCreate !== undefined\n ? resolveExecutionMutationDefaultPhase('onCreate', template.onCreate, args)\n : undefined,\n ),\n ...ifDefined(\n 'onUpdate',\n template.onUpdate !== undefined\n ? resolveExecutionMutationDefaultPhase('onUpdate', template.onUpdate, args)\n : undefined,\n ),\n };\n}\n\nexport function instantiateAuthoringTypeConstructor(\n descriptor: AuthoringTypeConstructorDescriptor,\n args: readonly unknown[],\n): {\n readonly codecId: string;\n readonly nativeType: string;\n readonly typeParams?: Record<string, unknown>;\n} {\n return resolveAuthoringStorageTypeTemplate(descriptor.output, args);\n}\n\nexport function instantiateAuthoringEntityType(\n helperPath: string,\n descriptor: AuthoringEntityTypeDescriptor,\n args: readonly unknown[],\n ctx: AuthoringEntityContext,\n): unknown {\n // Factory-output entities carry their input contract on the factory\n // signature itself — TypeScript narrows callers via\n // `EntityHelperFunction`'s extracted `input` parameter, and the factory\n // is free to do its own runtime validation (e.g. arktype Type). The\n // descriptor-level `args` validator is reserved for template-output\n // entities (which mirror field/type's declarative argument shape).\n if ('factory' in descriptor.output) {\n const input = args[0];\n // The base `AuthoringEntityTypeDescriptor`'s factory is typed\n // `(input: never, ctx) => unknown` so concrete pack-literal factories\n // with narrower input types remain assignable through the\n // contravariant position (see the type's docstring). The runtime\n // delegates input validation to the pack's factory itself, so we\n // forward the supplied input here without a static input contract.\n const factory = descriptor.output.factory as (\n input: unknown,\n ctx: AuthoringEntityContext,\n ) => unknown;\n return factory(input, ctx);\n }\n validateAuthoringHelperArguments(helperPath, descriptor.args, args);\n return resolveAuthoringTemplateValue(descriptor.output.template, args);\n}\n\nexport function instantiateAuthoringFieldPreset(\n descriptor: AuthoringFieldPresetDescriptor,\n args: readonly unknown[],\n): {\n readonly descriptor: {\n readonly codecId: string;\n readonly nativeType: string;\n readonly typeParams?: Record<string, unknown>;\n };\n readonly nullable: boolean;\n readonly default?: ColumnDefault;\n readonly executionDefaults?: ExecutionMutationDefaultPhases;\n readonly id: boolean;\n readonly unique: boolean;\n} {\n return {\n descriptor: resolveAuthoringStorageTypeTemplate(descriptor.output, args),\n nullable: descriptor.output.nullable ?? false,\n ...ifDefined(\n 'default',\n descriptor.output.default !== undefined\n ? resolveAuthoringColumnDefaultTemplate(descriptor.output.default, args)\n : undefined,\n ),\n ...ifDefined(\n 'executionDefaults',\n descriptor.output.executionDefaults !== undefined\n ? resolveAuthoringExecutionDefaultsTemplate(descriptor.output.executionDefaults, args)\n : undefined,\n ),\n id: descriptor.output.id ?? false,\n unique: descriptor.output.unique ?? false,\n };\n}\n"],"mappings":"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"} |
| import { f as AnyCodecDescriptor } from "./codec-types-yY3eSmi0.mjs"; | ||
| import { i as AuthoringContributions } from "./framework-authoring-CJC4jwGo.mjs"; | ||
| import { t as TypesImportSpec } from "./types-import-spec-DRKzrJ20.mjs"; | ||
| import { ColumnDefault, ExecutionMutationDefaultPhases, ExecutionMutationDefaultValue } from "@prisma-next/contract/types"; | ||
| //#region src/shared/mutation-default-types.d.ts | ||
| interface SourcePosition { | ||
| readonly offset: number; | ||
| readonly line: number; | ||
| readonly column: number; | ||
| } | ||
| interface SourceSpan { | ||
| readonly start: SourcePosition; | ||
| readonly end: SourcePosition; | ||
| } | ||
| interface SourceDiagnostic { | ||
| readonly code: string; | ||
| readonly message: string; | ||
| readonly sourceId?: string; | ||
| readonly span?: SourceSpan; | ||
| readonly data?: Readonly<Record<string, unknown>>; | ||
| } | ||
| interface DefaultFunctionArgument { | ||
| readonly raw: string; | ||
| readonly span: SourceSpan; | ||
| } | ||
| interface ParsedDefaultFunctionCall { | ||
| readonly name: string; | ||
| readonly raw: string; | ||
| readonly args: readonly DefaultFunctionArgument[]; | ||
| readonly span: SourceSpan; | ||
| } | ||
| interface DefaultFunctionLoweringContext { | ||
| readonly sourceId: string; | ||
| readonly modelName: string; | ||
| readonly fieldName: string; | ||
| readonly columnCodecId?: string; | ||
| } | ||
| type LoweredDefaultValue = { | ||
| readonly kind: 'storage'; | ||
| readonly defaultValue: ColumnDefault; | ||
| } | { | ||
| readonly kind: 'execution'; | ||
| readonly generated: ExecutionMutationDefaultValue; | ||
| }; | ||
| type LoweredDefaultResult = { | ||
| readonly ok: true; | ||
| readonly value: LoweredDefaultValue; | ||
| } | { | ||
| readonly ok: false; | ||
| readonly diagnostic: SourceDiagnostic; | ||
| }; | ||
| type DefaultFunctionLoweringHandler = (input: { | ||
| readonly call: ParsedDefaultFunctionCall; | ||
| readonly context: DefaultFunctionLoweringContext; | ||
| }) => LoweredDefaultResult; | ||
| interface DefaultFunctionRegistryEntry { | ||
| readonly lower: DefaultFunctionLoweringHandler; | ||
| readonly usageSignatures?: readonly string[]; | ||
| } | ||
| type DefaultFunctionRegistry = ReadonlyMap<string, DefaultFunctionRegistryEntry>; | ||
| interface MutationDefaultGeneratorDescriptor { | ||
| readonly id: string; | ||
| /** | ||
| * Codec ids the generator is compatible with when the codec choice | ||
| * and the generator choice are made independently by the contract | ||
| * author. Set when the registry-coherence check is meaningful | ||
| * (the codec and the generator can be paired arbitrarily by the | ||
| * caller); omitted when the generator is only reachable through a | ||
| * descriptor that co-registers a fixed codec, so coherence is | ||
| * structural and the list would be tautological. | ||
| */ | ||
| readonly applicableCodecIds?: readonly string[]; | ||
| readonly resolveGeneratedColumnDescriptor?: (input: { | ||
| readonly generated: ExecutionMutationDefaultValue; | ||
| }) => { | ||
| readonly codecId: string; | ||
| readonly nativeType: string; | ||
| readonly typeRef?: string; | ||
| readonly typeParams?: Record<string, unknown>; | ||
| } | undefined; | ||
| /** | ||
| * Construct the `onCreate`/`onUpdate` phases value owned by this | ||
| * generator. Authoring layers (PSL `temporal.updatedAt()`, TS field presets) call | ||
| * this instead of building the literal inline so PSL/TS-authored | ||
| * contracts stay byte-equivalent for any future params-bearing generator. | ||
| */ | ||
| readonly buildPhases?: (args?: Record<string, unknown>) => ExecutionMutationDefaultPhases; | ||
| } | ||
| interface ControlMutationDefaultEntry { | ||
| readonly lower: (input: { | ||
| readonly call: ParsedDefaultFunctionCall; | ||
| readonly context: DefaultFunctionLoweringContext; | ||
| }) => LoweredDefaultResult; | ||
| readonly usageSignatures?: readonly string[]; | ||
| } | ||
| type ControlMutationDefaultRegistry = ReadonlyMap<string, ControlMutationDefaultEntry>; | ||
| interface ControlMutationDefaults { | ||
| readonly defaultFunctionRegistry: ControlMutationDefaultRegistry; | ||
| readonly generatorDescriptors: readonly MutationDefaultGeneratorDescriptor[]; | ||
| } | ||
| //#endregion | ||
| //#region src/shared/framework-components.d.ts | ||
| /** | ||
| * Declarative fields that describe component metadata. | ||
| */ | ||
| interface ComponentMetadata { | ||
| /** Component version (semver) */ | ||
| readonly version: string; | ||
| /** | ||
| * Capabilities this component provides. | ||
| * | ||
| * For adapters, capabilities must be declared on the adapter descriptor (so they are emitted into the contract) and also exposed in runtime adapter code (e.g. `adapter.profile.capabilities`); keep these declarations in sync. Targets are identifiers/descriptors and typically do not declare capabilities. | ||
| */ | ||
| readonly capabilities?: Record<string, unknown>; | ||
| /** Type imports for contract.d.ts generation */ | ||
| readonly types?: { | ||
| readonly codecTypes?: { | ||
| /** | ||
| * Base codec types import spec. Optional: adapters typically provide this, extensions usually don't. | ||
| */ | ||
| readonly import?: TypesImportSpec; | ||
| /** | ||
| * Additional type-only imports for parameterized codec branded types. | ||
| * | ||
| * These imports are included in generated `contract.d.ts` but are NOT treated as codec type maps (i.e., they should not be intersected into `export type CodecTypes = ...`). | ||
| * | ||
| * Example: `Vector<N>` for pgvector codecs that emit `Vector<1536>` | ||
| */ | ||
| readonly typeImports?: ReadonlyArray<TypesImportSpec>; | ||
| /** | ||
| * Optional control-plane hooks keyed by codecId. Used by family-specific planners/verifiers to handle storage types. | ||
| */ | ||
| readonly controlPlaneHooks?: Record<string, unknown>; | ||
| /** | ||
| * Codec descriptors contributed by this component. Source of truth for codec-id-keyed metadata (`traits`, `targetTypes`, `meta`, `renderOutputType`) consumed by `extractCodecLookup`, and used to materialize representative `Codec` instances for codec-dispatched type rendering during emission. | ||
| */ | ||
| readonly codecDescriptors?: ReadonlyArray<AnyCodecDescriptor>; | ||
| }; | ||
| readonly queryOperationTypes?: { | ||
| readonly import: TypesImportSpec; | ||
| }; | ||
| readonly storage?: ReadonlyArray<{ | ||
| readonly typeId: string; | ||
| readonly familyId: string; | ||
| readonly targetId: string; | ||
| readonly nativeType?: string; | ||
| }>; | ||
| }; | ||
| /** | ||
| * Optional pure-data authoring contributions exposed by this component. | ||
| * | ||
| * These contributions are safe to include on pack refs and descriptors because they contain only declarative metadata. Higher-level authoring packages may project them into concrete helper functions for TS-first workflows. | ||
| */ | ||
| readonly authoring?: AuthoringContributions; | ||
| /** | ||
| * Scalar type name to codec ID mapping contributed by this component. Assembled by `createControlStack` with duplicate detection. | ||
| */ | ||
| readonly scalarTypeDescriptors?: ReadonlyMap<string, string>; | ||
| /** | ||
| * Mutation default function handlers and generator descriptors contributed by this component. Assembled by `createControlStack` with duplicate detection. | ||
| */ | ||
| readonly controlMutationDefaults?: ControlMutationDefaults; | ||
| } | ||
| /** | ||
| * Base descriptor for any framework component. | ||
| * | ||
| * All component descriptors share these fundamental properties that identify the component and provide its metadata. This interface is extended by specific descriptor types (FamilyDescriptor, TargetDescriptor, etc.). | ||
| * | ||
| * @template Kind - Discriminator literal identifying the component type. Built-in kinds are 'family', 'target', 'adapter', 'driver', 'extension', but the type accepts any string to allow ecosystem extensions. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * // All descriptors have these properties | ||
| * descriptor.kind // The Kind type parameter (e.g., 'family', 'target', or custom kinds) | ||
| * descriptor.id // Unique string identifier (e.g., 'sql', 'postgres') | ||
| * descriptor.version // Component version (semver) | ||
| * ``` | ||
| */ | ||
| interface ComponentDescriptor<Kind extends string> extends ComponentMetadata { | ||
| /** Discriminator identifying the component type */ | ||
| readonly kind: Kind; | ||
| /** Unique identifier for this component (e.g., 'sql', 'postgres', 'pgvector') */ | ||
| readonly id: string; | ||
| } | ||
| interface ContractComponentRequirementsCheckInput { | ||
| readonly contract: { | ||
| readonly target: string; | ||
| readonly targetFamily?: string | undefined; | ||
| readonly extensionPacks?: Record<string, unknown> | undefined; | ||
| }; | ||
| readonly expectedTargetFamily?: string | undefined; | ||
| readonly expectedTargetId?: string | undefined; | ||
| readonly providedComponentIds: Iterable<string>; | ||
| } | ||
| interface ContractComponentRequirementsCheckResult { | ||
| readonly familyMismatch?: { | ||
| readonly expected: string; | ||
| readonly actual: string; | ||
| } | undefined; | ||
| readonly targetMismatch?: { | ||
| readonly expected: string; | ||
| readonly actual: string; | ||
| } | undefined; | ||
| readonly missingExtensionPackIds: readonly string[]; | ||
| } | ||
| declare function checkContractComponentRequirements(input: ContractComponentRequirementsCheckInput): ContractComponentRequirementsCheckResult; | ||
| /** | ||
| * Descriptor for a family component. | ||
| * | ||
| * A "family" represents a category of data sources with shared semantics (e.g., SQL databases, document stores). Families define: | ||
| * - Query semantics and operations (SELECT, INSERT, find, aggregate, etc.) | ||
| * - Contract structure (tables vs collections, columns vs fields) | ||
| * - Type system and codecs | ||
| * | ||
| * Families are the top-level grouping. Each family contains multiple targets (e.g., SQL family contains Postgres, MySQL, SQLite targets). | ||
| * | ||
| * Extended by plane-specific descriptors: | ||
| * - `ControlFamilyDescriptor` - adds `emission` for CLI/tooling operations | ||
| * - `RuntimeFamilyDescriptor` - adds runtime-specific factory methods | ||
| * | ||
| * @template TFamilyId - Literal type for the family identifier (e.g., 'sql', 'document') | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import sql from '@prisma-next/family-sql/control'; | ||
| * | ||
| * sql.kind // 'family' | ||
| * sql.familyId // 'sql' | ||
| * sql.id // 'sql' | ||
| * ``` | ||
| */ | ||
| interface FamilyDescriptor<TFamilyId extends string> extends ComponentDescriptor<'family'> { | ||
| /** The family identifier (e.g., 'sql', 'document') */ | ||
| readonly familyId: TFamilyId; | ||
| } | ||
| /** | ||
| * Descriptor for a target component. | ||
| * | ||
| * A "target" represents a specific database or data store within a family (e.g., Postgres, MySQL, MongoDB). Targets define: | ||
| * - Native type mappings (e.g., Postgres int4 → TypeScript number) | ||
| * - Target-specific capabilities (e.g., RETURNING, LATERAL joins) | ||
| * | ||
| * Targets are bound to a family and provide the target-specific implementation details that adapters and drivers use. | ||
| * | ||
| * Extended by plane-specific descriptors: | ||
| * - `ControlTargetDescriptor` - adds optional `migrations` capability | ||
| * - `RuntimeTargetDescriptor` - adds runtime factory method | ||
| * | ||
| * @template TFamilyId - Literal type for the family identifier | ||
| * @template TTargetId - Literal type for the target identifier (e.g., 'postgres', 'mysql') | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import postgres from '@prisma-next/target-postgres/control'; | ||
| * | ||
| * postgres.kind // 'target' | ||
| * postgres.familyId // 'sql' | ||
| * postgres.targetId // 'postgres' | ||
| * ``` | ||
| */ | ||
| interface TargetDescriptor<TFamilyId extends string, TTargetId extends string> extends ComponentDescriptor<'target'> { | ||
| /** The family this target belongs to */ | ||
| readonly familyId: TFamilyId; | ||
| /** The target identifier (e.g., 'postgres', 'mysql', 'mongodb') */ | ||
| readonly targetId: TTargetId; | ||
| } | ||
| /** | ||
| * Base shape for any pack reference. Pack refs are pure JSON-friendly objects safe to import in authoring flows. | ||
| */ | ||
| interface PackRefBase<Kind extends string, TFamilyId extends string> extends ComponentMetadata { | ||
| readonly kind: Kind; | ||
| readonly id: string; | ||
| readonly familyId: TFamilyId; | ||
| readonly targetId?: string; | ||
| readonly authoring?: AuthoringContributions; | ||
| } | ||
| type FamilyPackRef<TFamilyId extends string = string> = PackRefBase<'family', TFamilyId>; | ||
| type TargetPackRef<TFamilyId extends string = string, TTargetId extends string = string> = PackRefBase<'target', TFamilyId> & { | ||
| readonly targetId: TTargetId; /** The namespace a bare (un-namespaced) entity name resolves to for this target (e.g. Postgres `'public'`). */ | ||
| readonly defaultNamespaceId: string; | ||
| }; | ||
| type AdapterPackRef<TFamilyId extends string = string, TTargetId extends string = string> = PackRefBase<'adapter', TFamilyId> & { | ||
| readonly targetId: TTargetId; | ||
| }; | ||
| type ExtensionPackRef<TFamilyId extends string = string, TTargetId extends string = string> = PackRefBase<'extension', TFamilyId> & { | ||
| readonly targetId: TTargetId; | ||
| }; | ||
| type DriverPackRef<TFamilyId extends string = string, TTargetId extends string = string> = PackRefBase<'driver', TFamilyId> & { | ||
| readonly targetId: TTargetId; | ||
| }; | ||
| /** | ||
| * Descriptor for an adapter component. | ||
| * | ||
| * An "adapter" provides the protocol and dialect implementation for a target. Adapters handle: | ||
| * - SQL/query generation (lowering AST to target-specific syntax) | ||
| * - Codec registration (encoding/decoding between JS and wire types) | ||
| * - Type mappings and coercions | ||
| * | ||
| * Adapters are bound to a specific family+target combination and work with any compatible driver for that target. | ||
| * | ||
| * Extended by plane-specific descriptors: | ||
| * - `ControlAdapterDescriptor` - control-plane factory | ||
| * - `RuntimeAdapterDescriptor` - runtime factory | ||
| * | ||
| * @template TFamilyId - Literal type for the family identifier | ||
| * @template TTargetId - Literal type for the target identifier | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import postgresAdapter from '@prisma-next/adapter-postgres/control'; | ||
| * | ||
| * postgresAdapter.kind // 'adapter' | ||
| * postgresAdapter.familyId // 'sql' | ||
| * postgresAdapter.targetId // 'postgres' | ||
| * ``` | ||
| */ | ||
| interface AdapterDescriptor<TFamilyId extends string, TTargetId extends string> extends ComponentDescriptor<'adapter'> { | ||
| /** The family this adapter belongs to */ | ||
| readonly familyId: TFamilyId; | ||
| /** The target this adapter is designed for */ | ||
| readonly targetId: TTargetId; | ||
| } | ||
| /** | ||
| * Descriptor for a driver component. | ||
| * | ||
| * A "driver" provides the connection and execution layer for a target. Drivers handle: | ||
| * - Connection management (pooling, timeouts, retries) | ||
| * - Query execution (sending SQL/commands, receiving results) | ||
| * - Transaction management | ||
| * - Wire protocol communication | ||
| * | ||
| * Drivers are bound to a specific family+target and work with any compatible adapter. Multiple drivers can exist for the same target (e.g., node-postgres vs postgres.js for Postgres). | ||
| * | ||
| * Extended by plane-specific descriptors: | ||
| * - `ControlDriverDescriptor` - creates driver from connection URL | ||
| * - `RuntimeDriverDescriptor` - creates driver with runtime options | ||
| * | ||
| * @template TFamilyId - Literal type for the family identifier | ||
| * @template TTargetId - Literal type for the target identifier | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import postgresDriver from '@prisma-next/driver-postgres/control'; | ||
| * | ||
| * postgresDriver.kind // 'driver' | ||
| * postgresDriver.familyId // 'sql' | ||
| * postgresDriver.targetId // 'postgres' | ||
| * ``` | ||
| */ | ||
| interface DriverDescriptor<TFamilyId extends string, TTargetId extends string> extends ComponentDescriptor<'driver'> { | ||
| /** The family this driver belongs to */ | ||
| readonly familyId: TFamilyId; | ||
| /** The target this driver connects to */ | ||
| readonly targetId: TTargetId; | ||
| } | ||
| /** | ||
| * Descriptor for an extension component. | ||
| * | ||
| * An "extension" adds optional capabilities to a target. Extensions can provide: | ||
| * - Additional operations (e.g., vector similarity search with pgvector) | ||
| * - Custom types and codecs (e.g., vector type) | ||
| * - Extended query capabilities | ||
| * | ||
| * Extensions are bound to a specific family+target and are registered in the config alongside the core components. Multiple extensions can be used together. | ||
| * | ||
| * Extended by plane-specific descriptors: | ||
| * - `ControlExtensionDescriptor` - control-plane extension factory | ||
| * - `RuntimeExtensionDescriptor` - runtime extension factory | ||
| * | ||
| * @template TFamilyId - Literal type for the family identifier | ||
| * @template TTargetId - Literal type for the target identifier | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import pgvector from '@prisma-next/extension-pgvector/control'; | ||
| * | ||
| * pgvector.kind // 'extension' | ||
| * pgvector.familyId // 'sql' | ||
| * pgvector.targetId // 'postgres' | ||
| * ``` | ||
| */ | ||
| interface ExtensionDescriptor<TFamilyId extends string, TTargetId extends string> extends ComponentDescriptor<'extension'> { | ||
| /** The family this extension belongs to */ | ||
| readonly familyId: TFamilyId; | ||
| /** The target this extension is designed for */ | ||
| readonly targetId: TTargetId; | ||
| } | ||
| /** Components bound to a specific family+target combination. */ | ||
| type TargetBoundComponentDescriptor<TFamilyId extends string, TTargetId extends string> = TargetDescriptor<TFamilyId, TTargetId> | AdapterDescriptor<TFamilyId, TTargetId> | DriverDescriptor<TFamilyId, TTargetId> | ExtensionDescriptor<TFamilyId, TTargetId>; | ||
| interface FamilyInstance<TFamilyId extends string> { | ||
| readonly familyId: TFamilyId; | ||
| } | ||
| interface TargetInstance<TFamilyId extends string, TTargetId extends string> { | ||
| readonly familyId: TFamilyId; | ||
| readonly targetId: TTargetId; | ||
| } | ||
| interface AdapterInstance<TFamilyId extends string, TTargetId extends string> { | ||
| readonly familyId: TFamilyId; | ||
| readonly targetId: TTargetId; | ||
| } | ||
| interface DriverInstance<TFamilyId extends string, TTargetId extends string> { | ||
| readonly familyId: TFamilyId; | ||
| readonly targetId: TTargetId; | ||
| } | ||
| interface ExtensionInstance<TFamilyId extends string, TTargetId extends string> { | ||
| readonly familyId: TFamilyId; | ||
| readonly targetId: TTargetId; | ||
| } | ||
| //#endregion | ||
| export { LoweredDefaultResult as A, ControlMutationDefaultEntry as C, DefaultFunctionLoweringHandler as D, DefaultFunctionLoweringContext as E, SourceSpan as F, MutationDefaultGeneratorDescriptor as M, ParsedDefaultFunctionCall as N, DefaultFunctionRegistry as O, SourceDiagnostic as P, checkContractComponentRequirements as S, ControlMutationDefaults as T, PackRefBase as _, ComponentMetadata as a, TargetInstance as b, DriverDescriptor as c, ExtensionDescriptor as d, ExtensionInstance as f, FamilyPackRef as g, FamilyInstance as h, ComponentDescriptor as i, LoweredDefaultValue as j, DefaultFunctionRegistryEntry as k, DriverInstance as l, FamilyDescriptor as m, AdapterInstance as n, ContractComponentRequirementsCheckInput as o, ExtensionPackRef as p, AdapterPackRef as r, ContractComponentRequirementsCheckResult as s, AdapterDescriptor as t, DriverPackRef as u, TargetBoundComponentDescriptor as v, ControlMutationDefaultRegistry as w, TargetPackRef as x, TargetDescriptor as y }; | ||
| //# sourceMappingURL=framework-components-5hA9ij1v.d.mts.map |
| {"version":3,"file":"framework-components-5hA9ij1v.d.mts","names":[],"sources":["../src/shared/mutation-default-types.ts","../src/shared/framework-components.ts"],"mappings":"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"} |
| import { r as CodecLookup } from "./codec-types-yY3eSmi0.mjs"; | ||
| import { R as PslDiagnosticCode, Y as PslSpan, h as AuthoringPslBlockDescriptorNamespace, z as PslExtensionBlock } from "./framework-authoring-CJC4jwGo.mjs"; | ||
| //#region src/control/psl-ast.d.ts | ||
| interface PslDiagnostic { | ||
| readonly code: PslDiagnosticCode; | ||
| readonly message: string; | ||
| readonly sourceId: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslDefaultFunctionValue { | ||
| readonly kind: 'function'; | ||
| readonly name: 'autoincrement' | 'now'; | ||
| } | ||
| interface PslDefaultLiteralValue { | ||
| readonly kind: 'literal'; | ||
| readonly value: string | number | boolean; | ||
| } | ||
| type PslDefaultValue = PslDefaultFunctionValue | PslDefaultLiteralValue; | ||
| type PslAttributeTarget = 'field' | 'model' | 'enum' | 'namedType'; | ||
| interface PslAttributePositionalArgument { | ||
| readonly kind: 'positional'; | ||
| readonly value: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslAttributeNamedArgument { | ||
| readonly kind: 'named'; | ||
| readonly name: string; | ||
| readonly value: string; | ||
| readonly span: PslSpan; | ||
| } | ||
| type PslAttributeArgument = PslAttributePositionalArgument | PslAttributeNamedArgument; | ||
| interface PslTypeConstructorCall { | ||
| readonly kind: 'typeConstructor'; | ||
| readonly path: readonly string[]; | ||
| readonly args: readonly PslAttributeArgument[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslAttribute { | ||
| readonly kind: 'attribute'; | ||
| readonly target: PslAttributeTarget; | ||
| readonly name: string; | ||
| readonly args: readonly PslAttributeArgument[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| type PslReferentialAction = string; | ||
| type PslFieldAttribute = PslAttribute; | ||
| interface PslField { | ||
| readonly kind: 'field'; | ||
| readonly name: string; | ||
| /** Unqualified type name, e.g. `"User"` for both `User`, `auth.User`, and `supabase:auth.User`. */ | ||
| readonly typeName: string; | ||
| /** Namespace qualifier from a dot-qualified type reference, e.g. `"auth"` for `auth.User` or `supabase:auth.User`. Absent for unqualified types. */ | ||
| readonly typeNamespaceId?: string; | ||
| /** | ||
| * Contract-space qualifier from a colon-prefix type reference, e.g. `"supabase"` for | ||
| * `supabase:auth.User` or `supabase:User`. Absent for local (same-space) type references. | ||
| * | ||
| * When present, the field references a model from a different contract space. The namespace | ||
| * (`typeNamespaceId`) and model name (`typeName`) identify the target within that space. | ||
| * Physical table resolution against the extension contract is deferred to the aggregate stage (M3). | ||
| */ | ||
| readonly typeContractSpaceId?: string; | ||
| readonly typeConstructor?: PslTypeConstructorCall; | ||
| readonly optional: boolean; | ||
| readonly list: boolean; | ||
| readonly typeRef?: string; | ||
| readonly attributes: readonly PslFieldAttribute[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslUniqueConstraint { | ||
| readonly kind: 'unique'; | ||
| readonly fields: readonly string[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslIndexConstraint { | ||
| readonly kind: 'index'; | ||
| readonly fields: readonly string[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| type PslModelAttribute = PslAttribute; | ||
| interface PslModel { | ||
| readonly kind: 'model'; | ||
| readonly name: string; | ||
| readonly fields: readonly PslField[]; | ||
| readonly attributes: readonly PslModelAttribute[]; | ||
| readonly span: PslSpan; | ||
| /** | ||
| * Optional leading comment line emitted above the `model` keyword by the | ||
| * printer. Producers (e.g. `sqlSchemaIrToPslAst`) attach introspection | ||
| * advisories such as "// WARNING: This table has no primary key in the | ||
| * database" here. The parser leaves this field unset; round-tripping a | ||
| * parsed schema does not re-attach comments. | ||
| */ | ||
| readonly comment?: string; | ||
| } | ||
| /** | ||
| * A reusable group of fields embedded in a model (a `type Name { … }` block) — | ||
| * e.g. a MongoDB embedded document or a Postgres composite type. Unlike | ||
| * {@link PslModel} it has no storage or identity of its own. | ||
| */ | ||
| interface PslCompositeType { | ||
| readonly kind: 'compositeType'; | ||
| readonly name: string; | ||
| readonly fields: readonly PslField[]; | ||
| readonly attributes: readonly PslAttribute[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslNamedTypeDeclaration { | ||
| readonly kind: 'namedType'; | ||
| readonly name: string; | ||
| /** | ||
| * Parser invariant: exactly one of `baseType` and `typeConstructor` is set. | ||
| * Expressing this as a discriminated union trips TypeScript narrowing when | ||
| * the declaration flows through helpers that accept the full union. | ||
| */ | ||
| readonly baseType?: string; | ||
| readonly typeConstructor?: PslTypeConstructorCall; | ||
| readonly attributes: readonly PslAttribute[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| interface PslTypesBlock { | ||
| readonly kind: 'types'; | ||
| readonly declarations: readonly PslNamedTypeDeclaration[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** | ||
| * Name of the synthesised namespace bucket the framework parser uses for | ||
| * top-level declarations that appear outside any `namespace { … }` block. | ||
| * The double-underscore decoration signals that the identifier is parser- | ||
| * synthesised and never appears in user-authored PSL source — writing | ||
| * `namespace __unspecified__ { … }` is a parse error. | ||
| * | ||
| * Distinct from the IR sentinel `__unbound__`: the PSL bucket describes | ||
| * syntactic absence at the parser layer; the IR sentinel describes a late- | ||
| * bound storage slot at the IR layer. Per-target interpreters decide how | ||
| * (or whether) to map the PSL bucket to the IR sentinel. | ||
| */ | ||
| declare const UNSPECIFIED_PSL_NAMESPACE_ID = "__unspecified__"; | ||
| /** A value in {@link PslNamespace.entries}: a built-in entity node or an extension-contributed {@link PslExtensionBlock}. */ | ||
| type PslNamespaceEntry = PslModel | PslCompositeType | PslExtensionBlock; | ||
| /** | ||
| * A namespace block, or the parser's synthesised `__unspecified__` bucket for | ||
| * declarations outside any `namespace { … }`. Same-name blocks reopen-merge; | ||
| * `span` points at the first opening. | ||
| * | ||
| * Entities are stored canonically (ADR 224) in `entries[kind][name]`, where | ||
| * `kind` is the PSL keyword for built-ins or the block discriminator for | ||
| * extension kinds, e.g. `entries['policy_select']['ReadPosts']`. | ||
| */ | ||
| interface PslNamespace { | ||
| readonly kind: 'namespace'; | ||
| readonly name: string; | ||
| /** Canonical store: a frozen container of frozen per-kind maps. The accessors below derive from it. */ | ||
| readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>; | ||
| /** Built-in models, from `entries['model']`. Extension kinds: {@link namespacePslExtensionBlocks}. */ | ||
| readonly models: readonly PslModel[]; | ||
| /** Built-in composite types, from `entries['compositeType']`. */ | ||
| readonly compositeTypes: readonly PslCompositeType[]; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** Constructs a {@link PslNamespace}. Use this, never a namespace literal — the accessors must derive from `entries`. */ | ||
| declare function makePslNamespace(init: { | ||
| readonly kind: 'namespace'; | ||
| readonly name: string; | ||
| readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>; | ||
| readonly span: PslSpan; | ||
| }): PslNamespace; | ||
| /** | ||
| * Builds the frozen `entries[kind][name]` container from per-kind arrays. | ||
| * Built-ins key on their PSL keyword; extension blocks key on their `kind` | ||
| * discriminator. Call this rather than hand-building the literal. | ||
| */ | ||
| declare function makePslNamespaceEntries(models: readonly PslModel[], compositeTypes: readonly PslCompositeType[], extensionBlocks: readonly PslExtensionBlock[]): Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>; | ||
| interface PslDocumentAst { | ||
| readonly kind: 'document'; | ||
| readonly sourceId: string; | ||
| readonly namespaces: readonly PslNamespace[]; | ||
| readonly types?: PslTypesBlock; | ||
| readonly span: PslSpan; | ||
| } | ||
| /** | ||
| * Returns all models from every namespace in document order. Convenience | ||
| * for consumers that don't (yet) need namespace-awareness. | ||
| */ | ||
| declare function flatPslModels(ast: PslDocumentAst): readonly PslModel[]; | ||
| /** | ||
| * Returns all composite types from every namespace in document order. | ||
| */ | ||
| declare function flatPslCompositeTypes(ast: PslDocumentAst): readonly PslCompositeType[]; | ||
| /** | ||
| * The set of `entries` kind keys that the framework parser reserves for | ||
| * built-in PSL entity kinds. Any own-enumerable key on `PslNamespace.entries` | ||
| * that is **not** in this set was contributed by an extension-block descriptor. | ||
| * | ||
| * Built-in keys match the PSL keyword used on each block type: | ||
| * `'model'`, `'compositeType'`. The `'enum'` keyword is claimed by the | ||
| * extension-block grammar via a registered descriptor, so `entries['enum']` | ||
| * holds `PslExtensionBlock` nodes and is returned by `namespacePslExtensionBlocks`. | ||
| */ | ||
| declare const BUILTIN_PSL_KIND_KEYS: ReadonlySet<string>; | ||
| /** | ||
| * Returns all extension-contributed blocks in the given namespace, in | ||
| * insertion order (the order the parser encountered them in the source). | ||
| * | ||
| * Reads from `namespace.entries`, skipping the built-in kind keys | ||
| * (`'model'`, `'compositeType'`). All remaining kind maps contain | ||
| * only `PslExtensionBlock` nodes by construction (see `makePslNamespaceEntries`). | ||
| */ | ||
| declare function namespacePslExtensionBlocks(ns: PslNamespace): readonly PslExtensionBlock[]; | ||
| interface ParsePslDocumentInput { | ||
| readonly schema: string; | ||
| readonly sourceId: string; | ||
| /** | ||
| * Registry of declarative block descriptors, keyed by arbitrary path | ||
| * segments with {@link AuthoringPslBlockDescriptor} leaves. The registry | ||
| * teaches the parser which top-level keywords belong to extension | ||
| * contributions: when the parser encounters an unknown keyword, it looks | ||
| * it up here and, when found, reads the block generically into a | ||
| * {@link PslExtensionBlock} node. Absent or undefined means no extension | ||
| * blocks are registered and any unknown keyword yields | ||
| * `PSL_UNSUPPORTED_TOP_LEVEL_BLOCK`. | ||
| * | ||
| * Contrast with the parsed block nodes themselves, which live in | ||
| * {@link PslNamespace.entries} under their discriminator key (read them with | ||
| * {@link namespacePslExtensionBlocks}); this field holds the registry of | ||
| * descriptors that teach the parser how to read those blocks. | ||
| */ | ||
| readonly pslBlockDescriptors?: AuthoringPslBlockDescriptorNamespace; | ||
| /** | ||
| * Codec lookup for validating `value`-kind extension block parameters. | ||
| * When provided alongside `pslBlockDescriptors`, the generic validator runs | ||
| * over every parsed extension block after the full AST is assembled, | ||
| * appending any diagnostics to the parse result. Absent or undefined means | ||
| * no codec validation runs; `ref` resolution still runs when namespace | ||
| * context is available (built from the assembled namespaces). | ||
| */ | ||
| readonly codecLookup?: CodecLookup; | ||
| } | ||
| interface ParsePslDocumentResult { | ||
| readonly ast: PslDocumentAst; | ||
| readonly diagnostics: readonly PslDiagnostic[]; | ||
| readonly ok: boolean; | ||
| } | ||
| //#endregion | ||
| export { makePslNamespace as A, PslReferentialAction as C, UNSPECIFIED_PSL_NAMESPACE_ID as D, PslUniqueConstraint as E, namespacePslExtensionBlocks as M, flatPslCompositeTypes as O, PslNamespaceEntry as S, PslTypesBlock as T, PslIndexConstraint as _, PslAttributeArgument as a, PslNamedTypeDeclaration as b, PslAttributeTarget as c, PslDefaultLiteralValue as d, PslDefaultValue as f, PslFieldAttribute as g, PslField as h, PslAttribute as i, makePslNamespaceEntries as j, flatPslModels as k, PslCompositeType as l, PslDocumentAst as m, ParsePslDocumentInput as n, PslAttributeNamedArgument as o, PslDiagnostic as p, ParsePslDocumentResult as r, PslAttributePositionalArgument as s, BUILTIN_PSL_KIND_KEYS as t, PslDefaultFunctionValue as u, PslModel as v, PslTypeConstructorCall as w, PslNamespace as x, PslModelAttribute as y }; | ||
| //# sourceMappingURL=psl-ast-B-C_9dWr.d.mts.map |
| {"version":3,"file":"psl-ast-B-C_9dWr.d.mts","names":[],"sources":["../src/control/psl-ast.ts"],"mappings":"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"} |
| export const VERIFY_CODE_MARKER_MISSING = 'PN-RUN-3001'; | ||
| export const VERIFY_CODE_HASH_MISMATCH = 'PN-RUN-3002'; | ||
| export const VERIFY_CODE_TARGET_MISMATCH = 'PN-RUN-3003'; | ||
| export const VERIFY_CODE_SCHEMA_FAILURE = 'PN-RUN-3010'; | ||
| export interface OperationContext { | ||
| readonly contractPath?: string; | ||
| readonly configPath?: string; | ||
| readonly meta?: Readonly<Record<string, unknown>>; | ||
| } | ||
| export interface VerifyDatabaseResult { | ||
| readonly ok: boolean; | ||
| readonly code?: string; | ||
| readonly summary: string; | ||
| readonly contract: { | ||
| readonly storageHash: string; | ||
| readonly profileHash?: string; | ||
| }; | ||
| readonly marker?: { | ||
| readonly storageHash?: string; | ||
| readonly profileHash?: string; | ||
| }; | ||
| readonly target: { | ||
| readonly expected: string; | ||
| readonly actual?: string; | ||
| }; | ||
| readonly missingCodecs?: readonly string[]; | ||
| readonly codecCoverageSkipped?: boolean; | ||
| readonly meta?: { | ||
| readonly configPath?: string; | ||
| readonly contractPath: string; | ||
| }; | ||
| readonly timings: { | ||
| readonly total: number; | ||
| }; | ||
| } | ||
| export interface BaseSchemaIssue { | ||
| readonly kind: | ||
| | 'missing_schema' | ||
| | 'missing_table' | ||
| | 'missing_column' | ||
| | 'extra_table' | ||
| | 'extra_column' | ||
| | 'extra_primary_key' | ||
| | 'extra_foreign_key' | ||
| | 'extra_unique_constraint' | ||
| | 'extra_index' | ||
| | 'extra_validator' | ||
| | 'type_mismatch' | ||
| | 'type_missing' | ||
| | 'type_values_mismatch' | ||
| | 'nullability_mismatch' | ||
| | 'primary_key_mismatch' | ||
| | 'foreign_key_mismatch' | ||
| | 'unique_constraint_mismatch' | ||
| | 'index_mismatch' | ||
| | 'default_missing' | ||
| | 'default_mismatch' | ||
| | 'extra_default' | ||
| | 'check_missing' | ||
| | 'check_removed' | ||
| | 'check_mismatch'; | ||
| readonly table?: string; | ||
| /** | ||
| * Namespace coordinate of the issue's subject (e.g. the schema a SQL | ||
| * table lives in). Populated by family verifiers that have the | ||
| * coordinate in scope when constructing the issue; absent for issues | ||
| * whose family has no namespace concept (e.g. Mongo collections) or | ||
| * whose subject isn't in any contract namespace (e.g. an extra-table | ||
| * issue raised for a table that exists in the live DB but not in the | ||
| * contract). | ||
| * | ||
| * Downstream planners trust this field as the authoritative subject | ||
| * coordinate and do not re-derive it by name lookup. A finer-grained | ||
| * structural split between framework-shared and family-specific issue | ||
| * fields is tracked under a follow-up ticket. | ||
| */ | ||
| readonly namespaceId?: string; | ||
| readonly column?: string; | ||
| readonly indexOrConstraint?: string; | ||
| readonly typeName?: string; | ||
| readonly expected?: string; | ||
| readonly actual?: string; | ||
| readonly message: string; | ||
| } | ||
| export interface EnumValuesChangedIssue { | ||
| readonly kind: 'enum_values_changed'; | ||
| /** | ||
| * Namespace coordinate of the enum type that changed values. Populated by | ||
| * family verifiers that have the coordinate in scope when constructing the | ||
| * issue. Downstream planners trust this field as the authoritative subject | ||
| * coordinate and do not re-derive it by name lookup. | ||
| */ | ||
| readonly namespaceId: string; | ||
| readonly typeName: string; | ||
| readonly addedValues: readonly string[]; | ||
| readonly removedValues: readonly string[]; | ||
| readonly message: string; | ||
| } | ||
| export type SchemaIssue = BaseSchemaIssue | EnumValuesChangedIssue; | ||
| export interface SchemaVerificationNode { | ||
| readonly status: 'pass' | 'warn' | 'fail'; | ||
| readonly kind: string; | ||
| readonly name: string; | ||
| readonly contractPath: string; | ||
| readonly code: string; | ||
| readonly message: string; | ||
| readonly expected: unknown; | ||
| readonly actual: unknown; | ||
| readonly children: readonly SchemaVerificationNode[]; | ||
| } | ||
| export interface VerifyDatabaseSchemaResult { | ||
| readonly ok: boolean; | ||
| readonly code?: string; | ||
| readonly summary: string; | ||
| readonly contract: { | ||
| readonly storageHash: string; | ||
| readonly profileHash?: string; | ||
| }; | ||
| readonly target: { | ||
| readonly expected: string; | ||
| readonly actual?: string; | ||
| }; | ||
| readonly schema: { | ||
| readonly issues: readonly SchemaIssue[]; | ||
| readonly root: SchemaVerificationNode; | ||
| readonly counts: { | ||
| readonly pass: number; | ||
| readonly warn: number; | ||
| readonly fail: number; | ||
| readonly totalNodes: number; | ||
| }; | ||
| }; | ||
| readonly meta?: { | ||
| readonly configPath?: string; | ||
| readonly contractPath?: string; | ||
| readonly strict: boolean; | ||
| }; | ||
| readonly timings: { | ||
| readonly total: number; | ||
| }; | ||
| } | ||
| export interface EmitContractResult { | ||
| readonly contractJson: string; | ||
| readonly contractDts: string; | ||
| readonly storageHash: string; | ||
| readonly executionHash?: string; | ||
| readonly profileHash: string; | ||
| } | ||
| export interface IntrospectSchemaResult<TSchemaIR> { | ||
| readonly ok: true; | ||
| readonly summary: string; | ||
| readonly target: { | ||
| readonly familyId: string; | ||
| readonly id: string; | ||
| }; | ||
| readonly schema: TSchemaIR; | ||
| readonly meta?: { | ||
| readonly configPath?: string; | ||
| readonly dbUrl?: string; | ||
| }; | ||
| readonly timings: { | ||
| readonly total: number; | ||
| }; | ||
| } | ||
| export interface SignDatabaseResult { | ||
| readonly ok: boolean; | ||
| readonly summary: string; | ||
| readonly contract: { | ||
| readonly storageHash: string; | ||
| readonly profileHash?: string; | ||
| }; | ||
| readonly target: { | ||
| readonly expected: string; | ||
| readonly actual?: string; | ||
| }; | ||
| readonly marker: { | ||
| readonly created: boolean; | ||
| readonly updated: boolean; | ||
| readonly previous?: { | ||
| readonly storageHash?: string; | ||
| readonly profileHash?: string; | ||
| }; | ||
| }; | ||
| readonly meta?: { | ||
| readonly configPath?: string; | ||
| readonly contractPath: string; | ||
| }; | ||
| readonly timings: { | ||
| readonly total: number; | ||
| }; | ||
| } |
1069814
15.12%122
4.27%10080
14.56%+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
Updated