@prisma-next/contract-authoring 0.11.0 → 0.12.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.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,21 @@
1
1
  import { AuthoringEntityContext, AuthoringEntityTypeDescriptor, AuthoringEntityTypeNamespace } from "@prisma-next/framework-components/authoring";
2
2
 
3
+ //#region src/capability-registry.d.ts
4
+ type CapabilityMatrix = Readonly<Record<string, Readonly<Record<string, boolean>>>>;
5
+ /**
6
+ * Deep-merges any number of capability matrices into a single matrix.
7
+ *
8
+ * Merge is purely structural — namespaces and capability flags from later
9
+ * sources overlay earlier ones. Undefined entries are skipped so callers
10
+ * can pass optional sources without pre-filtering.
11
+ *
12
+ * The helper is target-agnostic: it contains no SQL or family-specific
13
+ * knowledge. Higher layers contribute their own capability matrices (for
14
+ * example, a target pack, an extension pack, or the contract author's
15
+ * own `capabilities` block) and call this helper to fold them together.
16
+ */
17
+ declare function mergeCapabilityMatrices(...sources: ReadonlyArray<CapabilityMatrix | undefined>): Record<string, Record<string, boolean>>;
18
+ //#endregion
3
19
  //#region src/composed-helpers-scaffolding.d.ts
