@prisma-next/framework-components 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/authoring.d.mts +2 -2
  2. package/dist/authoring.mjs +1 -1
  3. package/dist/{codec-DCQAerzB.d.mts → codec-types-yY3eSmi0.d.mts} +90 -67
  4. package/dist/codec-types-yY3eSmi0.d.mts.map +1 -0
  5. package/dist/codec.d.mts +31 -2
  6. package/dist/codec.d.mts.map +1 -1
  7. package/dist/codec.mjs +2 -1
  8. package/dist/codec.mjs.map +1 -1
  9. package/dist/components.d.mts +1 -1
  10. package/dist/control.d.mts +13 -25
  11. package/dist/control.d.mts.map +1 -1
  12. package/dist/control.mjs +12 -2
  13. package/dist/control.mjs.map +1 -1
  14. package/dist/{emission-types-vfpSTe63.d.mts → emission-types-C561PwcN.d.mts} +4 -4
  15. package/dist/emission-types-C561PwcN.d.mts.map +1 -0
  16. package/dist/emission.d.mts +1 -1
  17. package/dist/execution.d.mts +1 -1
  18. package/dist/{framework-authoring-R0TYCkvG.d.mts → framework-authoring-CJC4jwGo.d.mts} +121 -9
  19. package/dist/framework-authoring-CJC4jwGo.d.mts.map +1 -0
  20. package/dist/{framework-authoring-CnwPJCO4.mjs → framework-authoring-Dv5F3EFC.mjs} +51 -24
  21. package/dist/framework-authoring-Dv5F3EFC.mjs.map +1 -0
  22. package/dist/{framework-components-DDQXmW0b.d.mts → framework-components-5hA9ij1v.d.mts} +3 -3
  23. package/dist/{framework-components-DDQXmW0b.d.mts.map → framework-components-5hA9ij1v.d.mts.map} +1 -1
  24. package/dist/ir.d.mts +34 -4
  25. package/dist/ir.d.mts.map +1 -1
  26. package/dist/ir.mjs +51 -6
  27. package/dist/ir.mjs.map +1 -1
  28. package/dist/{psl-ast-Cn50B-UG.d.mts → psl-ast-B-C_9dWr.d.mts} +11 -37
  29. package/dist/psl-ast-B-C_9dWr.d.mts.map +1 -0
  30. package/dist/psl-ast.d.mts +4 -4
  31. package/dist/psl-ast.mjs +18 -32
  32. package/dist/psl-ast.mjs.map +1 -1
  33. package/dist/resolve-codec-D8EPZosv.mjs +59 -0
  34. package/dist/resolve-codec-D8EPZosv.mjs.map +1 -0
  35. package/dist/runtime-error-B2gWOtgH.mjs +37 -0
  36. package/dist/runtime-error-B2gWOtgH.mjs.map +1 -0
  37. package/dist/runtime.d.mts +12 -10
  38. package/dist/runtime.d.mts.map +1 -1
  39. package/dist/runtime.mjs +1 -33
  40. package/dist/runtime.mjs.map +1 -1
  41. package/package.json +7 -7
  42. package/src/control/control-migration-types.ts +5 -22
  43. package/src/control/control-stack.ts +28 -3
  44. package/src/control/emission-types.ts +3 -3
  45. package/src/control/psl-ast.ts +10 -61
  46. package/src/control/psl-extension-block-validator.ts +11 -9
  47. package/src/execution/runtime-error.ts +5 -55
  48. package/src/exports/authoring.ts +1 -0
  49. package/src/exports/codec.ts +7 -0
  50. package/src/exports/control.ts +0 -1
  51. package/src/exports/ir.ts +3 -1
  52. package/src/ir/entity-kind.ts +54 -0
  53. package/src/ir/storage.ts +32 -6
  54. package/src/shared/codec-descriptor.ts +5 -0
  55. package/src/shared/codec-types.ts +21 -1
  56. package/src/shared/framework-authoring.ts +118 -35
  57. package/src/shared/psl-extension-block.ts +85 -5
  58. package/src/shared/resolve-codec.ts +86 -0
  59. package/src/shared/runtime-error.ts +50 -0
  60. package/dist/codec-DCQAerzB.d.mts.map +0 -1
  61. package/dist/emission-types-vfpSTe63.d.mts.map +0 -1
  62. package/dist/framework-authoring-CnwPJCO4.mjs.map +0 -1
  63. package/dist/framework-authoring-R0TYCkvG.d.mts.map +0 -1
  64. package/dist/psl-ast-Cn50B-UG.d.mts.map +0 -1
