🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@prisma-next/framework-components

Package Overview
Dependencies
Maintainers
4
Versions
442
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@prisma-next/framework-components - npm Package Compare versions

Comparing version
0.14.0-dev.31
to
0.14.0-dev.32
+139
src/ir/contract-view.ts
import { blindCast } from '@prisma-next/utils/casts';
import { UNBOUND_NAMESPACE_ID } from './namespace';
import type { Storage } from './storage';
/**
* Extracts the entries map of a contract's single default namespace
* (`UNBOUND_NAMESPACE_ID`). Both single-namespace families (Mongo, SQLite)
* store all entities under this one namespace.
*/
export type DefaultNamespaceEntries<TStorage extends { readonly namespaces: object }> =
TStorage['namespaces'] extends Record<typeof UNBOUND_NAMESPACE_ID, { readonly entries: infer E }>
? E
: never;
/**
* Generic single-namespace projection shape — one namespace's entity-kind slots.
* A family supplies:
* - `TEntries` — the family's `*NamespaceEntries` type for the namespace.
* - `TBuiltinKinds` — the union of the family's statically-named built-in kind
* keys (Mongo `'collection'`; SQL `'table' | 'valueSet'`).
*
* Each built-in kind becomes a top-level accessor; the remaining pack-contributed
* kinds stay under `.entries` (keyed by their registered singular kind string).
*
* A built-in kind that the emitted contract does not carry resolves to an empty
* map (`Record<string, never>`), matching the runtime which always materializes
* each built-in slot. The `& string` index-signature member of `TEntries` is
* excluded from `.entries` so only the literal pack-kind keys remain.
*/
export type SingleNamespaceView<TEntries, TBuiltinKinds extends string> = {
readonly [K in TBuiltinKinds]-?: K extends keyof TEntries
? NonNullable<TEntries[K]>
: Record<string, never>;
} & {
readonly entries: {
readonly [K in Exclude<keyof TEntries, TBuiltinKinds | number | symbol> as string extends K
? never
: K]: TEntries[K];
};
};
/** The `entries` shape of one namespace in a storage map. */
type EntriesOf<TNamespace> = TNamespace extends { readonly entries: infer E } ? E : never;
/**
* The namespace-keyed entity-view map — every storage namespace keyed by its raw
* id, each projected to its {@link SingleNamespaceView}. Mirrors
* `NamespacedEnums` from `@prisma-next/contract/enum-accessor`: the migration
* author's storage-side `view.namespace.<nsId>` is the twin of the runtime's
* `db.enums.<nsId>`. Nesting the schema map under one fixed `namespace` member
* makes it collision-proof — a schema named `storage` is `view.namespace.storage`,
* never a contract-root key.
*/
export type NamespacedEntities<
TStorage extends { readonly namespaces: object },
TBuiltinKinds extends string,
> = {
readonly [Ns in keyof TStorage['namespaces']]: SingleNamespaceView<
EntriesOf<TStorage['namespaces'][Ns]>,
TBuiltinKinds
>;
};
/**
* Projects one namespace's `entries` into the view shape: each built-in kind
* becomes a top-level slot (materialized empty if absent), and the remaining
* pack-contributed kinds sit under `.entries`. Shared by the single-namespace
* builder and the namespace-map builder.
*/
export function promoteBuiltinKinds<TView>(
entries: Readonly<Record<string, unknown>>,
builtinKinds: readonly string[],
): TView {
const view: Record<string, unknown> = {};
const rest: Record<string, unknown> = {};
for (const [kind, kindMap] of Object.entries(entries)) {
if (builtinKinds.includes(kind)) {
view[kind] = kindMap;
} else {
rest[kind] = kindMap;
}
}
for (const kind of builtinKinds) {
if (!(kind in view)) {
view[kind] = {};
}
}
view['entries'] = rest;
return blindCast<TView, 'view is built to the SingleNamespaceView shape the caller parametrizes'>(
view,
);
}
/**
* Builds one namespace's entity view: promotes the given built-in kind slots to
* top-level for the default (`UNBOUND_NAMESPACE_ID`) namespace. Single-namespace
* targets (Mongo, SQLite) use this to unwrap their sole namespace to the root.
*
* Throws if the contract has no default (`UNBOUND_NAMESPACE_ID`) namespace.
*/
export function buildSingleNamespaceView<TView>(
storage: Storage,
builtinKinds: readonly string[],
): TView {
const defaultNs = storage.namespaces[UNBOUND_NAMESPACE_ID];
if (defaultNs === undefined) {
throw new Error(`ContractView: contract has no default namespace (${UNBOUND_NAMESPACE_ID})`);
}
const entries = blindCast<
Record<string, unknown>,
'Namespace.entries is the open ADR 224 dictionary Record<string, Record<string, unknown>>'
>(defaultNs.entries);
return promoteBuiltinKinds<TView>(entries, builtinKinds);
}
/**
* Builds the namespace-keyed entity-view map (`{ <nsId>: SingleNamespaceView }`)
* for every namespace in the storage, keyed by raw namespace id. Mirrors
* `buildNamespacedEnums(domain)` — the storage-side twin.
*/
export function buildNamespacedEntities<TMap>(
storage: Storage,
builtinKinds: readonly string[],
): TMap {
const out: Record<string, unknown> = {};
for (const [nsId, ns] of Object.entries(storage.namespaces)) {
out[nsId] = promoteBuiltinKinds(
blindCast<
Readonly<Record<string, unknown>>,
'Namespace.entries is the open ADR 224 dictionary Record<string, Record<string, unknown>>'
>(ns.entries),
builtinKinds,
);
}
return blindCast<
TMap,
'each namespace projected to its SingleNamespaceView; keys mirror the storage namespace ids'
>(out);
}
+68
-1

@@ -211,2 +211,69 @@ import { ApplicationDomain, StorageBase, StorageNamespace } from "@prisma-next/contract/types";