4
20
  /**
5
21
  * Family-agnostic merge / instantiation scaffolding for pack-bag-driven
@@ -66,5 +82,5 @@ interface ForeignKeyDefaultsState {
66
82
  readonly index: boolean;
67
83
  }
68
84
  //#endregion
69
- export { type AuthoringNamespaceKey, type EntityHelperFactoryOptions, type EntityHelperFunction, type EntityHelpersFromNamespace, type ExtractAuthoringNamespaceFromPack, type ForeignKeyDefaultsState, type IndexDef, type MergeExtensionAuthoringNamespaces, type UnionToIntersection, createEntityHelpersFromNamespace };
85
+ export { type AuthoringNamespaceKey, type CapabilityMatrix, type EntityHelperFactoryOptions, type EntityHelperFunction, type EntityHelpersFromNamespace, type ExtractAuthoringNamespaceFromPack, type ForeignKeyDefaultsState, type IndexDef, type MergeExtensionAuthoringNamespaces, type UnionToIntersection, createEntityHelpersFromNamespace, mergeCapabilityMatrices };
70
86
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/composed-helpers-scaffolding.ts","../src/descriptors.ts"],"mappings":";;;;;AAyBA;;;;;;;;;;;;;AAMA;;KANY,mBAAA,OAA0B,CAAA,oBAAqB,KAAA,EAAO,CAAA,6BAChE,KAAA,sBAEE,CAAA;AAAA,KAGQ,qBAAA;AAAA,KAEA,iCAAA,mBAEE,qBAAA,oBAEV,IAAA;EAAA,SACO,SAAA,oBAA6B,GAAA;AAAA,IAEpC,SAAA,SAAkB,MAAA,oBAChB,SAAA,GACA,cAAA,GACF,cAAA;AAAA,KAEQ,iCAAA,6BAEE,qBAAA,mBACK,MAAA,kBAEjB,cAAA,SAAuB,MAAA,0BACb,cAAA,iBACJ,cAAA,GACA,mBAAA,eAEgB,cAAA,GAAiB,iCAAA,CAC3B,cAAA,CAAe,CAAA,GACf,GAAA,EACA,cAAA,UAEI,cAAA,KAEZ,cAAA;;;;;;KAOD,4BAAA,oBAAgD,6BAAA,IACnD,UAAA;EAAA,SACW,OAAA,GAAU,KAAA,eAAoB,GAAA,EAAK,sBAAA;AAAA;EAExC,KAAA,EAAO,KAAA;EAAO,MAAA,EAAQ,MAAA;AAAA;EACtB,KAAA;EAAgB,MAAA;AAAA;AAAA,KAEZ,oBAAA,oBAAwC,6BAAA,IAClD,4BAAA,CAA6B,UAAA;EAAsB,KAAA;EAAoB,MAAA;AAAA,KAClE,KAAA,EAAO,KAAA,KAAU,MAAA;AAAA,KAGZ,0BAAA,qCACW,SAAA,GAAY,SAAA,CAAU,CAAA,UAAW,6BAAA,GAClD,oBAAA,CAAqB,SAAA,CAAU,CAAA,KAC/B,SAAA,CAAU,CAAA,UAAW,MAAA,oBACnB,0BAAA,CAA2B,SAAA,CAAU,CAAA;AAAA,UAI5B,0BAAA;EAAA,SACN,GAAA,EAAK,sBAAA;AAAA;;;;;;;iBASA,gCAAA,CACd,SAAA,EAAW,4BAAA,EACX,OAAA,EAAS,0BAAA,EACT,IAAA,uBACC,MAAA;;;UCvGc,QAAA;EAAA,SACN,OAAA;EAAA,SACA,IAAA;EAAA,SACA,IAAA;EAAA,SACA,OAAA,GAAU,MAAA;AAAA;AAAA,UAGJ,uBAAA;EAAA,SACN,UAAA;EAAA,SACA,KAAA;AAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/capability-registry.ts","../src/composed-helpers-scaffolding.ts","../src/descriptors.ts"],"mappings":";;;KAAY,gBAAA,GAAmB,QAAA,CAAS,MAAA,SAAe,QAAA,CAAS,MAAA;;;AAAhE;;;;;;;;;;iBAcgB,uBAAA,CAAA,GACX,OAAA,EAAS,aAAA,CAAc,gBAAA,gBACzB,MAAA,SAAe,MAAA;;;;;AAhBlB;;;;;;;;;;;;;;AAAsE;KCyB1D,mBAAA,OAA0B,CAAA,oBAAqB,KAAA,EAAO,CAAC,6BACjE,KAAA,sBAEE,CAAA;AAAA,KAGQ,qBAAA;AAAA,KAEA,iCAAA,mBAEE,qBAAA,oBAEV,IAAA;EAAA,SACO,SAAA,oBAA6B,GAAA;AAAA,IAEpC,SAAA,SAAkB,MAAA,oBAChB,SAAA,GACA,cAAA,GACF,cAAA;AAAA,KAEQ,iCAAA,6BAEE,qBAAA,mBACK,MAAA,kBAEjB,cAAA,SAAuB,MAAA,0BACb,cAAA,iBACJ,cAAA,GACA,mBAAA,eAEgB,cAAA,GAAiB,iCAAA,CAC3B,cAAA,CAAe,CAAA,GACf,GAAA,EACA,cAAA,UAEI,cAAA,KAEZ,cAAA;;;;;;KAOD,4BAAA,oBAAgD,6BAAA,IACnD,UAAA;EAAA,SACW,OAAA,GAAU,KAAA,eAAoB,GAAA,EAAK,sBAAA;AAAA;EAExC,KAAA,EAAO,KAAA;EAAO,MAAA,EAAQ,MAAA;AAAA;EACtB,KAAA;EAAgB,MAAA;AAAA;AAAA,KAEZ,oBAAA,oBAAwC,6BAAA,IAClD,4BAAA,CAA6B,UAAA;EAAsB,KAAA;EAAoB,MAAA;AAAA,KAClE,KAAA,EAAO,KAAA,KAAU,MAAA;AAAA,KAGZ,0BAAA,qCACW,SAAA,GAAY,SAAA,CAAU,CAAA,UAAW,6BAAA,GAClD,oBAAA,CAAqB,SAAA,CAAU,CAAA,KAC/B,SAAA,CAAU,CAAA,UAAW,MAAA,oBACnB,0BAAA,CAA2B,SAAA,CAAU,CAAA;AAAA,UAI5B,0BAAA;EAAA,SACN,GAAA,EAAK,sBAAsB;AAAA;;;AA3DL;AAEjC;;;iBAkEgB,gCAAA,CACd,SAAA,EAAW,4BAAA,EACX,OAAA,EAAS,0BAAA,EACT,IAAA,uBACC,MAAA;;;UCvGc,QAAA;EAAA,SACN,OAAA;EAAA,SACA,IAAA;EAAA,SACA,IAAA;EAAA,SACA,OAAA,GAAU,MAAM;AAAA;AAAA,UAGV,uBAAA;EAAA,SACN,UAAA;EAAA,SACA,KAAK;AAAA"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,32 @@
1
1
  import { instantiateAuthoringEntityType } from "@prisma-next/framework-components/authoring";
2
+ //#region src/capability-registry.ts
3
+ /**
4
+ * Deep-merges any number of capability matrices into a single matrix.
5
+ *
6
+ * Merge is purely structural — namespaces and capability flags from later
7
+ * sources overlay earlier ones. Undefined entries are skipped so callers
8
+ * can pass optional sources without pre-filtering.
9
+ *
10
+ * The helper is target-agnostic: it contains no SQL or family-specific
11
+ * knowledge. Higher layers contribute their own capability matrices (for
12
+ * example, a target pack, an extension pack, or the contract author's
13
+ * own `capabilities` block) and call this helper to fold them together.
14
+ */
15
+ function mergeCapabilityMatrices(...sources) {
16
+ const result = {};
17
+ for (const source of sources) {
18
+ if (source === void 0) continue;
19
+ for (const [namespace, capabilities] of Object.entries(source)) {
20
+ const existing = result[namespace];
21
+ result[namespace] = existing ? {
22
+ ...existing,
23
+ ...capabilities
24
+ } : { ...capabilities };
25
+ }
26
+ }
27
+ return result;
28
+ }
29
+ //#endregion
2
30
  //#region src/composed-helpers-scaffolding.ts