@@ -54,12 +54,19 @@ function hasRegisteredFieldNamespace(contributions, namespace) {
54
54
  if (contributions?.field === void 0 || !Object.hasOwn(contributions.field, namespace)) return false;
55
55
  return !isAuthoringFieldPresetDescriptor(contributions.field[namespace]);
56
56
  }
57
- function isPlainNamespaceObject(value) {
58
- return typeof value === "object" && value !== null && !Array.isArray(value);
57
+ function isCopyableNamespaceObject(value) {
58
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
59
+ const proto = Object.getPrototypeOf(value);
60
+ return proto === Object.prototype || proto === null;
61
+ }
62
+ function deepCopyNamespace(source, isLeafDescriptor) {
63
+ const copy = {};
64
+ for (const [key, value] of Object.entries(source)) copy[key] = isCopyableNamespaceObject(value) && !isLeafDescriptor(value) ? deepCopyNamespace(value, isLeafDescriptor) : value;
65
+ return copy;
59
66
  }
60
67
  /**
61
68
  * Merges `source` into `target` recursively at the descriptor-namespace
62
- * level. `leafGuard` decides which values are descriptors (terminal
69
+ * level. `isLeafDescriptor` decides which values are descriptors (terminal
63
70
  * merge points; same-path registrations across components are reported
64
71
  * as duplicates) versus sub-namespaces (recursion targets).
65
72
  *
@@ -75,7 +82,7 @@ function isPlainNamespaceObject(value) {
75
82
  * cross-registry detection runs separately via
76
83
  * `assertNoCrossRegistryCollisions` after merging completes.
77
84
  */
78
- function mergeAuthoringNamespaces(target, source, path, leafGuard, label) {
85
+ function mergeAuthoringNamespaces(target, source, path, isLeafDescriptor, label) {
79
86
  const assertSafePath = (currentPath) => {
80
87
  const blockedSegment = currentPath.find((segment) => segment === "__proto__" || segment === "constructor" || segment === "prototype");
81
88
  if (blockedSegment) throw new Error(`Invalid authoring ${label} helper "${currentPath.join(".")}". Helper path segments must not use "${blockedSegment}".`);
@@ -86,17 +93,17 @@ function mergeAuthoringNamespaces(target, source, path, leafGuard, label) {
86
93
  const hasExistingValue = Object.hasOwn(target, key);
87
94
  const existingValue = hasExistingValue ? target[key] : void 0;
88
95
  if (!hasExistingValue) {
89
- target[key] = sourceValue;
96
+ target[key] = isCopyableNamespaceObject(sourceValue) && !isLeafDescriptor(sourceValue) ? deepCopyNamespace(sourceValue, isLeafDescriptor) : sourceValue;
90
97
  continue;
91
98
  }
92
- const existingIsLeaf = leafGuard(existingValue);
93
- const sourceIsLeaf = leafGuard(sourceValue);
99
+ const existingIsLeaf = isLeafDescriptor(existingValue);
100
+ const sourceIsLeaf = isLeafDescriptor(sourceValue);
94
101
  if (existingIsLeaf || sourceIsLeaf) throw new Error(`Duplicate authoring ${label} helper "${currentPath.join(".")}". Helper names must be unique across composed packs.`);
95
- if (!isPlainNamespaceObject(existingValue) || !isPlainNamespaceObject(sourceValue)) throw new Error(`Invalid authoring ${label} helper "${currentPath.join(".")}". Expected a sub-namespace object or a recognized descriptor; received a malformed value.`);
96
- mergeAuthoringNamespaces(existingValue, sourceValue, currentPath, leafGuard, label);
102
+ 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.`);
103
+ mergeAuthoringNamespaces(existingValue, sourceValue, currentPath, isLeafDescriptor, label);
97
104
  }
98
105
  }
99
- function collectAuthoringLeafPaths(namespace, isLeaf, path = []) {
106
+ function collectDescriptorPaths(namespace, isLeaf, path = []) {
100
107
  const paths = [];
101
108
  for (const [key, value] of Object.entries(namespace)) {
102
109
  const currentPath = [...path, key];
@@ -104,11 +111,11 @@ function collectAuthoringLeafPaths(namespace, isLeaf, path = []) {
104
111
  paths.push(currentPath.join("."));
105
112
  continue;
106
113
  }
107
- if (typeof value === "object" && value !== null && !Array.isArray(value)) paths.push(...collectAuthoringLeafPaths(value, isLeaf, currentPath));
114
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) paths.push(...collectDescriptorPaths(value, isLeaf, currentPath));
108
115
  }
109
116
  return paths;
110
117
  }
111
- function collectAuthoringLeafDiscriminators(namespace, isLeaf, label, path = []) {
118
+ function collectDescriptorEntries(namespace, isLeaf, label, path = []) {
112
119
  const entries = [];
113
120
  for (const [key, value] of Object.entries(namespace)) {
114
121
  const currentPath = [...path, key];
@@ -128,7 +135,7 @@ function collectAuthoringLeafDiscriminators(namespace, isLeaf, label, path = [])
128
135
  const hasDiscriminator = typeof record["discriminator"] === "string";
129
136
  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.`);
130
137
  }
131
- entries.push(...collectAuthoringLeafDiscriminators(record, isLeaf, label, currentPath));
138
+ entries.push(...collectDescriptorEntries(record, isLeaf, label, currentPath));
132
139
  }
133
140
  }
134
141
  return entries;
@@ -147,25 +154,45 @@ function assertUniqueDiscriminators(entries, label) {
147
154
  seen.set(discriminator, path);
148
155
  }
149
156
  }