//#endregion
//#region src/ir/contract-view.d.ts
/**
* Extracts the entries map of a contract's single default namespace
* (`UNBOUND_NAMESPACE_ID`). Both single-namespace families (Mongo, SQLite)
* store all entities under this one namespace.
*/
type DefaultNamespaceEntries<TStorage extends {
readonly namespaces: object;
}> = TStorage['namespaces'] extends Record<typeof UNBOUND_NAMESPACE_ID, {
readonly entries: infer E;
}> ? E : never;
/**
* Generic single-namespace projection shape — one namespace's entity-kind slots.
* A family supplies:
* - `TEntries` — the family's `*NamespaceEntries` type for the namespace.
* - `TBuiltinKinds` — the union of the family's statically-named built-in kind
* keys (Mongo `'collection'`; SQL `'table' | 'valueSet'`).
*
* Each built-in kind becomes a top-level accessor; the remaining pack-contributed
* kinds stay under `.entries` (keyed by their registered singular kind string).
*
* A built-in kind that the emitted contract does not carry resolves to an empty
* map (`Record<string, never>`), matching the runtime which always materializes
* each built-in slot. The `& string` index-signature member of `TEntries` is
* excluded from `.entries` so only the literal pack-kind keys remain.
*/
type SingleNamespaceView<TEntries, TBuiltinKinds extends string> = { readonly [K in TBuiltinKinds]-?: K extends keyof TEntries ? NonNullable<TEntries[K]> : Record<string, never> } & {
readonly entries: { readonly [K in Exclude<keyof TEntries, TBuiltinKinds | number | symbol> as string extends K ? never : K]: TEntries[K] };
};
/** The `entries` shape of one namespace in a storage map. */
type EntriesOf<TNamespace> = TNamespace extends {
readonly entries: infer E;
} ? E : never;
/**
* The namespace-keyed entity-view map — every storage namespace keyed by its raw
* id, each projected to its {@link SingleNamespaceView}. Mirrors
* `NamespacedEnums` from `@prisma-next/contract/enum-accessor`: the migration
* author's storage-side `view.namespace.<nsId>` is the twin of the runtime's
* `db.enums.<nsId>`. Nesting the schema map under one fixed `namespace` member
* makes it collision-proof — a schema named `storage` is `view.namespace.storage`,
* never a contract-root key.
*/
type NamespacedEntities<TStorage extends {
readonly namespaces: object;
}, TBuiltinKinds extends string> = { readonly [Ns in keyof TStorage['namespaces']]: SingleNamespaceView<EntriesOf<TStorage['namespaces'][Ns]>, TBuiltinKinds> };
/**
* Projects one namespace's `entries` into the view shape: each built-in kind
* becomes a top-level slot (materialized empty if absent), and the remaining
* pack-contributed kinds sit under `.entries`. Shared by the single-namespace
* builder and the namespace-map builder.
*/
declare function promoteBuiltinKinds<TView>(entries: Readonly<Record<string, unknown>>, builtinKinds: readonly string[]): TView;
/**
* Builds one namespace's entity view: promotes the given built-in kind slots to
* top-level for the default (`UNBOUND_NAMESPACE_ID`) namespace. Single-namespace
* targets (Mongo, SQLite) use this to unwrap their sole namespace to the root.
*
* Throws if the contract has no default (`UNBOUND_NAMESPACE_ID`) namespace.
*/
declare function buildSingleNamespaceView<TView>(storage: Storage, builtinKinds: readonly string[]): TView;
/**
* Builds the namespace-keyed entity-view map (`{ <nsId>: SingleNamespaceView }`)
* for every namespace in the storage, keyed by raw namespace id. Mirrors
* `buildNamespacedEnums(domain)` — the storage-side twin.
*/
declare function buildNamespacedEntities<TMap>(storage: Storage, builtinKinds: readonly string[]): TMap;
//#endregion
//#region src/ir/domain.d.ts

@@ -266,3 +333,3 @@ /**

//#endregion
export { type AnyEntityKindDescriptor, type EntityCoordinate, type EntityKindDescriptor, type IRNode, IRNodeBase, type Namespace, NamespaceBase, type Storage, type StorageType, UNBOUND_NAMESPACE_ID, domainElementCoordinates, elementCoordinates, entityAt, freezeNode, hydrateNamespaceEntities, isPlainRecord };
export { type AnyEntityKindDescriptor, type DefaultNamespaceEntries, type EntityCoordinate, type EntityKindDescriptor, type IRNode, IRNodeBase, type Namespace, NamespaceBase, type NamespacedEntities, type SingleNamespaceView, type Storage, type StorageType, UNBOUND_NAMESPACE_ID, buildNamespacedEntities, buildSingleNamespaceView, domainElementCoordinates, elementCoordinates, entityAt, freezeNode, hydrateNamespaceEntities, isPlainRecord, promoteBuiltinKinds };
//# sourceMappingURL=ir.d.mts.map
+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"ir.d.mts","names":[],"sources":["../src/ir/ir-node.ts","../src/ir/namespace.ts","../src/ir/storage.ts","../src/ir/domain.ts","../src/ir/entity-kind.ts","../src/ir/storage-type.ts"],"mappings":";;;;;;;;;;AAyCA;;;;AACe;AAGf;;;;AACwB;AAYxB;;;;;;;;;;;;;;AAAwD;;;;AChCxD;;;;AAA0D;AAkC1D;;UDnBiB,MAAA;EAAA,SACN,IAAI;AAAA;AAAA,uBAGO,UAAA,YAAsB,MAAM;EAAA,kBAC9B,IAAI;AAAA;;;;;;;;;;iBAYR,UAAA,WAAqB,MAAA,EAAQ,IAAA,EAAM,CAAA,GAAI,CAAA;;;;;;AAjBvD;;;;AACe;AAGf;;;;AACwB;AAYxB;;;;;;;;;;cChCa,oBAAA;;;;ADgC2C;;;;AChCxD;;;;AAA0D;AAkC1D;;;;;;;;;;;;;;;;;;;;UAAiB,SAAA,SAAkB,MAAA,EAAQ,gBAAA;EAAA,SAChC,IAAA;EAAA,SACA,OAAA,EAAS,QAAA,CAAS,MAAA,SAAe,QAAA,CAAS,MAAA;AAAA;AAAA,uBAG/B,aAAA,SAAsB,UAAA,YAAsB,SAAA;EAAA,kBAC9C,EAAA;EAAA,kBACA,OAAA,EAAS,QAAA,CAAS,MAAA,SAAe,QAAA,CAAS,MAAA;EAAA,kBACjC,IAAA;AAAA;;;AD3B7B;;;;AACe;AAGf;;;;AACwB;AAYxB;;;;;;AAjBA,UEjBiB,gBAAA;EAAA,SACN,KAAA;EAAA,SACA,WAAA;EAAA,SACA,UAAA;EAAA,SACA,UAAA;AAAA;;;AF8B6C;;;;AChCxD;;;;AAA0D;iBCgBzC,kBAAA,CACf,OAAA,EAAS,IAAA,CAAK,WAAA,kBACb,SAAA,CAAU,gBAAA;;;;;;;iBAmBG,QAAA,cACd,OAAA,EAAS,IAAA,CAAK,WAAA,iBACd,KAAA,EAAO,IAAA,CAAK,gBAAA,iDACX,CAAA;;;;;;;;;;;;;ADJwD;AAG3D;;;;;;;;;;;;;;;;;;;;;AAGiC;UC8ChB,OAAA,SAAgB,MAAA;EAAA,SACtB,UAAA,EAAY,QAAA,CAAS,MAAA,SAAe,SAAA;AAAA;;;;;;AF1E/C;;;;iBG/BiB,wBAAA,CACf,MAAA,EAAQ,IAAA,CAAK,iBAAA,kBACZ,SAAA,CAAU,gBAAA;;;UCTI,oBAAA;EAAA,SACN,IAAA;EAAA,SAEA,MAAA,EAAQ,IAAA;EAAA,SACR,SAAA,GAAY,KAAA,EAAO,KAAA,KAAU,IAAA;AAAA;AAAA,KAG5B,uBAAA,GAA0B,oBAAoB;;;AJgC3C;AAGf;;;;AACwB;AAYxB;;;;iBIlCgB,wBAAA,CACd,OAAA,EAAS,QAAA,CAAS,MAAA,SAAe,QAAA,CAAS,MAAA,sBAC1C,KAAA,EAAO,WAAA,SAAoB,uBAAA,GAC3B,SAAA,oBACA,IAAA,YACC,MAAA,SAAe,QAAA,CAAS,MAAA;;;;;;;AJY3B;;;;AACe;AAGf;;;;AACwB;AAYxB;;;;UKtCiB,WAAA,SAAoB,MAAM;EAAA,SAChC,IAAI;AAAA"}
{"version":3,"file":"ir.d.mts","names":[],"sources":["../src/ir/ir-node.ts","../src/ir/namespace.ts","../src/ir/storage.ts","../src/ir/contract-view.ts","../src/ir/domain.ts","../src/ir/entity-kind.ts","../src/ir/storage-type.ts"],"mappings":"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"}
import { blindCast } from "@prisma-next/utils/casts";
import { isPlainRecord } from "@prisma-next/contract/is-plain-record";
//#region src/ir/ir-node.ts
var IRNodeBase = class {};
/**
* Seal an IR class instance after its constructor has assigned all
* fields. The free-helper form (rather than a `protected freeze()`
* instance method) keeps the class type structurally narrow so emitted
* contract literal types remain assignable to their class types.
*
* The helper name stays `freezeNode` — it operates on IR nodes
* regardless of root naming.
*/
function freezeNode(node) {
Object.freeze(node);
return node;
}
//#endregion
//#region src/ir/namespace.ts
/**
* Reserved sentinel namespace id for the late-bound storage slot —
* the slot whose binding the target resolves at connection time
* rather than at authoring time. Postgres uses it for `search_path`
* late binding; SQLite uses it for the trivial singleton; Mongo uses
* it for the connection's `db` binding.
*
* Materialised target-side as a singleton subclass of the target's
* `NamespaceBase` concretion that overrides the namespace's
* qualifier-emission methods to elide the prefix entirely. Call sites
* stay polymorphic and never branch on `id === UNBOUND_NAMESPACE_ID`
* — the singleton's overrides drop the qualifier so emitted SQL / Mongo
* commands look unqualified.
*
* The double-underscore decoration marks the id as a framework-reserved
* coordinate when it appears in a JSON envelope (cold-read-as-reserved
* — no realistic collision with user-declared namespace names).
*
* Encoded as an exported const (rather than scattered string literals)
* so the sentinel-id invariant is single-sourced: any production-source
* site that constructs an unbound-namespace singleton imports this
* constant.
*/
const UNBOUND_NAMESPACE_ID = "__unbound__";
var NamespaceBase = class extends IRNodeBase {};
//#endregion
//#region src/ir/contract-view.ts
/**
* Projects one namespace's `entries` into the view shape: each built-in kind
* becomes a top-level slot (materialized empty if absent), and the remaining
* pack-contributed kinds sit under `.entries`. Shared by the single-namespace
* builder and the namespace-map builder.
*/
function promoteBuiltinKinds(entries, builtinKinds) {
const view = {};
const rest = {};
for (const [kind, kindMap] of Object.entries(entries)) if (builtinKinds.includes(kind)) view[kind] = kindMap;
else rest[kind] = kindMap;
for (const kind of builtinKinds) if (!(kind in view)) view[kind] = {};
view["entries"] = rest;
return blindCast(view);
}
/**
* Builds one namespace's entity view: promotes the given built-in kind slots to
* top-level for the default (`UNBOUND_NAMESPACE_ID`) namespace. Single-namespace
* targets (Mongo, SQLite) use this to unwrap their sole namespace to the root.
*
* Throws if the contract has no default (`UNBOUND_NAMESPACE_ID`) namespace.
*/
function buildSingleNamespaceView(storage, builtinKinds) {
const defaultNs = storage.namespaces[UNBOUND_NAMESPACE_ID];
if (defaultNs === void 0) throw new Error(`ContractView: contract has no default namespace (${UNBOUND_NAMESPACE_ID})`);
return promoteBuiltinKinds(blindCast(defaultNs.entries), builtinKinds);
}
/**
* Builds the namespace-keyed entity-view map (`{ <nsId>: SingleNamespaceView }`)
* for every namespace in the storage, keyed by raw namespace id. Mirrors
* `buildNamespacedEnums(domain)` — the storage-side twin.
*/
function buildNamespacedEntities(storage, builtinKinds) {
const out = {};
for (const [nsId, ns] of Object.entries(storage.namespaces)) out[nsId] = promoteBuiltinKinds(blindCast(ns.entries), builtinKinds);
return blindCast(out);
}
//#endregion
//#region src/ir/domain.ts