3
31
  /**
4
32
  * Walks an entity-type namespace (after cross-pack merge) and produces the
@@ -27,6 +55,6 @@ function createEntityHelper(helperPath, descriptor, options) {
27
55
  return (...args) => instantiateAuthoringEntityType(helperPath, descriptor, args, options.ctx);
28
56
  }
29
57
  //#endregion
30
- export { createEntityHelpersFromNamespace };
58
+ export { createEntityHelpersFromNamespace, mergeCapabilityMatrices };
31
59
 
32
60
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/composed-helpers-scaffolding.ts"],"sourcesContent":["import type {\n AuthoringEntityContext,\n AuthoringEntityTypeDescriptor,\n AuthoringEntityTypeNamespace,\n} from '@prisma-next/framework-components/authoring';\nimport { instantiateAuthoringEntityType } from '@prisma-next/framework-components/authoring';\n\n/**\n * Family-agnostic merge / instantiation scaffolding for pack-bag-driven\n * authoring contributions. The per-namespace shape (`field`, `type`,\n * `entityTypes`) is parameterized by the discriminator key so each\n * namespace can reuse the same extractor + cross-pack merger without\n * re-deriving the template per family. Call sites flatten merged\n * `entityTypes` onto the user-facing top-level helpers surface\n * alongside the built-in `model` / `rel` (e.g. `helpers.enum(...)`).\n * The contribution data structure stays as\n * `authoring.entityTypes.<name>` — pack authors keep contributing\n * through the namespace; the composed-helpers template performs the\n * rename in the type system.\n *\n * SQL-specific composition (the `field` / `model` / `rel` / `type` core\n * helpers, the SQL index-types merge) lives in the SQL contract-ts\n * package and imports from here.\n */\n\nexport type UnionToIntersection<U> = (U extends unknown ? (value: U) => void : never) extends (\n value: infer I,\n) => void\n ? I\n : never;\n\nexport type AuthoringNamespaceKey = 'field' | 'type' | 'entityTypes';\n\nexport type ExtractAuthoringNamespaceFromPack<\n Pack,\n Key extends AuthoringNamespaceKey,\n EmptyNamespace,\n> = Pack extends {\n readonly authoring?: { readonly [P in Key]?: infer Namespace };\n}\n ? Namespace extends Record<string, unknown>\n ? Namespace\n : EmptyNamespace\n : EmptyNamespace;\n\nexport type MergeExtensionAuthoringNamespaces<\n ExtensionPacks,\n Key extends AuthoringNamespaceKey,\n EmptyNamespace = Record<never, never>,\n> =\n ExtensionPacks extends Record<string, unknown>\n ? keyof ExtensionPacks extends never\n ? EmptyNamespace\n : UnionToIntersection<\n {\n [K in keyof ExtensionPacks]: ExtractAuthoringNamespaceFromPack<\n ExtensionPacks[K],\n Key,\n EmptyNamespace\n >;\n }[keyof ExtensionPacks]\n >\n : EmptyNamespace;\n\n/**\n * Entity-helper shape derivation. Mirrors `FieldHelpersFromNamespace` /\n * `TypeHelpersFromNamespace` in the SQL package: leaf descriptors become\n * callable helpers; nested namespaces recurse.\n */\ntype ExtractFactoryInputAndOutput<Descriptor extends AuthoringEntityTypeDescriptor> =\n Descriptor['output'] extends {\n readonly factory: (input: infer Input, ctx: AuthoringEntityContext) => infer Output;\n }\n ? { input: Input; output: Output }\n : { input: unknown; output: unknown };\n\nexport type EntityHelperFunction<Descriptor extends AuthoringEntityTypeDescriptor> =\n ExtractFactoryInputAndOutput<Descriptor> extends { input: infer Input; output: infer Output }\n ? (input: Input) => Output\n : never;\n\nexport type EntityHelpersFromNamespace<Namespace> = {\n readonly [K in keyof Namespace]: Namespace[K] extends AuthoringEntityTypeDescriptor\n ? EntityHelperFunction<Namespace[K]>\n : Namespace[K] extends Record<string, unknown>\n ? EntityHelpersFromNamespace<Namespace[K]>\n : never;\n};\n\nexport interface EntityHelperFactoryOptions {\n readonly ctx: AuthoringEntityContext;\n}\n\n/**\n * Walks an entity-type namespace (after cross-pack merge) and produces the\n * runtime callable surface mirroring its tree shape. Each leaf\n * descriptor becomes a function `(input) => factory(input, ctx)`;\n * nested namespace objects recurse.\n */\nexport function createEntityHelpersFromNamespace(\n namespace: AuthoringEntityTypeNamespace,\n options: EntityHelperFactoryOptions,\n path: readonly string[] = [],\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(namespace)) {\n const currentPath = [...path, key];\n if (isLeafEntityDescriptor(value)) {\n result[key] = createEntityHelper(currentPath.join('.'), value, options);\n continue;\n }\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n result[key] = createEntityHelpersFromNamespace(\n value as AuthoringEntityTypeNamespace,\n options,\n currentPath,\n );\n }\n }\n return result;\n}\n\nfunction isLeafEntityDescriptor(value: unknown): 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 return typeof discriminator === 'string' && discriminator.length > 0;\n}\n\nfunction createEntityHelper(\n helperPath: string,\n descriptor: AuthoringEntityTypeDescriptor,\n options: EntityHelperFactoryOptions,\n): (...args: readonly unknown[]) => unknown {\n return (...args: readonly unknown[]) =>\n instantiateAuthoringEntityType(helperPath, descriptor, args, options.ctx);\n}\n"],"mappings":";;;;;;;;AAmGA,SAAgB,iCACd,WACA,SACA,OAA0B,EAAE,EACH;CACzB,MAAM,SAAkC,EAAE;CAC1C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,UAAU,EAAE;EACpD,MAAM,cAAc,CAAC,GAAG,MAAM,IAAI;EAClC,IAAI,uBAAuB,MAAM,EAAE;GACjC,OAAO,OAAO,mBAAmB,YAAY,KAAK,IAAI,EAAE,OAAO,QAAQ;GACvE;;EAEF,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM,EACtE,OAAO,OAAO,iCACZ,OACA,SACA,YACD;;CAGL,OAAO;;AAGT,SAAS,uBAAuB,OAAwD;CACtF,IACE,OAAO,UAAU,YACjB,UAAU,QACT,MAA6B,SAAS,UAEvC,OAAO;CAET,MAAM,gBAAiB,MAAsC;CAC7D,OAAO,OAAO,kBAAkB,YAAY,cAAc,SAAS;;AAGrE,SAAS,mBACP,YACA,YACA,SAC0C;CAC1C,QAAQ,GAAG,SACT,+BAA+B,YAAY,YAAY,MAAM,QAAQ,IAAI"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/capability-registry.ts","../src/composed-helpers-scaffolding.ts"],"sourcesContent":["export type CapabilityMatrix = Readonly<Record<string, Readonly<Record<string, boolean>>>>;\n\n/**\n * Deep-merges any number of capability matrices into a single matrix.\n *\n * Merge is purely structural — namespaces and capability flags from later\n * sources overlay earlier ones. Undefined entries are skipped so callers\n * can pass optional sources without pre-filtering.\n *\n * The helper is target-agnostic: it contains no SQL or family-specific\n * knowledge. Higher layers contribute their own capability matrices (for\n * example, a target pack, an extension pack, or the contract author's\n * own `capabilities` block) and call this helper to fold them together.\n */\nexport function mergeCapabilityMatrices(\n ...sources: ReadonlyArray<CapabilityMatrix | undefined>\n): Record<string, Record<string, boolean>> {\n const result: Record<string, Record<string, boolean>> = {};\n for (const source of sources) {\n if (source === undefined) continue;\n for (const [namespace, capabilities] of Object.entries(source)) {\n const existing = result[namespace];\n result[namespace] = existing ? { ...existing, ...capabilities } : { ...capabilities };\n }\n }\n return result;\n}\n","import type {\n AuthoringEntityContext,\n AuthoringEntityTypeDescriptor,\n AuthoringEntityTypeNamespace,\n} from '@prisma-next/framework-components/authoring';\nimport { instantiateAuthoringEntityType } from '@prisma-next/framework-components/authoring';\n\n/**\n * Family-agnostic merge / instantiation scaffolding for pack-bag-driven\n * authoring contributions. The per-namespace shape (`field`, `type`,\n * `entityTypes`) is parameterized by the discriminator key so each\n * namespace can reuse the same extractor + cross-pack merger without\n * re-deriving the template per family. Call sites flatten merged\n * `entityTypes` onto the user-facing top-level helpers surface\n * alongside the built-in `model` / `rel` (e.g. `helpers.enum(...)`).\n * The contribution data structure stays as\n * `authoring.entityTypes.<name>` — pack authors keep contributing\n * through the namespace; the composed-helpers template performs the\n * rename in the type system.\n *\n * SQL-specific composition (the `field` / `model` / `rel` / `type` core\n * helpers, the SQL index-types merge) lives in the SQL contract-ts\n * package and imports from here.\n */\n\nexport type UnionToIntersection<U> = (U extends unknown ? (value: U) => void : never) extends (\n value: infer I,\n) => void\n ? I\n : never;\n\nexport type AuthoringNamespaceKey = 'field' | 'type' | 'entityTypes';\n\nexport type ExtractAuthoringNamespaceFromPack<\n Pack,\n Key extends AuthoringNamespaceKey,\n EmptyNamespace,\n> = Pack extends {\n readonly authoring?: { readonly [P in Key]?: infer Namespace };\n}\n ? Namespace extends Record<string, unknown>\n ? Namespace\n : EmptyNamespace\n : EmptyNamespace;\n\nexport type MergeExtensionAuthoringNamespaces<\n ExtensionPacks,\n Key extends AuthoringNamespaceKey,\n EmptyNamespace = Record<never, never>,\n> =\n ExtensionPacks extends Record<string, unknown>\n ? keyof ExtensionPacks extends never\n ? EmptyNamespace\n : UnionToIntersection<\n {\n [K in keyof ExtensionPacks]: ExtractAuthoringNamespaceFromPack<\n ExtensionPacks[K],\n Key,\n EmptyNamespace\n >;\n }[keyof ExtensionPacks]\n >\n : EmptyNamespace;\n\n/**\n * Entity-helper shape derivation. Mirrors `FieldHelpersFromNamespace` /\n * `TypeHelpersFromNamespace` in the SQL package: leaf descriptors become\n * callable helpers; nested namespaces recurse.\n */\ntype ExtractFactoryInputAndOutput<Descriptor extends AuthoringEntityTypeDescriptor> =\n Descriptor['output'] extends {\n readonly factory: (input: infer Input, ctx: AuthoringEntityContext) => infer Output;\n }\n ? { input: Input; output: Output }\n : { input: unknown; output: unknown };\n\nexport type EntityHelperFunction<Descriptor extends AuthoringEntityTypeDescriptor> =\n ExtractFactoryInputAndOutput<Descriptor> extends { input: infer Input; output: infer Output }\n ? (input: Input) => Output\n : never;\n\nexport type EntityHelpersFromNamespace<Namespace> = {\n readonly [K in keyof Namespace]: Namespace[K] extends AuthoringEntityTypeDescriptor\n ? EntityHelperFunction<Namespace[K]>\n : Namespace[K] extends Record<string, unknown>\n ? EntityHelpersFromNamespace<Namespace[K]>\n : never;\n};\n\nexport interface EntityHelperFactoryOptions {\n readonly ctx: AuthoringEntityContext;\n}\n\n/**\n * Walks an entity-type namespace (after cross-pack merge) and produces the\n * runtime callable surface mirroring its tree shape. Each leaf\n * descriptor becomes a function `(input) => factory(input, ctx)`;\n * nested namespace objects recurse.\n */\nexport function createEntityHelpersFromNamespace(\n namespace: AuthoringEntityTypeNamespace,\n options: EntityHelperFactoryOptions,\n path: readonly string[] = [],\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(namespace)) {\n const currentPath = [...path, key];\n if (isLeafEntityDescriptor(value)) {\n result[key] = createEntityHelper(currentPath.join('.'), value, options);\n continue;\n }\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n result[key] = createEntityHelpersFromNamespace(\n value as AuthoringEntityTypeNamespace,\n options,\n currentPath,\n );\n }\n }\n return result;\n}\n\nfunction isLeafEntityDescriptor(value: unknown): 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 return typeof discriminator === 'string' && discriminator.length > 0;\n}\n\nfunction createEntityHelper(\n helperPath: string,\n descriptor: AuthoringEntityTypeDescriptor,\n options: EntityHelperFactoryOptions,\n): (...args: readonly unknown[]) => unknown {\n return (...args: readonly unknown[]) =>\n instantiateAuthoringEntityType(helperPath, descriptor, args, options.ctx);\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,SAAgB,wBACd,GAAG,SACsC;CACzC,MAAM,SAAkD,CAAC;CACzD,KAAK,MAAM,UAAU,SAAS;EAC5B,IAAI,WAAW,KAAA,GAAW;EAC1B,KAAK,MAAM,CAAC,WAAW,iBAAiB,OAAO,QAAQ,MAAM,GAAG;GAC9D,MAAM,WAAW,OAAO;GACxB,OAAO,aAAa,WAAW;IAAE,GAAG;IAAU,GAAG;GAAa,IAAI,EAAE,GAAG,aAAa;EACtF;CACF;CACA,OAAO;AACT;;;;;;;;;ACyEA,SAAgB,iCACd,WACA,SACA,OAA0B,CAAC,GACF;CACzB,MAAM,SAAkC,CAAC;CACzC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,GAAG;EACpD,MAAM,cAAc,CAAC,GAAG,MAAM,GAAG;EACjC,IAAI,uBAAuB,KAAK,GAAG;GACjC,OAAO,OAAO,mBAAmB,YAAY,KAAK,GAAG,GAAG,OAAO,OAAO;GACtE;EACF;EACA,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,GACrE,OAAO,OAAO,iCACZ,OACA,SACA,WACF;CAEJ;CACA,OAAO;AACT;AAEA,SAAS,uBAAuB,OAAwD;CACtF,IACE,OAAO,UAAU,YACjB,UAAU,QACT,MAA6B,SAAS,UAEvC,OAAO;CAET,MAAM,gBAAiB,MAAsC;CAC7D,OAAO,OAAO,kBAAkB,YAAY,cAAc,SAAS;AACrE;AAEA,SAAS,mBACP,YACA,YACA,SAC0C;CAC1C,QAAQ,GAAG,SACT,+BAA+B,YAAY,YAAY,MAAM,QAAQ,GAAG;AAC5E"}
package/package.json CHANGED
@@ -1,29 +1,40 @@
1
1
  {
2
2
  "name": "@prisma-next/contract-authoring",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "Target-agnostic authored storage descriptor types for Prisma Next",
8
8
  "dependencies": {
9
- "@prisma-next/framework-components": "0.11.0"
9
+ "@prisma-next/framework-components": "0.12.0"
10
10
  },
11
11
  "devDependencies": {
12
- "@prisma-next/tsconfig": "0.11.0",
13
- "@prisma-next/tsdown": "0.11.0",
12
+ "@prisma-next/tsconfig": "0.12.0",
13
+ "@prisma-next/tsdown": "0.12.0",
14
14
  "tsdown": "0.22.0",
15
15
  "typescript": "5.9.3",
16
16
  "vitest": "4.1.6"
17
17
  },
18
+ "peerDependencies": {
19
+ "typescript": ">=5.9"
20
+ },
21
+ "peerDependenciesMeta": {
22
+ "typescript": {
23
+ "optional": true
24
+ }
25
+ },
18
26
  "files": [
19
27
  "dist",
20
28
  "src"
21
29
  ],
30
+ "types": "./dist/index.d.mts",
22
31
  "exports": {
23
32
  ".": "./dist/index.mjs",
24
33
  "./package.json": "./package.json"
25
34
  },
26
- "types": "./dist/index.d.mts",
35
+ "engines": {
36
+ "node": ">=24"
37
+ },
27
38
  "repository": {
28
39
  "type": "git",
29
40
  "url": "https://github.com/prisma/prisma-next.git",
@@ -0,0 +1,27 @@
1
+ export type CapabilityMatrix = Readonly<Record<string, Readonly<Record<string, boolean>>>>;
2
+
3
+ /**
4
+ * Deep-merges any number of capability matrices into a single matrix.
5
+ *
6
+ * Merge is purely structural — namespaces and capability flags from later
7
+ * sources overlay earlier ones. Undefined entries are skipped so callers
8
+ * can pass optional sources without pre-filtering.
9
+ *
10
+ * The helper is target-agnostic: it contains no SQL or family-specific
11
+ * knowledge. Higher layers contribute their own capability matrices (for
12
+ * example, a target pack, an extension pack, or the contract author's
13
+ * own `capabilities` block) and call this helper to fold them together.
14
+ */
15
+ export function mergeCapabilityMatrices(
16
+ ...sources: ReadonlyArray<CapabilityMatrix | undefined>
17
+ ): Record<string, Record<string, boolean>> {
18
+ const result: Record<string, Record<string, boolean>> = {};
19
+ for (const source of sources) {
20
+ if (source === undefined) continue;
21
+ for (const [namespace, capabilities] of Object.entries(source)) {
22
+ const existing = result[namespace];
23
+ result[namespace] = existing ? { ...existing, ...capabilities } : { ...capabilities };
24
+ }
25
+ }
26
+ return result;
27
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export type { CapabilityMatrix } from './capability-registry';
2
+ export { mergeCapabilityMatrices } from './capability-registry';
1
3
  export type {
2
4
  AuthoringNamespaceKey,
3
5
  EntityHelperFactoryOptions,