157
+ function collectPslBlockDescriptorEntries(namespace, path = []) {
158
+ const entries = [];
159
+ for (const [key, value] of Object.entries(namespace)) {
160
+ const currentPath = [...path, key];
161
+ if (isAuthoringPslBlockDescriptor(value)) {
162
+ entries.push({
163
+ path: currentPath.join("."),
164
+ discriminator: value.discriminator
165
+ });
166
+ continue;
167
+ }
168
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
169
+ const record = blindCast(value);
170
+ const hasKind = record["kind"] === "pslBlock";
171
+ const hasKeyword = typeof record["keyword"] === "string";
172
+ const hasDiscriminator = typeof record["discriminator"] === "string";
173
+ 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.`);
174
+ entries.push(...collectPslBlockDescriptorEntries(record, currentPath));
175
+ }
176
+ }
177
+ return entries;
178
+ }
150
179
  /**
151
- * Every `pslBlockDescriptors` entry needs a matching `entityTypes` factory
152
- * (same discriminator): the parser would otherwise produce an AST node
153
- * nothing can lower to an IR class instance. The link is one-directional
154
- * — an `entityTypes` factory may stand alone (e.g. `enum`, reachable from
155
- * the TypeScript builder without any PSL block).
180
+ * Every `pslBlockDescriptors` entry requires a matching `entityTypes` factory
181
+ * with the same discriminator. An `entityTypes` factory may stand alone (e.g.
182
+ * `enum`, reachable from the TypeScript builder without any PSL block).
156
183
  */
157
184
  function assertPslBlocksHaveFactories(entityTypeNamespace, pslBlockNamespace) {
158
- const blockEntries = collectAuthoringLeafDiscriminators(pslBlockNamespace, isAuthoringPslBlockDescriptor, "pslBlock");
159
- const entityEntries = collectAuthoringLeafDiscriminators(entityTypeNamespace, isAuthoringEntityTypeDescriptor, "entityType");
185
+ const blockEntries = collectPslBlockDescriptorEntries(pslBlockNamespace);
186
+ const entityEntries = collectDescriptorEntries(entityTypeNamespace, isAuthoringEntityTypeDescriptor, "entityType");
160
187
  assertUniqueDiscriminators(blockEntries, "pslBlock");
161
188
  assertUniqueDiscriminators(entityEntries, "entityType");
162
189
  const entityDiscriminators = new Set(entityEntries.map((entry) => entry.discriminator));
163
190
  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}".`);
164
191
  }