@@ -51,45 +133,2 @@ /**

//#endregion
//#region src/ir/ir-node.ts
var IRNodeBase = class {};
/**
* Seal an IR class instance after its constructor has assigned all
* fields. The free-helper form (rather than a `protected freeze()`
* instance method) keeps the class type structurally narrow so emitted
* contract literal types remain assignable to their class types.
*
* The helper name stays `freezeNode` — it operates on IR nodes
* regardless of root naming.
*/
function freezeNode(node) {
Object.freeze(node);
return node;
}
//#endregion
//#region src/ir/namespace.ts
/**
* Reserved sentinel namespace id for the late-bound storage slot —
* the slot whose binding the target resolves at connection time
* rather than at authoring time. Postgres uses it for `search_path`
* late binding; SQLite uses it for the trivial singleton; Mongo uses
* it for the connection's `db` binding.
*
* Materialised target-side as a singleton subclass of the target's
* `NamespaceBase` concretion that overrides the namespace's
* qualifier-emission methods to elide the prefix entirely. Call sites
* stay polymorphic and never branch on `id === UNBOUND_NAMESPACE_ID`
* — the singleton's overrides drop the qualifier so emitted SQL / Mongo
* commands look unqualified.
*
* The double-underscore decoration marks the id as a framework-reserved
* coordinate when it appears in a JSON envelope (cold-read-as-reserved
* — no realistic collision with user-declared namespace names).
*
* Encoded as an exported const (rather than scattered string literals)
* so the sentinel-id invariant is single-sourced: any production-source
* site that constructs an unbound-namespace singleton imports this
* constant.
*/
const UNBOUND_NAMESPACE_ID = "__unbound__";
var NamespaceBase = class extends IRNodeBase {};
//#endregion
//#region src/ir/storage.ts