165
192
  function assertNoCrossRegistryCollisions(typeNamespace, fieldNamespace, entityTypeNamespace = {}, pslBlockNamespace = {}) {
166
- const typePaths = new Set(collectAuthoringLeafPaths(typeNamespace, isAuthoringTypeConstructorDescriptor));
167
- const fieldPaths = new Set(collectAuthoringLeafPaths(fieldNamespace, isAuthoringFieldPresetDescriptor));
168
- const entityPaths = new Set(collectAuthoringLeafPaths(entityTypeNamespace, isAuthoringEntityTypeDescriptor));
193
+ const typePaths = new Set(collectDescriptorPaths(typeNamespace, isAuthoringTypeConstructorDescriptor));
194
+ const fieldPaths = new Set(collectDescriptorPaths(fieldNamespace, isAuthoringFieldPresetDescriptor));
195
+ const entityPaths = new Set(collectDescriptorPaths(entityTypeNamespace, isAuthoringEntityTypeDescriptor));
169
196
  const ambiguityHint = "Register each path in only one of authoringContributions.field / authoringContributions.type / authoringContributions.entityTypes.";
170
197
  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}`);
171
198
  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}`);
@@ -298,4 +325,4 @@ function instantiateAuthoringFieldPreset(descriptor, args) {
298
325
  //#endregion
299
326
  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 };
300
327
 
301
- //# sourceMappingURL=framework-authoring-CnwPJCO4.mjs.map
328
+ //# sourceMappingURL=framework-authoring-Dv5F3EFC.mjs.map
@@ -0,0 +1 @@
1
+ {"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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"}
@@ -1,5 +1,5 @@
1
- import { i as AuthoringContributions } from "./framework-authoring-R0TYCkvG.mjs";
2
- import { r as AnyCodecDescriptor } from "./codec-DCQAerzB.mjs";
1
+ import { f as AnyCodecDescriptor } from "./codec-types-yY3eSmi0.mjs";
2
+ import { i as AuthoringContributions } from "./framework-authoring-CJC4jwGo.mjs";
3
3
  import { t as TypesImportSpec } from "./types-import-spec-DRKzrJ20.mjs";
4
4
  import { ColumnDefault, ExecutionMutationDefaultPhases, ExecutionMutationDefaultValue } from "@prisma-next/contract/types";
5
5
 
@@ -409,4 +409,4 @@ interface ExtensionInstance<TFamilyId extends string, TTargetId extends string>
409
409
  }
410
410
  //#endregion
411
411
  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 };
412
- //# sourceMappingURL=framework-components-DDQXmW0b.d.mts.map
412
+ //# sourceMappingURL=framework-components-5hA9ij1v.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"framework-components-DDQXmW0b.d.mts","names":[],"sources":["../src/shared/mutation-default-types.ts","../src/shared/framework-components.ts"],"mappings":"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"}
1
+ {"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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"}
package/dist/ir.d.mts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { ApplicationDomain, StorageBase, StorageNamespace } from "@prisma-next/contract/types";
2
+ import { isPlainRecord } from "@prisma-next/contract/is-plain-record";
3
+ import { Type } from "arktype";
2
4
 
3
5
  //#region src/ir/ir-node.d.ts
4
6
  /**
@@ -153,13 +155,20 @@ interface EntityCoordinate {
153
155
  * value, yielded as {@link EntityCoordinate} tuples with
154
156
  * `plane: 'storage'` (the parameter type binds the plane).
155
157
  *
156
- * Iterates each namespace's `entries` slot maps structurally. Skips
158
+ * Iterates each namespace's `entries` kind maps structurally. Skips
157
159
  * non-object `entries`; `id` and `kind` are not walked (`kind` is
158
160
  * non-enumerable on concretions). For every entity-kind key under
159
161
  * `entries` whose value is a non-null object, yields one coordinate per
160
- * entity name in that map. No family-specific slot vocabulary is required.
162
+ * entity name in that map. No family-specific kind vocabulary is required.
161
163
  */
162
164
  declare function elementCoordinates(storage: Pick<StorageBase, 'namespaces'>): Generator<EntityCoordinate>;
165
+ /**
166
+ * Looks up a single entity in a `Storage`-shaped value by its full coordinate.
167
+ * Returns `undefined` if the namespace, entity kind, or entity name is absent.
168
+ * The type parameter is a caller assertion — the walk itself is structural
169
+ * and cannot verify the entity's shape.
170
+ */
171
+ declare function entityAt<T = unknown>(storage: Pick<StorageBase, 'namespaces'>, coord: Pick<EntityCoordinate, 'namespaceId' | 'entityKind' | 'entityName'>): T | undefined;
163
172
  /**
164
173
  * Framework-level promise that every Contract IR / Schema IR carries a
165
174
  * collection of namespaces keyed by namespace id. Family storage
@@ -175,7 +184,7 @@ declare function elementCoordinates(storage: Pick<StorageBase, 'namespaces'>): G
175
184
  * is honest at every layer.
176
185
  *
177
186
  * Extends `IRNode` so the framework's IR-walking surfaces (verifiers,
178
- * serializers) can dispatch on `Storage`-typed slots through the same
187
+ * serializers) can dispatch on `Storage`-typed fields through the same
179
188
  * IR-node alphabet as every other node — the structural dual already
180
189
  * holds in code (every concrete storage class extends an IR-node base);
181
190
  * the interface promotion makes the typing honest.
@@ -209,6 +218,27 @@ interface Storage extends IRNode {
209
218
  */
210
219
  declare function domainElementCoordinates(domain: Pick<ApplicationDomain, 'namespaces'>): Generator<EntityCoordinate>;
211
220
  //#endregion
221
+ //#region src/ir/entity-kind.d.ts
222
+ interface EntityKindDescriptor<Input, Node> {
223
+ readonly kind: string;
224
+ readonly schema: Type<unknown>;
225
+ readonly construct: (input: Input) => Node;
226
+ }
227
+ type AnyEntityKindDescriptor = EntityKindDescriptor<never, unknown>;
228
+ /**
229
+ * Hydrates a namespace's entities from raw JSON maps into IR class instances.
230
+ *
231
+ * For each kind in `entries`: if the descriptor map has a descriptor,
232
+ * construct each inner-map value; otherwise freeze-and-carry (`'carry'`)
233
+ * or throw naming the kind and nsId (`'fail'`).
234
+ *
235
+ * The single boundary cast hands `value` to `descriptor.construct` as its
236
+ * `Input`. The value satisfies the kind's `Input` either by the
237
+ * entries-input contract at authoring time or by prior `validateStorage`
238
+ * validation at hydration time.
239
+ */
240
+ declare function hydrateNamespaceEntities(entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>, kinds: ReadonlyMap<string, AnyEntityKindDescriptor>, onUnknown: 'carry' | 'fail', nsId?: string): Record<string, Readonly<Record<string, unknown>>>;
241
+ //#endregion
212
242
  //#region src/ir/storage-type.d.ts