@@ -139,4 +178,4 @@ /**

//#endregion
export { IRNodeBase, NamespaceBase, UNBOUND_NAMESPACE_ID, domainElementCoordinates, elementCoordinates, entityAt, freezeNode, hydrateNamespaceEntities, isPlainRecord };
export { IRNodeBase, NamespaceBase, UNBOUND_NAMESPACE_ID, buildNamespacedEntities, buildSingleNamespaceView, domainElementCoordinates, elementCoordinates, entityAt, freezeNode, hydrateNamespaceEntities, isPlainRecord, promoteBuiltinKinds };
//# sourceMappingURL=ir.mjs.map

@@ -1,1 +0,1 @@

{"version":3,"file":"ir.mjs","names":[],"sources":["../src/ir/domain.ts","../src/ir/entity-kind.ts","../src/ir/ir-node.ts","../src/ir/namespace.ts","../src/ir/storage.ts"],"sourcesContent":["import type { ApplicationDomain } from '@prisma-next/contract/types';\nimport type { EntityCoordinate } from './storage';\n\n/**\n * Lazy walk over every named domain entity in a {@link ApplicationDomain},\n * yielded as {@link EntityCoordinate} tuples with `plane: 'domain'`.\n *\n * Same structural rules as {@link elementCoordinates} over storage: skip\n * scalar `id`; each other object-valued property is an entity-kind slot.\n */\nexport function* domainElementCoordinates(\n domain: Pick<ApplicationDomain, 'namespaces'>,\n): Generator<EntityCoordinate> {\n for (const [namespaceId, ns] of Object.entries(domain.namespaces)) {\n for (const [entityKind, slot] of Object.entries(ns)) {\n if (entityKind === 'id') continue;\n if (slot === null || typeof slot !== 'object') continue;\n for (const entityName of Object.keys(slot)) {\n yield { plane: 'domain', namespaceId, entityKind, entityName };\n }\n }\n }\n}\n","import { blindCast } from '@prisma-next/utils/casts';\nimport type { Type } from 'arktype';\n\nexport interface EntityKindDescriptor<Input, Node> {\n readonly kind: string;\n // Type<unknown>, not Type<Input>: AnyEntityKindDescriptor widens Input to never, which would force an unusable Type<never>; concrete descriptors still carry their real schema.\n readonly schema: Type<unknown>;\n readonly construct: (input: Input) => Node;\n}\n\nexport type AnyEntityKindDescriptor = EntityKindDescriptor<never, unknown>;\n\n/**\n * Hydrates a namespace's entities from raw JSON maps into IR class instances.\n *\n * For each kind in `entries`: if the descriptor map has a descriptor,\n * construct each inner-map value; otherwise freeze-and-carry (`'carry'`)\n * or throw naming the kind and nsId (`'fail'`).\n *\n * The single boundary cast hands `value` to `descriptor.construct` as its\n * `Input`. The value satisfies the kind's `Input` either by the\n * entries-input contract at authoring time or by prior `validateStorage`\n * validation at hydration time.\n */\nexport function hydrateNamespaceEntities(\n entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>,\n kinds: ReadonlyMap<string, AnyEntityKindDescriptor>,\n onUnknown: 'carry' | 'fail',\n nsId?: string,\n): Record<string, Readonly<Record<string, unknown>>> {\n const result: Record<string, Readonly<Record<string, unknown>>> = {};\n for (const [kind, rawMap] of Object.entries(entries)) {\n const descriptor = kinds.get(kind);\n if (descriptor !== undefined) {\n const built: Record<string, unknown> = {};\n for (const [name, value] of Object.entries(rawMap)) {\n built[name] = descriptor.construct(\n blindCast<\n never,\n \"value is this kind's descriptor Input: when authoring, the typed entries-input contract produces it; when hydrating, it was validated against descriptor.schema before this loop. The never target is AnyEntityKindDescriptor's erased Input parameter.\"\n >(value),\n );\n }\n result[kind] = Object.freeze(built);\n } else if (onUnknown === 'carry') {\n result[kind] = Object.freeze(rawMap);\n } else {\n throw new Error(\n `Unknown entries key \"${kind}\" in namespace \"${nsId ?? '?'}\"; no hydration factory registered for this entity kind`,\n );\n }\n }\n return result;\n}\n","/**\n * Framework-level IR alphabet.\n *\n * The framework's contribution to Contract IR / Schema IR is a common\n * root for the IR class hierarchy and a freeze affordance. Family\n * abstract bases (e.g. `SqlNode`, `MongoSchemaIRNode`) refine the alphabet\n * for their family shape; targets ship the concrete classes.\n *\n * `kind` is an optional discriminator on the base. Families and leaves\n * that benefit from discriminated-union dispatch declare their own\n * literal `kind` at the level that earns it — Mongo leaves carry\n * per-class literals (`readonly kind = 'mongo-collection' as const`)\n * because Mongo IR has polymorphic walkers; SQL declares a single\n * family-level `kind = 'sql'` on `SqlNode` because SQL IR has no\n * polymorphic dispatch today. No framework consumer dispatches on\n * `IRNode.kind` at the BASE type — every dispatch site narrows\n * through a union of leaves where each leaf carries a literal kind, so\n * requiring `kind` at the base would be unearned. Future leaves that\n * earn polymorphic dispatch override with a required literal at that\n * leaf (e.g. `override readonly kind = 'pack-contributed-kind' as const`).\n *\n * `IRNodeBase` carries no methods: the freeze-and-assign affordance\n * lives in the free `freezeNode` helper below. Keeping `freezeNode` out\n * of the class type means an emitted contract literal type\n * (`{ readonly kind: 'mongo-collection', ... }` or an unkeyed literal\n * like `{ nativeType, codecId, nullable }`) is structurally assignable\n * to its class type — a `protected freeze()` instance method would\n * otherwise leak into the public type surface and require the literal\n * to carry it too.\n *\n * Subclasses construct fields then call `freezeNode(this)` to seal the\n * instance. Frozen instances + plain readonly fields keep IR nodes\n * JSON-clean by construction, so `JSON.stringify(node)` produces canonical\n * JSON without a `toJSON()` method. The `ContractSerializer` SPI handles\n * round-trip from canonical JSON back to typed class instances.\n *\n * The name (`IRNode` / `IRNodeBase`) reflects the dual-hierarchy reality:\n * this base is the common root for both Contract IR and Schema IR class\n * hierarchies, not a Schema-IR-specific alphabet.\n */\n\nexport interface IRNode {\n readonly kind?: string;\n}\n\nexport abstract class IRNodeBase implements IRNode {\n abstract readonly kind?: string;\n}\n\n/**\n * Seal an IR class instance after its constructor has assigned all\n * fields. The free-helper form (rather than a `protected freeze()`\n * instance method) keeps the class type structurally narrow so emitted\n * contract literal types remain assignable to their class types.\n *\n * The helper name stays `freezeNode` — it operates on IR nodes\n * regardless of root naming.\n */\nexport function freezeNode<T extends IRNode>(node: T): T {\n Object.freeze(node);\n return node;\n}\n","import type { StorageNamespace } from '@prisma-next/contract/types';\nimport { type IRNode, IRNodeBase } from './ir-node';\n\n/**\n * Reserved sentinel namespace id for the late-bound storage slot —\n * the slot whose binding the target resolves at connection time\n * rather than at authoring time. Postgres uses it for `search_path`\n * late binding; SQLite uses it for the trivial singleton; Mongo uses\n * it for the connection's `db` binding.\n *\n * Materialised target-side as a singleton subclass of the target's\n * `NamespaceBase` concretion that overrides the namespace's\n * qualifier-emission methods to elide the prefix entirely. Call sites\n * stay polymorphic and never branch on `id === UNBOUND_NAMESPACE_ID`\n * — the singleton's overrides drop the qualifier so emitted SQL / Mongo\n * commands look unqualified.\n *\n * The double-underscore decoration marks the id as a framework-reserved\n * coordinate when it appears in a JSON envelope (cold-read-as-reserved\n * — no realistic collision with user-declared namespace names).\n *\n * Encoded as an exported const (rather than scattered string literals)\n * so the sentinel-id invariant is single-sourced: any production-source\n * site that constructs an unbound-namespace singleton imports this\n * constant.\n */\nexport const UNBOUND_NAMESPACE_ID = '__unbound__' as const;\n\n/**\n * Framework-level building block for a \"namespace\" — the database-level\n * grouping under which storage objects (tables, collections, enums, …)\n * reside. Each target's namespace concretion maps the framework concept to\n * a target-native binding:\n *\n * - Postgres: a schema (`CREATE SCHEMA …`); rendered as `\"<schema>\"`.\n * - SQLite: the singleton `UNBOUND_NAMESPACE_ID`; emitted SQL has no qualifier.\n * - Mongo: the connection's `db` field; addressed as a database name.\n *\n * See `UNBOUND_NAMESPACE_ID` above for the sentinel id and the\n * singleton-subclass pattern that materialises it.\n *\n * The framework promises only the coordinate (`id`) — the named storage\n * entities a namespace contains are family-typed (SQL contributes\n * `table` / `type`, Mongo contributes `collection`, future families pick\n * their own native idiom under `entries`). Generic consumers walking \"all\n * named entries\" go through a family-typed namespace, not the framework\n * `Namespace`.\n *\n * Every namespace concretion (e.g. family-built SQL namespaces,\n * `MongoUnboundNamespace`, target-promoted namespaces like\n * `PostgresSchema`) carries exactly: `id` (enumerable string),\n * `entries` (frozen object holding entity-kind slot maps), and `kind`\n * (non-enumerable string discriminator set via `Object.defineProperty`).\n * Each slot map under `entries` uses a singular essence key (`table`,\n * `type`, `collection`, …) mapping entity names to IR classes. No other\n * own-enumerable data lives on a namespace; non-entity computed data lives\n * on the surrounding storage or contract IR. The framework's\n * `elementCoordinates(storage)` walk relies on this invariant to enumerate\n * entities structurally without family-specific knowledge.\n */\nexport interface Namespace extends IRNode, StorageNamespace {\n readonly kind: string;\n readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>;\n}\n\nexport abstract class NamespaceBase extends IRNodeBase implements Namespace {\n abstract readonly id: string;\n abstract readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>;\n abstract override readonly kind: string;\n}\n","import { isPlainRecord } from '@prisma-next/contract/is-plain-record';\nimport type { StorageBase } from '@prisma-next/contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { IRNode } from './ir-node';\nimport type { Namespace } from './namespace';\n\nexport { isPlainRecord };\n\n/**\n * Canonical address for a named entity in Contract IR / Schema IR.\n *\n * `plane` is `'domain' | 'storage'`: which top-level contract plane the\n * entity lives on. Domain-side walks yield `plane: 'domain'` via\n * {@link domainElementCoordinates}; {@link elementCoordinates} over storage\n * yields `plane: 'storage'`.\n *\n * Cross-plane references obey a directional invariant: domain → storage is\n * allowed; storage → domain is forbidden. That rule is enforced by a\n * separate validator, not by constraining this coordinate shape — the\n * coordinate carries the axis the validator checks.\n *\n * Iteration order over namespace properties follows `Object.entries` order;\n * consumers that depend on ordering must sort.\n */\nexport interface EntityCoordinate {\n readonly plane: 'domain' | 'storage';\n readonly namespaceId: string;\n readonly entityKind: string;\n readonly entityName: string;\n}\n\n/**\n * Lazy walk over every named storage entity in a `Storage`-shaped\n * value, yielded as {@link EntityCoordinate} tuples with\n * `plane: 'storage'` (the parameter type binds the plane).\n *\n * Iterates each namespace's `entries` kind maps structurally. Skips\n * non-object `entries`; `id` and `kind` are not walked (`kind` is\n * non-enumerable on concretions). For every entity-kind key under\n * `entries` whose value is a non-null object, yields one coordinate per\n * entity name in that map. No family-specific kind vocabulary is required.\n */\nexport function* elementCoordinates(\n storage: Pick<StorageBase, 'namespaces'>,\n): Generator<EntityCoordinate> {\n for (const [namespaceId, ns] of Object.entries(storage.namespaces)) {\n const entries = ns.entries;\n if (entries === null || typeof entries !== 'object') continue;\n for (const [entityKind, kindMap] of Object.entries(entries)) {\n if (kindMap === null || typeof kindMap !== 'object') continue;\n for (const entityName of Object.keys(kindMap)) {\n yield { plane: 'storage', namespaceId, entityKind, entityName };\n }\n }\n }\n}\n\n/**\n * Looks up a single entity in a `Storage`-shaped value by its full coordinate.\n * Returns `undefined` if the namespace, entity kind, or entity name is absent.\n * The type parameter is a caller assertion — the walk itself is structural\n * and cannot verify the entity's shape.\n */\nexport function entityAt<T = unknown>(\n storage: Pick<StorageBase, 'namespaces'>,\n coord: Pick<EntityCoordinate, 'namespaceId' | 'entityKind' | 'entityName'>,\n): T | undefined {\n const ns = storage.namespaces[coord.namespaceId];\n if (ns === undefined) return undefined;\n const entries = ns.entries;\n if (!isPlainRecord(entries)) return undefined;\n const kindMap = entries[coord.entityKind];\n if (!isPlainRecord(kindMap)) return undefined;\n if (!Object.hasOwn(kindMap, coord.entityName)) return undefined;\n return blindCast<T | undefined, 'caller asserts the entity type at this coordinate'>(\n kindMap[coord.entityName],\n );\n}\n\n/**\n * Framework-level promise that every Contract IR / Schema IR carries a\n * collection of namespaces keyed by namespace id. Family storage\n * concretions (`SqlStorage`, `MongoStorage`) refine the shape with\n * family-specific fields (tables, collections, enums, …); target\n * concretions add target fields where the family vocabulary doesn't\n * reach.\n *\n * Keeping `namespaces` at the framework layer enforces that every storage\n * object — across any target — is namespace-scoped. The framework can\n * therefore walk the namespace map without knowing the family alphabet, and\n * the `(namespace.id, name)` keying that the verifier and planner depend on\n * is honest at every layer.\n *\n * Extends `IRNode` so the framework's IR-walking surfaces (verifiers,\n * serializers) can dispatch on `Storage`-typed fields through the same\n * IR-node alphabet as every other node — the structural dual already\n * holds in code (every concrete storage class extends an IR-node base);\n * the interface promotion makes the typing honest.\n *\n * **Persisted envelope shape is target-owned, not framework-promised.**\n * Whether the `namespaces` map appears in the on-disk JSON envelope is\n * a per-target decision made by `ContractSerializer.serializeContract`.\n * Some targets emit a JSON-clean namespace shape that round-trips\n * through `JSON.stringify` cleanly (SQL today via the family-layer\n * identity serializer); others ship runtime-only fields on their\n * namespace concretions and override `serializeContract` to strip\n * them (Mongo). Future open (F16): extend the per-target\n * `ContractSerializer` integration-test surface with an explicit\n * envelope-shape assertion for each target, so the strip-vs-pass-through\n * choice is locked at test time rather than implied by the override\n * presence/absence. Earned by PR2's per-target namespace lift, when\n * `PostgresSchema` / `SqliteUnboundDatabase` start carrying\n * target-specific fields.\n */\nexport interface Storage extends IRNode {\n readonly namespaces: Readonly<Record<string, Namespace>>;\n}\n"],"mappings":";;;;;;;;;;AAUA,UAAiB,yBACf,QAC6B;CAC7B,KAAK,MAAM,CAAC,aAAa,OAAO,OAAO,QAAQ,OAAO,UAAU,GAC9D,KAAK,MAAM,CAAC,YAAY,SAAS,OAAO,QAAQ,EAAE,GAAG;EACnD,IAAI,eAAe,MAAM;EACzB,IAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;EAC/C,KAAK,MAAM,cAAc,OAAO,KAAK,IAAI,GACvC,MAAM;GAAE,OAAO;GAAU;GAAa;GAAY;EAAW;CAEjE;AAEJ;;;;;;;;;;;;;;;ACEA,SAAgB,yBACd,SACA,OACA,WACA,MACmD;CACnD,MAAM,SAA4D,CAAC;CACnE,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,OAAO,GAAG;EACpD,MAAM,aAAa,MAAM,IAAI,IAAI;EACjC,IAAI,eAAe,KAAA,GAAW;GAC5B,MAAM,QAAiC,CAAC;GACxC,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,GAC/C,MAAM,QAAQ,WAAW,UACvB,UAGE,KAAK,CACT;GAEF,OAAO,QAAQ,OAAO,OAAO,KAAK;EACpC,OAAO,IAAI,cAAc,SACvB,OAAO,QAAQ,OAAO,OAAO,MAAM;OAEnC,MAAM,IAAI,MACR,wBAAwB,KAAK,kBAAkB,QAAQ,IAAI,wDAC7D;CAEJ;CACA,OAAO;AACT;;;ACRA,IAAsB,aAAtB,MAAmD,CAEnD;;;;;;;;;;AAWA,SAAgB,WAA6B,MAAY;CACvD,OAAO,OAAO,IAAI;CAClB,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA,MAAa,uBAAuB;AAuCpC,IAAsB,gBAAtB,cAA4C,WAAgC,CAI5E;;;;;;;;;;;;;;AC3BA,UAAiB,mBACf,SAC6B;CAC7B,KAAK,MAAM,CAAC,aAAa,OAAO,OAAO,QAAQ,QAAQ,UAAU,GAAG;EAClE,MAAM,UAAU,GAAG;EACnB,IAAI,YAAY,QAAQ,OAAO,YAAY,UAAU;EACrD,KAAK,MAAM,CAAC,YAAY,YAAY,OAAO,QAAQ,OAAO,GAAG;GAC3D,IAAI,YAAY,QAAQ,OAAO,YAAY,UAAU;GACrD,KAAK,MAAM,cAAc,OAAO,KAAK,OAAO,GAC1C,MAAM;IAAE,OAAO;IAAW;IAAa;IAAY;GAAW;EAElE;CACF;AACF;;;;;;;AAQA,SAAgB,SACd,SACA,OACe;CACf,MAAM,KAAK,QAAQ,WAAW,MAAM;CACpC,IAAI,OAAO,KAAA,GAAW,OAAO,KAAA;CAC7B,MAAM,UAAU,GAAG;CACnB,IAAI,CAAC,cAAc,OAAO,GAAG,OAAO,KAAA;CACpC,MAAM,UAAU,QAAQ,MAAM;CAC9B,IAAI,CAAC,cAAc,OAAO,GAAG,OAAO,KAAA;CACpC,IAAI,CAAC,OAAO,OAAO,SAAS,MAAM,UAAU,GAAG,OAAO,KAAA;CACtD,OAAO,UACL,QAAQ,MAAM,WAChB;AACF"}
{"version":3,"file":"ir.mjs","names":[],"sources":["../src/ir/ir-node.ts","../src/ir/namespace.ts","../src/ir/contract-view.ts","../src/ir/domain.ts","../src/ir/entity-kind.ts","../src/ir/storage.ts"],"sourcesContent":["/**\n * Framework-level IR alphabet.\n *\n * The framework's contribution to Contract IR / Schema IR is a common\n * root for the IR class hierarchy and a freeze affordance. Family\n * abstract bases (e.g. `SqlNode`, `MongoSchemaIRNode`) refine the alphabet\n * for their family shape; targets ship the concrete classes.\n *\n * `kind` is an optional discriminator on the base. Families and leaves\n * that benefit from discriminated-union dispatch declare their own\n * literal `kind` at the level that earns it — Mongo leaves carry\n * per-class literals (`readonly kind = 'mongo-collection' as const`)\n * because Mongo IR has polymorphic walkers; SQL declares a single\n * family-level `kind = 'sql'` on `SqlNode` because SQL IR has no\n * polymorphic dispatch today. No framework consumer dispatches on\n * `IRNode.kind` at the BASE type — every dispatch site narrows\n * through a union of leaves where each leaf carries a literal kind, so\n * requiring `kind` at the base would be unearned. Future leaves that\n * earn polymorphic dispatch override with a required literal at that\n * leaf (e.g. `override readonly kind = 'pack-contributed-kind' as const`).\n *\n * `IRNodeBase` carries no methods: the freeze-and-assign affordance\n * lives in the free `freezeNode` helper below. Keeping `freezeNode` out\n * of the class type means an emitted contract literal type\n * (`{ readonly kind: 'mongo-collection', ... }` or an unkeyed literal\n * like `{ nativeType, codecId, nullable }`) is structurally assignable\n * to its class type — a `protected freeze()` instance method would\n * otherwise leak into the public type surface and require the literal\n * to carry it too.\n *\n * Subclasses construct fields then call `freezeNode(this)` to seal the\n * instance. Frozen instances + plain readonly fields keep IR nodes\n * JSON-clean by construction, so `JSON.stringify(node)` produces canonical\n * JSON without a `toJSON()` method. The `ContractSerializer` SPI handles\n * round-trip from canonical JSON back to typed class instances.\n *\n * The name (`IRNode` / `IRNodeBase`) reflects the dual-hierarchy reality:\n * this base is the common root for both Contract IR and Schema IR class\n * hierarchies, not a Schema-IR-specific alphabet.\n */\n\nexport interface IRNode {\n readonly kind?: string;\n}\n\nexport abstract class IRNodeBase implements IRNode {\n abstract readonly kind?: string;\n}\n\n/**\n * Seal an IR class instance after its constructor has assigned all\n * fields. The free-helper form (rather than a `protected freeze()`\n * instance method) keeps the class type structurally narrow so emitted\n * contract literal types remain assignable to their class types.\n *\n * The helper name stays `freezeNode` — it operates on IR nodes\n * regardless of root naming.\n */\nexport function freezeNode<T extends IRNode>(node: T): T {\n Object.freeze(node);\n return node;\n}\n","import type { StorageNamespace } from '@prisma-next/contract/types';\nimport { type IRNode, IRNodeBase } from './ir-node';\n\n/**\n * Reserved sentinel namespace id for the late-bound storage slot —\n * the slot whose binding the target resolves at connection time\n * rather than at authoring time. Postgres uses it for `search_path`\n * late binding; SQLite uses it for the trivial singleton; Mongo uses\n * it for the connection's `db` binding.\n *\n * Materialised target-side as a singleton subclass of the target's\n * `NamespaceBase` concretion that overrides the namespace's\n * qualifier-emission methods to elide the prefix entirely. Call sites\n * stay polymorphic and never branch on `id === UNBOUND_NAMESPACE_ID`\n * — the singleton's overrides drop the qualifier so emitted SQL / Mongo\n * commands look unqualified.\n *\n * The double-underscore decoration marks the id as a framework-reserved\n * coordinate when it appears in a JSON envelope (cold-read-as-reserved\n * — no realistic collision with user-declared namespace names).\n *\n * Encoded as an exported const (rather than scattered string literals)\n * so the sentinel-id invariant is single-sourced: any production-source\n * site that constructs an unbound-namespace singleton imports this\n * constant.\n */\nexport const UNBOUND_NAMESPACE_ID = '__unbound__' as const;\n\n/**\n * Framework-level building block for a \"namespace\" — the database-level\n * grouping under which storage objects (tables, collections, enums, …)\n * reside. Each target's namespace concretion maps the framework concept to\n * a target-native binding:\n *\n * - Postgres: a schema (`CREATE SCHEMA …`); rendered as `\"<schema>\"`.\n * - SQLite: the singleton `UNBOUND_NAMESPACE_ID`; emitted SQL has no qualifier.\n * - Mongo: the connection's `db` field; addressed as a database name.\n *\n * See `UNBOUND_NAMESPACE_ID` above for the sentinel id and the\n * singleton-subclass pattern that materialises it.\n *\n * The framework promises only the coordinate (`id`) — the named storage\n * entities a namespace contains are family-typed (SQL contributes\n * `table` / `type`, Mongo contributes `collection`, future families pick\n * their own native idiom under `entries`). Generic consumers walking \"all\n * named entries\" go through a family-typed namespace, not the framework\n * `Namespace`.\n *\n * Every namespace concretion (e.g. family-built SQL namespaces,\n * `MongoUnboundNamespace`, target-promoted namespaces like\n * `PostgresSchema`) carries exactly: `id` (enumerable string),\n * `entries` (frozen object holding entity-kind slot maps), and `kind`\n * (non-enumerable string discriminator set via `Object.defineProperty`).\n * Each slot map under `entries` uses a singular essence key (`table`,\n * `type`, `collection`, …) mapping entity names to IR classes. No other\n * own-enumerable data lives on a namespace; non-entity computed data lives\n * on the surrounding storage or contract IR. The framework's\n * `elementCoordinates(storage)` walk relies on this invariant to enumerate\n * entities structurally without family-specific knowledge.\n */\nexport interface Namespace extends IRNode, StorageNamespace {\n readonly kind: string;\n readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>;\n}\n\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 { blindCast } from '@prisma-next/utils/casts';\nimport { UNBOUND_NAMESPACE_ID } from './namespace';\nimport type { Storage } from './storage';\n\n/**\n * Extracts the entries map of a contract's single default namespace\n * (`UNBOUND_NAMESPACE_ID`). Both single-namespace families (Mongo, SQLite)\n * store all entities under this one namespace.\n */\nexport type DefaultNamespaceEntries<TStorage extends { readonly namespaces: object }> =\n TStorage['namespaces'] extends Record<typeof UNBOUND_NAMESPACE_ID, { readonly entries: infer E }>\n ? E\n : never;\n\n/**\n * Generic single-namespace projection shape — one namespace's entity-kind slots.\n * A family supplies:\n * - `TEntries` — the family's `*NamespaceEntries` type for the namespace.\n * - `TBuiltinKinds` — the union of the family's statically-named built-in kind\n * keys (Mongo `'collection'`; SQL `'table' | 'valueSet'`).\n *\n * Each built-in kind becomes a top-level accessor; the remaining pack-contributed\n * kinds stay under `.entries` (keyed by their registered singular kind string).\n *\n * A built-in kind that the emitted contract does not carry resolves to an empty\n * map (`Record<string, never>`), matching the runtime which always materializes\n * each built-in slot. The `& string` index-signature member of `TEntries` is\n * excluded from `.entries` so only the literal pack-kind keys remain.\n */\nexport type SingleNamespaceView<TEntries, TBuiltinKinds extends string> = {\n readonly [K in TBuiltinKinds]-?: K extends keyof TEntries\n ? NonNullable<TEntries[K]>\n : Record<string, never>;\n} & {\n readonly entries: {\n readonly [K in Exclude<keyof TEntries, TBuiltinKinds | number | symbol> as string extends K\n ? never\n : K]: TEntries[K];\n };\n};\n\n/** The `entries` shape of one namespace in a storage map. */\ntype EntriesOf<TNamespace> = TNamespace extends { readonly entries: infer E } ? E : never;\n\n/**\n * The namespace-keyed entity-view map — every storage namespace keyed by its raw\n * id, each projected to its {@link SingleNamespaceView}. Mirrors\n * `NamespacedEnums` from `@prisma-next/contract/enum-accessor`: the migration\n * author's storage-side `view.namespace.<nsId>` is the twin of the runtime's\n * `db.enums.<nsId>`. Nesting the schema map under one fixed `namespace` member\n * makes it collision-proof — a schema named `storage` is `view.namespace.storage`,\n * never a contract-root key.\n */\nexport type NamespacedEntities<\n TStorage extends { readonly namespaces: object },\n TBuiltinKinds extends string,\n> = {\n readonly [Ns in keyof TStorage['namespaces']]: SingleNamespaceView<\n EntriesOf<TStorage['namespaces'][Ns]>,\n TBuiltinKinds\n >;\n};\n\n/**\n * Projects one namespace's `entries` into the view shape: each built-in kind\n * becomes a top-level slot (materialized empty if absent), and the remaining\n * pack-contributed kinds sit under `.entries`. Shared by the single-namespace\n * builder and the namespace-map builder.\n */\nexport function promoteBuiltinKinds<TView>(\n entries: Readonly<Record<string, unknown>>,\n builtinKinds: readonly string[],\n): TView {\n const view: Record<string, unknown> = {};\n const rest: Record<string, unknown> = {};\n for (const [kind, kindMap] of Object.entries(entries)) {\n if (builtinKinds.includes(kind)) {\n view[kind] = kindMap;\n } else {\n rest[kind] = kindMap;\n }\n }\n for (const kind of builtinKinds) {\n if (!(kind in view)) {\n view[kind] = {};\n }\n }\n view['entries'] = rest;\n return blindCast<TView, 'view is built to the SingleNamespaceView shape the caller parametrizes'>(\n view,\n );\n}\n\n/**\n * Builds one namespace's entity view: promotes the given built-in kind slots to\n * top-level for the default (`UNBOUND_NAMESPACE_ID`) namespace. Single-namespace\n * targets (Mongo, SQLite) use this to unwrap their sole namespace to the root.\n *\n * Throws if the contract has no default (`UNBOUND_NAMESPACE_ID`) namespace.\n */\nexport function buildSingleNamespaceView<TView>(\n storage: Storage,\n builtinKinds: readonly string[],\n): TView {\n const defaultNs = storage.namespaces[UNBOUND_NAMESPACE_ID];\n if (defaultNs === undefined) {\n throw new Error(`ContractView: contract has no default namespace (${UNBOUND_NAMESPACE_ID})`);\n }\n const entries = blindCast<\n Record<string, unknown>,\n 'Namespace.entries is the open ADR 224 dictionary Record<string, Record<string, unknown>>'\n >(defaultNs.entries);\n return promoteBuiltinKinds<TView>(entries, builtinKinds);\n}\n\n/**\n * Builds the namespace-keyed entity-view map (`{ <nsId>: SingleNamespaceView }`)\n * for every namespace in the storage, keyed by raw namespace id. Mirrors\n * `buildNamespacedEnums(domain)` — the storage-side twin.\n */\nexport function buildNamespacedEntities<TMap>(\n storage: Storage,\n builtinKinds: readonly string[],\n): TMap {\n const out: Record<string, unknown> = {};\n for (const [nsId, ns] of Object.entries(storage.namespaces)) {\n out[nsId] = promoteBuiltinKinds(\n blindCast<\n Readonly<Record<string, unknown>>,\n 'Namespace.entries is the open ADR 224 dictionary Record<string, Record<string, unknown>>'\n >(ns.entries),\n builtinKinds,\n );\n }\n return blindCast<\n TMap,\n 'each namespace projected to its SingleNamespaceView; keys mirror the storage namespace ids'\n >(out);\n}\n","import type { ApplicationDomain } from '@prisma-next/contract/types';\nimport type { EntityCoordinate } from './storage';\n\n/**\n * Lazy walk over every named domain entity in a {@link ApplicationDomain},\n * yielded as {@link EntityCoordinate} tuples with `plane: 'domain'`.\n *\n * Same structural rules as {@link elementCoordinates} over storage: skip\n * scalar `id`; each other object-valued property is an entity-kind slot.\n */\nexport function* domainElementCoordinates(\n domain: Pick<ApplicationDomain, 'namespaces'>,\n): Generator<EntityCoordinate> {\n for (const [namespaceId, ns] of Object.entries(domain.namespaces)) {\n for (const [entityKind, slot] of Object.entries(ns)) {\n if (entityKind === 'id') continue;\n if (slot === null || typeof slot !== 'object') continue;\n for (const entityName of Object.keys(slot)) {\n yield { plane: 'domain', namespaceId, entityKind, entityName };\n }\n }\n }\n}\n","import { blindCast } from '@prisma-next/utils/casts';\nimport type { Type } from 'arktype';\n\nexport interface EntityKindDescriptor<Input, Node> {\n readonly kind: string;\n // Type<unknown>, not Type<Input>: AnyEntityKindDescriptor widens Input to never, which would force an unusable Type<never>; concrete descriptors still carry their real schema.\n readonly schema: Type<unknown>;\n readonly construct: (input: Input) => Node;\n}\n\nexport type AnyEntityKindDescriptor = EntityKindDescriptor<never, unknown>;\n\n/**\n * Hydrates a namespace's entities from raw JSON maps into IR class instances.\n *\n * For each kind in `entries`: if the descriptor map has a descriptor,\n * construct each inner-map value; otherwise freeze-and-carry (`'carry'`)\n * or throw naming the kind and nsId (`'fail'`).\n *\n * The single boundary cast hands `value` to `descriptor.construct` as its\n * `Input`. The value satisfies the kind's `Input` either by the\n * entries-input contract at authoring time or by prior `validateStorage`\n * validation at hydration time.\n */\nexport function hydrateNamespaceEntities(\n entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>,\n kinds: ReadonlyMap<string, AnyEntityKindDescriptor>,\n onUnknown: 'carry' | 'fail',\n nsId?: string,\n): Record<string, Readonly<Record<string, unknown>>> {\n const result: Record<string, Readonly<Record<string, unknown>>> = {};\n for (const [kind, rawMap] of Object.entries(entries)) {\n const descriptor = kinds.get(kind);\n if (descriptor !== undefined) {\n const built: Record<string, unknown> = {};\n for (const [name, value] of Object.entries(rawMap)) {\n built[name] = descriptor.construct(\n blindCast<\n never,\n \"value is this kind's descriptor Input: when authoring, the typed entries-input contract produces it; when hydrating, it was validated against descriptor.schema before this loop. The never target is AnyEntityKindDescriptor's erased Input parameter.\"\n >(value),\n );\n }\n result[kind] = Object.freeze(built);\n } else if (onUnknown === 'carry') {\n result[kind] = Object.freeze(rawMap);\n } else {\n throw new Error(\n `Unknown entries key \"${kind}\" in namespace \"${nsId ?? '?'}\"; no hydration factory registered for this entity kind`,\n );\n }\n }\n return result;\n}\n","import { isPlainRecord } from '@prisma-next/contract/is-plain-record';\nimport type { StorageBase } from '@prisma-next/contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { IRNode } from './ir-node';\nimport type { Namespace } from './namespace';\n\nexport { isPlainRecord };\n\n/**\n * Canonical address for a named entity in Contract IR / Schema IR.\n *\n * `plane` is `'domain' | 'storage'`: which top-level contract plane the\n * entity lives on. Domain-side walks yield `plane: 'domain'` via\n * {@link domainElementCoordinates}; {@link elementCoordinates} over storage\n * yields `plane: 'storage'`.\n *\n * Cross-plane references obey a directional invariant: domain → storage is\n * allowed; storage → domain is forbidden. That rule is enforced by a\n * separate validator, not by constraining this coordinate shape — the\n * coordinate carries the axis the validator checks.\n *\n * Iteration order over namespace properties follows `Object.entries` order;\n * consumers that depend on ordering must sort.\n */\nexport interface EntityCoordinate {\n readonly plane: 'domain' | 'storage';\n readonly namespaceId: string;\n readonly entityKind: string;\n readonly entityName: string;\n}\n\n/**\n * Lazy walk over every named storage entity in a `Storage`-shaped\n * value, yielded as {@link EntityCoordinate} tuples with\n * `plane: 'storage'` (the parameter type binds the plane).\n *\n * Iterates each namespace's `entries` kind maps structurally. Skips\n * non-object `entries`; `id` and `kind` are not walked (`kind` is\n * non-enumerable on concretions). For every entity-kind key under\n * `entries` whose value is a non-null object, yields one coordinate per\n * entity name in that map. No family-specific kind vocabulary is required.\n */\nexport function* elementCoordinates(\n storage: Pick<StorageBase, 'namespaces'>,\n): Generator<EntityCoordinate> {\n for (const [namespaceId, ns] of Object.entries(storage.namespaces)) {\n const entries = ns.entries;\n if (entries === null || typeof entries !== 'object') continue;\n for (const [entityKind, kindMap] of Object.entries(entries)) {\n if (kindMap === null || typeof kindMap !== 'object') continue;\n for (const entityName of Object.keys(kindMap)) {\n yield { plane: 'storage', namespaceId, entityKind, entityName };\n }\n }\n }\n}\n\n/**\n * 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":"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"}
{
"name": "@prisma-next/framework-components",
"version": "0.14.0-dev.31",
"version": "0.14.0-dev.32",
"license": "Apache-2.0",

@@ -9,6 +9,6 @@ "type": "module",

"dependencies": {
"@prisma-next/contract": "0.14.0-dev.31",
"@prisma-next/operations": "0.14.0-dev.31",
"@prisma-next/ts-render": "0.14.0-dev.31",
"@prisma-next/utils": "0.14.0-dev.31",
"@prisma-next/contract": "0.14.0-dev.32",
"@prisma-next/operations": "0.14.0-dev.32",
"@prisma-next/ts-render": "0.14.0-dev.32",
"@prisma-next/utils": "0.14.0-dev.32",
"@standard-schema/spec": "^1.1.0",

@@ -18,4 +18,4 @@ "arktype": "^2.2.0"

"devDependencies": {
"@prisma-next/tsconfig": "0.14.0-dev.31",
"@prisma-next/tsdown": "0.14.0-dev.31",
"@prisma-next/tsconfig": "0.14.0-dev.32",
"@prisma-next/tsdown": "0.14.0-dev.32",
"tsdown": "0.22.1",

@@ -22,0 +22,0 @@ "typescript": "5.9.3",

@@ -0,1 +1,11 @@

export type {
DefaultNamespaceEntries,
NamespacedEntities,
SingleNamespaceView,
} from '../ir/contract-view';
export {
buildNamespacedEntities,
buildSingleNamespaceView,
promoteBuiltinKinds,
} from '../ir/contract-view';
export { domainElementCoordinates } from '../ir/domain';

@@ -2,0 +12,0 @@ export type { AnyEntityKindDescriptor, EntityKindDescriptor } from '../ir/entity-kind';