213
243
  /**
214
244
  * Framework-level alphabet for entries in a storage `types` slot.
@@ -232,5 +262,5 @@ interface StorageType extends IRNode {
232
262
  readonly kind: string;
233
263
  }
234
264
  //#endregion
235
- export { type EntityCoordinate, type IRNode, IRNodeBase, type Namespace, NamespaceBase, type Storage, type StorageType, UNBOUND_NAMESPACE_ID, domainElementCoordinates, elementCoordinates, freezeNode };
265
+ 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 };
236
266
  //# sourceMappingURL=ir.d.mts.map
package/dist/ir.d.mts.map CHANGED
@@ -1 +1 @@
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/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;;;;;;;;;;;;;;;;;;;;AAE2D;AAG3D;UALiB,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,UErBiB,gBAAA;EAAA,SACN,KAAA;EAAA,SACA,WAAA;EAAA,SACA,UAAA;EAAA,SACA,UAAA;AAAA;;;AFkC6C;;;;AChCxD;;;;AAA0D;iBCYzC,kBAAA,CACf,OAAA,EAAS,IAAA,CAAK,WAAA,kBACb,SAAA,CAAU,gBAAA;;;;;;;;;;;;;;;;;;;;ADsB8C;AAG3D;;;;;;;;;;;;;;;UCuBiB,OAAA,SAAgB,MAAA;EAAA,SACtB,UAAA,EAAY,QAAA,CAAS,MAAA,SAAe,SAAA;AAAA;;;;AFhD/C;;;;AACe;AAGf;iBGnCiB,wBAAA,CACf,MAAA,EAAQ,IAAA,CAAK,iBAAA,kBACZ,SAAA,CAAU,gBAAA;;;;;AH6Bb;;;;AACe;AAGf;;;;AACwB;AAYxB;;;;;;UItCiB,WAAA,SAAoB,MAAM;EAAA,SAChC,IAAI;AAAA"}
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"}
package/dist/ir.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ import { blindCast } from "@prisma-next/utils/casts";
2
+ import { isPlainRecord } from "@prisma-next/contract/is-plain-record";
1
3
  //#region src/ir/domain.ts
2
4
  /**
3
5
  * Lazy walk over every named domain entity in a {@link ApplicationDomain},
@@ -19,6 +21,33 @@ function* domainElementCoordinates(domain) {
19
21
  }
20
22
  }
21
23
  //#endregion
24
+ //#region src/ir/entity-kind.ts
25
+ /**
26
+ * Hydrates a namespace's entities from raw JSON maps into IR class instances.
27
+ *
28
+ * For each kind in `entries`: if the descriptor map has a descriptor,
29
+ * construct each inner-map value; otherwise freeze-and-carry (`'carry'`)
30
+ * or throw naming the kind and nsId (`'fail'`).
31
+ *
32
+ * The single boundary cast hands `value` to `descriptor.construct` as its
33
+ * `Input`. The value satisfies the kind's `Input` either by the
34
+ * entries-input contract at authoring time or by prior `validateStorage`
35
+ * validation at hydration time.
36
+ */
37
+ function hydrateNamespaceEntities(entries, kinds, onUnknown, nsId) {
38
+ const result = {};
39
+ for (const [kind, rawMap] of Object.entries(entries)) {
40
+ const descriptor = kinds.get(kind);
41
+ if (descriptor !== void 0) {
42
+ const built = {};
43
+ for (const [name, value] of Object.entries(rawMap)) built[name] = descriptor.construct(blindCast(value));
44
+ result[kind] = Object.freeze(built);
45
+ } else if (onUnknown === "carry") result[kind] = Object.freeze(rawMap);
46
+ else throw new Error(`Unknown entries key "${kind}" in namespace "${nsId ?? "?"}"; no hydration factory registered for this entity kind`);
47
+ }
48
+ return result;
49
+ }
50
+ //#endregion
22
51
  //#region src/ir/ir-node.ts
23
52
  var IRNodeBase = class {};
24
53
  /**
@@ -68,19 +97,19 @@ var NamespaceBase = class extends IRNodeBase {};
68
97
  * value, yielded as {@link EntityCoordinate} tuples with
69
98
  * `plane: 'storage'` (the parameter type binds the plane).
70
99
  *
71
- * Iterates each namespace's `entries` slot maps structurally. Skips
100
+ * Iterates each namespace's `entries` kind maps structurally. Skips
72
101
  * non-object `entries`; `id` and `kind` are not walked (`kind` is
73
102
  * non-enumerable on concretions). For every entity-kind key under
74
103
  * `entries` whose value is a non-null object, yields one coordinate per
75
- * entity name in that map. No family-specific slot vocabulary is required.
104
+ * entity name in that map. No family-specific kind vocabulary is required.
76
105
  */
77
106
  function* elementCoordinates(storage) {
78
107
  for (const [namespaceId, ns] of Object.entries(storage.namespaces)) {
79
108
  const entries = ns.entries;
80
109
  if (entries === null || typeof entries !== "object") continue;
81
- for (const [entityKind, slot] of Object.entries(entries)) {
82
- if (slot === null || typeof slot !== "object") continue;
83
- for (const entityName of Object.keys(slot)) yield {
110
+ for (const [entityKind, kindMap] of Object.entries(entries)) {
111
+ if (kindMap === null || typeof kindMap !== "object") continue;
112
+ for (const entityName of Object.keys(kindMap)) yield {
84
113
  plane: "storage",
85
114
  namespaceId,
86
115
  entityKind,
@@ -89,7 +118,23 @@ function* elementCoordinates(storage) {
89
118
  }
90
119
  }
91
120
  }
121
+ /**
122
+ * Looks up a single entity in a `Storage`-shaped value by its full coordinate.
123
+ * Returns `undefined` if the namespace, entity kind, or entity name is absent.
124
+ * The type parameter is a caller assertion — the walk itself is structural
125
+ * and cannot verify the entity's shape.
126
+ */
127
+ function entityAt(storage, coord) {
128
+ const ns = storage.namespaces[coord.namespaceId];
129
+ if (ns === void 0) return void 0;
130
+ const entries = ns.entries;
131
+ if (!isPlainRecord(entries)) return void 0;
132
+ const kindMap = entries[coord.entityKind];
133
+ if (!isPlainRecord(kindMap)) return void 0;
134
+ if (!Object.hasOwn(kindMap, coord.entityName)) return void 0;
135
+ return blindCast(kindMap[coord.entityName]);
136
+ }
92
137
  //#endregion
93
- export { IRNodeBase, NamespaceBase, UNBOUND_NAMESPACE_ID, domainElementCoordinates, elementCoordinates, freezeNode };
138
+ export { IRNodeBase, NamespaceBase, UNBOUND_NAMESPACE_ID, domainElementCoordinates, elementCoordinates, entityAt, freezeNode, hydrateNamespaceEntities, isPlainRecord };
94
139
 
95
140
  //# sourceMappingURL=ir.mjs.map
package/dist/ir.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ir.mjs","names":[],"sources":["../src/ir/domain.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","/**\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 type { StorageBase } from '@prisma-next/contract/types';\nimport type { IRNode } from './ir-node';\nimport type { Namespace } from './namespace';\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` slot 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 slot 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, slot] of Object.entries(entries)) {\n if (slot === null || typeof slot !== 'object') continue;\n for (const entityName of Object.keys(slot)) {\n yield { plane: 'storage', namespaceId, entityKind, entityName };\n }\n }\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 slots 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;;;ACuBA,IAAsB,aAAtB,MAAmD,CAEnD;;;;;;;;;;AAWA,SAAgB,WAA6B,MAAY;CACvD,OAAO,OAAO,IAAI;CAClB,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA,MAAa,uBAAuB;AAuCpC,IAAsB,gBAAtB,cAA4C,WAAgC,CAI5E;;;;;;;;;;;;;;AC/BA,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,SAAS,OAAO,QAAQ,OAAO,GAAG;GACxD,IAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;GAC/C,KAAK,MAAM,cAAc,OAAO,KAAK,IAAI,GACvC,MAAM;IAAE,OAAO;IAAW;IAAa;IAAY;GAAW;EAElE;CACF;AACF"}
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"}