@prisma-next/core-control-plane 0.3.0-dev.123 → 0.3.0-dev.125

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.
@@ -7,8 +7,9 @@ type CanonicalContractInput = {
7
7
  schemaVersion: string;
8
8
  targetFamily: string;
9
9
  target: string;
10
+ roots?: Record<string, string>;
10
11
  models: Record<string, unknown>;
11
- relations: Record<string, unknown>;
12
+ relations?: Record<string, unknown>;
12
13
  storage: Record<string, unknown>;
13
14
  execution?: Record<string, unknown>;
14
15
  extensionPacks: Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"emission.d.mts","names":[],"sources":["../src/emission/canonicalization.ts","../src/emission/types.ts","../src/emission/emit.ts","../src/emission/hashing.ts"],"sourcesContent":[],"mappings":";;;;;KAoBY,sBAAA;;;;UAIF;EAJE,SAAA,EAKC,MALD,CAAA,MAAA,EAAsB,OAAA,CAAA;EAIxB,OAAA,EAEC,MAFD,CAAA,MAAA,EAAA,OAAA,CAAA;EACG,SAAA,CAAA,EAEC,MAFD,CAAA,MAAA,EAAA,OAAA,CAAA;EACF,cAAA,EAEO,MAFP,CAAA,MAAA,EAAA,OAAA,CAAA;EACG,YAAA,EAEE,MAFF,CAAA,MAAA,EAEiB,MAFjB,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;EACI,IAAA,EAEV,MAFU,CAAA,MAAA,EAAA,OAAA,CAAA;EACa,WAAA,CAAA,EAAA,MAAA;EAAf,aAAA,CAAA,EAAA,MAAA;EACR,WAAA,CAAA,EAAA,MAAA;CAAM;AAkPE,iBAAA,oBAAA,CAAyB,EAAA,EAAA,sBAAsB,CAAA,EAAA,MAAA;;;UC7Q9C,WAAA;;+BAEc;EDenB,SAAA,gBAAsB,CAAA,ECdJ,aDcI,CCdU,eDcV,CAAA;EAIxB,SAAA,oBAAA,CAAA,ECjBwB,aDiBxB,CCjBsC,eDiBtC,CAAA;EACG,SAAA,YAAA,CAAA,ECjBa,aDiBb,CAAA,MAAA,CAAA;EACF;;;;EAGK,SAAA,sBAAA,CAAA,EChBoB,GDgBpB,CAAA,MAAA,EChBgC,eDgBhC,CAAA;EACR;;AAkPR;;sCC9PsC,cAAc;;AAfpD;;;EAG8B,SAAA,yBAAA,CAAA,EAiBS,aAjBT,CAiBuB,eAjBvB,CAAA;;AACI,UAmBjB,UAAA,CAnBiB;EACR,SAAA,YAAA,EAAA,MAAA;EAKsB,SAAA,WAAA,EAAA,MAAA;EAAZ,SAAA,WAAA,EAAA,MAAA;EAKgB,SAAA,aAAA,CAAA,EAAA,MAAA;EAAd,SAAA,WAAA,EAAA,MAAA;;;;iBCwDhB,IAAA,KAChB,qBACK,2BACK,mBACb,QAAQ;;;iBCnEK,kBAAA,WAA6B;iBAgB7B,kBAAA,WAA6B;iBAgB7B,oBAAA,WAA+B"}
1
+ {"version":3,"file":"emission.d.mts","names":[],"sources":["../src/emission/canonicalization.ts","../src/emission/types.ts","../src/emission/emit.ts","../src/emission/hashing.ts"],"sourcesContent":[],"mappings":";;;;;KAqBY,sBAAA;;;;UAIF;EAJE,MAAA,EAKF,MALE,CAAA,MAAA,EAAA,OAAsB,CAAA;EAIxB,SAAA,CAAA,EAEI,MAFJ,CAAA,MAAA,EAAA,OAAA,CAAA;EACA,OAAA,EAEC,MAFD,CAAA,MAAA,EAAA,OAAA,CAAA;EACI,SAAA,CAAA,EAEA,MAFA,CAAA,MAAA,EAAA,OAAA,CAAA;EACH,cAAA,EAEO,MAFP,CAAA,MAAA,EAAA,OAAA,CAAA;EACG,YAAA,EAEE,MAFF,CAAA,MAAA,EAEiB,MAFjB,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;EACI,IAAA,EAEV,MAFU,CAAA,MAAA,EAAA,OAAA,CAAA;EACa,WAAA,CAAA,EAAA,MAAA;EAAf,aAAA,CAAA,EAAA,MAAA;EACR,WAAA,CAAA,EAAA,MAAA;CAAM;AAqPE,iBAAA,oBAAA,CAAyB,EAAA,EAAA,sBAAsB,CAAA,EAAA,MAAA;;;UClR9C,WAAA;;+BAEc;EDgBnB,SAAA,gBAAsB,CAAA,ECfJ,aDeI,CCfU,eDeV,CAAA;EAIxB,SAAA,oBAAA,CAAA,EClBwB,aDkBxB,CClBsC,eDkBtC,CAAA;EACA,SAAA,YAAA,CAAA,EClBgB,aDkBhB,CAAA,MAAA,CAAA;EACI;;;;EAIiB,SAAA,sBAAA,CAAA,EClBK,GDkBL,CAAA,MAAA,EClBiB,eDkBjB,CAAA;EAAf;;;AAsPhB;sCCnQsC,cAAc;;;AAfpD;;EAG4C,SAAA,yBAAA,CAAA,EAiBL,aAjBK,CAiBS,eAjBT,CAAA;;AACI,UAmB/B,UAAA,CAnB+B;EAAd,SAAA,YAAA,EAAA,MAAA;EACR,SAAA,WAAA,EAAA,MAAA;EAKsB,SAAA,WAAA,EAAA,MAAA;EAAZ,SAAA,aAAA,CAAA,EAAA,MAAA;EAKgB,SAAA,WAAA,EAAA,MAAA;;;;iBC8H9B,IAAA,KAChB,qBACK,2BACK,mBACb,QAAQ;;;iBCzIK,kBAAA,WAA6B;iBAgB7B,kBAAA,WAA6B;iBAgB7B,oBAAA,WAA+B"}
package/dist/emission.mjs CHANGED
@@ -14,6 +14,7 @@ const TOP_LEVEL_ORDER = [
14
14
  "storageHash",
15
15
  "executionHash",
16
16
  "profileHash",
17
+ "roots",
17
18
  "models",
18
19
  "relations",
19
20
  "storage",
@@ -45,6 +46,7 @@ function omitDefaults(obj, path) {
45
46
  const isRequiredModels = isArrayEqual(currentPath, ["models"]);
46
47
  const isRequiredTables = isArrayEqual(currentPath, ["storage", "tables"]);
47
48
  const isRequiredRelations = isArrayEqual(currentPath, ["relations"]);
49
+ const isRequiredRoots = isArrayEqual(currentPath, ["roots"]);
48
50
  const isRequiredExtensionPacks = isArrayEqual(currentPath, ["extensionPacks"]);
49
51
  const isRequiredCapabilities = isArrayEqual(currentPath, ["capabilities"]);
50
52
  const isRequiredMeta = isArrayEqual(currentPath, ["meta"]);
@@ -83,7 +85,7 @@ function omitDefaults(obj, path) {
83
85
  "foreignKeys"
84
86
  ]);
85
87
  const isFkBooleanField = currentPath.length === 5 && currentPath[0] === "storage" && currentPath[1] === "tables" && currentPath[3] === "foreignKeys" && (key === "constraint" || key === "index");
86
- if (!isRequiredModels && !isRequiredTables && !isRequiredRelations && !isRequiredExtensionPacks && !isRequiredCapabilities && !isRequiredMeta && !isRequiredExecutionDefaults && !isExtensionNamespace && !isModelRelations && !isTableUniques && !isTableIndexes && !isTableForeignKeys && !isFkBooleanField) continue;
88
+ if (!isRequiredModels && !isRequiredTables && !isRequiredRelations && !isRequiredRoots && !isRequiredExtensionPacks && !isRequiredCapabilities && !isRequiredMeta && !isRequiredExecutionDefaults && !isExtensionNamespace && !isModelRelations && !isTableUniques && !isTableIndexes && !isTableForeignKeys && !isFkBooleanField) continue;
87
89
  }
88
90
  result[key] = omitDefaults(value, currentPath);
89
91
  }
@@ -143,8 +145,9 @@ function canonicalizeContract(ir) {
143
145
  schemaVersion: ir.schemaVersion,
144
146
  targetFamily: ir.targetFamily,
145
147
  target: ir.target,
148
+ ...ifDefined("roots", ir.roots),
146
149
  models: ir.models,
147
- relations: ir.relations,
150
+ ...ifDefined("relations", ir.relations),
148
151
  storage: ir.storage,
149
152
  ...ifDefined("execution", ir.execution),
150
153
  extensionPacks: ir.extensionPacks,
@@ -211,6 +214,57 @@ function computeExecutionHash(contract) {
211
214
 
212
215
  //#endregion
213
216
  //#region src/emission/emit.ts
217
+ function stripStrategyFromRelations(relations) {
218
+ if (!relations) return void 0;
219
+ const result = {};
220
+ for (const [relName, rel] of Object.entries(relations)) {
221
+ const { strategy: _, ...rest } = rel;
222
+ result[relName] = rest;
223
+ }
224
+ return result;
225
+ }
226
+ function toDomainModel(models) {
227
+ const result = {};
228
+ for (const [modelName, modelUnknown] of Object.entries(models)) {
229
+ const model = modelUnknown;
230
+ const relations = model["relations"];
231
+ const cleanedRelations = stripStrategyFromRelations(relations);
232
+ const fields = model["fields"];
233
+ if (!fields) {
234
+ result[modelName] = {
235
+ ...model,
236
+ ...cleanedRelations !== void 0 ? { relations: cleanedRelations } : {}
237
+ };
238
+ continue;
239
+ }
240
+ if (!Object.values(fields).some((f) => f["codecId"] !== void 0)) {
241
+ result[modelName] = {
242
+ ...model,
243
+ ...cleanedRelations !== void 0 ? { relations: cleanedRelations } : {}
244
+ };
245
+ continue;
246
+ }
247
+ const storage = model["storage"] ?? {};
248
+ const mergedStorageFields = { ...storage["fields"] ?? {} };
249
+ const cleanedFields = {};
250
+ for (const [fieldName, field] of Object.entries(fields)) {
251
+ const { column, ...domainOnly } = field;
252
+ if (domainOnly["nullable"] === void 0) domainOnly["nullable"] = false;
253
+ cleanedFields[fieldName] = domainOnly;
254
+ if (column !== void 0 && !mergedStorageFields[fieldName]) mergedStorageFields[fieldName] = { column };
255
+ }
256
+ result[modelName] = {
257
+ ...model,
258
+ fields: cleanedFields,
259
+ ...cleanedRelations !== void 0 ? { relations: cleanedRelations } : {},
260
+ storage: {
261
+ ...storage,
262
+ fields: mergedStorageFields
263
+ }
264
+ };
265
+ }
266
+ return result;
267
+ }
214
268
  const CanonicalMetaSchema = type({ "[string]": "unknown" });
215
269
  const CanonicalContractSchema = type({
216
270
  "+": "reject",
@@ -218,7 +272,8 @@ const CanonicalContractSchema = type({
218
272
  targetFamily: "string",
219
273
  target: "string",
220
274
  models: type({ "[string]": "unknown" }),
221
- relations: type({ "[string]": "unknown" }),
275
+ "relations?": type({ "[string]": "unknown" }),
276
+ "roots?": "Record<string, string>",
222
277
  storage: type({ "[string]": "unknown" }),
223
278
  "execution?": type({ "[string]": "unknown" }),
224
279
  extensionPacks: type({ "[string]": "unknown" }),
@@ -240,7 +295,7 @@ function validateCoreStructure(ir) {
240
295
  if (!ir.schemaVersion) throw new Error("ContractIR must have schemaVersion");
241
296
  if (!ir.models || typeof ir.models !== "object") throw new Error("ContractIR must have models");
242
297
  if (!ir.storage || typeof ir.storage !== "object") throw new Error("ContractIR must have storage");
243
- if (!ir.relations || typeof ir.relations !== "object") throw new Error("ContractIR must have relations");
298
+ if (ir.relations !== void 0 && typeof ir.relations !== "object") throw new Error("ContractIR relations must be an object when provided");
244
299
  if (!ir.extensionPacks || typeof ir.extensionPacks !== "object") throw new Error("ContractIR must have extensionPacks");
245
300
  if (!ir.capabilities || typeof ir.capabilities !== "object") throw new Error("ContractIR must have capabilities");
246
301
  if (!ir.meta || typeof ir.meta !== "object") throw new Error("ContractIR must have meta");
@@ -260,8 +315,9 @@ async function emit(ir, options, targetFamily) {
260
315
  schemaVersion: ir.schemaVersion,
261
316
  targetFamily: ir.targetFamily,
262
317
  target: ir.target,
263
- models: ir.models,
264
- relations: ir.relations,
318
+ ...ifDefined("roots", ir.roots),
319
+ models: toDomainModel(ir.models),
320
+ ...ifDefined("relations", ir.relations),
265
321
  storage: ir.storage,
266
322
  ...ifDefined("execution", ir.execution),
267
323
  extensionPacks: ir.extensionPacks,
@@ -1 +1 @@
1
- {"version":3,"file":"emission.mjs","names":["result: Record<string, unknown>","sorted: Record<string, unknown>","result: StorageObject","sortedTable: TableObject","ordered: Record<string, unknown>","normalized: NormalizedContract","ctx: ValidationContext"],"sources":["../src/emission/canonicalization.ts","../src/emission/hashing.ts","../src/emission/emit.ts"],"sourcesContent":["import { bigintJsonReplacer } from '@prisma-next/contract/types';\nimport { isArrayEqual } from '@prisma-next/utils/array-equal';\nimport { ifDefined } from '@prisma-next/utils/defined';\n\ntype NormalizedContract = {\n schemaVersion: string;\n targetFamily: string;\n target: string;\n storageHash?: string;\n executionHash?: string;\n profileHash?: string;\n models: Record<string, unknown>;\n relations: Record<string, unknown>;\n storage: Record<string, unknown>;\n execution?: Record<string, unknown>;\n extensionPacks: Record<string, unknown>;\n capabilities: Record<string, Record<string, boolean>>;\n meta: Record<string, unknown>;\n};\n\nexport type CanonicalContractInput = {\n schemaVersion: string;\n targetFamily: string;\n target: string;\n models: Record<string, unknown>;\n relations: Record<string, unknown>;\n storage: Record<string, unknown>;\n execution?: Record<string, unknown>;\n extensionPacks: Record<string, unknown>;\n capabilities: Record<string, Record<string, boolean>>;\n meta: Record<string, unknown>;\n storageHash?: string;\n executionHash?: string;\n profileHash?: string;\n};\n\nconst TOP_LEVEL_ORDER = [\n 'schemaVersion',\n 'canonicalVersion',\n 'targetFamily',\n 'target',\n 'storageHash',\n 'executionHash',\n 'profileHash',\n 'models',\n 'relations',\n 'storage',\n 'execution',\n 'capabilities',\n 'extensionPacks',\n 'meta',\n] as const;\n\nfunction isDefaultValue(value: unknown): boolean {\n if (value === false) return true;\n if (value === null) return false;\n if (value instanceof Date) return false;\n if (Array.isArray(value) && value.length === 0) return true;\n if (typeof value === 'object' && value !== null) {\n const keys = Object.keys(value);\n return keys.length === 0;\n }\n return false;\n}\n\nfunction omitDefaults(obj: unknown, path: readonly string[]): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (obj instanceof Date) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => omitDefaults(item, path));\n }\n\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n const currentPath = [...path, key];\n\n // Exclude metadata fields from canonicalization\n if (key === '_generated') {\n continue;\n }\n\n if (key === 'nullable' && value === false) {\n continue;\n }\n\n if (key === 'generated' && value === false) {\n continue;\n }\n\n // Strip 'noAction' referential actions (the database default) for hash stability.\n // A contract with explicit `onDelete: 'noAction'` is semantically identical to\n // one that omits `onDelete` entirely, so they should produce the same hash.\n if ((key === 'onDelete' || key === 'onUpdate') && value === 'noAction') {\n continue;\n }\n\n if (isDefaultValue(value)) {\n const isRequiredModels = isArrayEqual(currentPath, ['models']);\n const isRequiredTables = isArrayEqual(currentPath, ['storage', 'tables']);\n const isRequiredRelations = isArrayEqual(currentPath, ['relations']);\n const isRequiredExtensionPacks = isArrayEqual(currentPath, ['extensionPacks']);\n const isRequiredCapabilities = isArrayEqual(currentPath, ['capabilities']);\n const isRequiredMeta = isArrayEqual(currentPath, ['meta']);\n const isRequiredExecutionDefaults = isArrayEqual(currentPath, [\n 'execution',\n 'mutations',\n 'defaults',\n ]);\n const isExtensionNamespace = currentPath.length === 2 && currentPath[0] === 'extensionPacks';\n const isModelRelations =\n currentPath.length === 3 &&\n isArrayEqual([currentPath[0], currentPath[2]], ['models', 'relations']);\n const isTableUniques =\n currentPath.length === 4 &&\n isArrayEqual(\n [currentPath[0], currentPath[1], currentPath[3]],\n ['storage', 'tables', 'uniques'],\n );\n const isTableIndexes =\n currentPath.length === 4 &&\n isArrayEqual(\n [currentPath[0], currentPath[1], currentPath[3]],\n ['storage', 'tables', 'indexes'],\n );\n const isTableForeignKeys =\n currentPath.length === 4 &&\n isArrayEqual(\n [currentPath[0], currentPath[1], currentPath[3]],\n ['storage', 'tables', 'foreignKeys'],\n );\n\n // Preserve per-FK `constraint` and `index` booleans (even when `false`)\n // so that hash distinguishes `false` from absent.\n // Path: ['storage', 'tables', <tableName>, 'foreignKeys', 'constraint' | 'index']\n const isFkBooleanField =\n currentPath.length === 5 &&\n currentPath[0] === 'storage' &&\n currentPath[1] === 'tables' &&\n currentPath[3] === 'foreignKeys' &&\n (key === 'constraint' || key === 'index');\n\n if (\n !isRequiredModels &&\n !isRequiredTables &&\n !isRequiredRelations &&\n !isRequiredExtensionPacks &&\n !isRequiredCapabilities &&\n !isRequiredMeta &&\n !isRequiredExecutionDefaults &&\n !isExtensionNamespace &&\n !isModelRelations &&\n !isTableUniques &&\n !isTableIndexes &&\n !isTableForeignKeys &&\n !isFkBooleanField\n ) {\n continue;\n }\n }\n\n result[key] = omitDefaults(value, currentPath);\n }\n\n return result;\n}\n\nfunction sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (obj instanceof Date) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => sortObjectKeys(item));\n }\n\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(obj).sort();\n for (const key of keys) {\n sorted[key] = sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n\n return sorted;\n}\n\ntype StorageObject = {\n tables?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\ntype TableObject = {\n indexes?: unknown[];\n uniques?: unknown[];\n [key: string]: unknown;\n};\n\nfunction sortIndexesAndUniques(storage: unknown): unknown {\n if (!storage || typeof storage !== 'object') {\n return storage;\n }\n\n const storageObj = storage as StorageObject;\n if (!storageObj.tables || typeof storageObj.tables !== 'object') {\n return storage;\n }\n\n const tables = storageObj.tables;\n const result: StorageObject = { ...storageObj };\n\n result.tables = {};\n // Sort table names to ensure deterministic ordering\n const sortedTableNames = Object.keys(tables).sort();\n for (const tableName of sortedTableNames) {\n const table = tables[tableName];\n if (!table || typeof table !== 'object') {\n result.tables[tableName] = table;\n continue;\n }\n\n const tableObj = table as TableObject;\n const sortedTable: TableObject = { ...tableObj };\n\n if (Array.isArray(tableObj.indexes)) {\n sortedTable.indexes = [...tableObj.indexes].sort((a, b) => {\n const nameA = (a as { name?: string })?.name || '';\n const nameB = (b as { name?: string })?.name || '';\n return nameA.localeCompare(nameB);\n });\n }\n\n if (Array.isArray(tableObj.uniques)) {\n sortedTable.uniques = [...tableObj.uniques].sort((a, b) => {\n const nameA = (a as { name?: string })?.name || '';\n const nameB = (b as { name?: string })?.name || '';\n return nameA.localeCompare(nameB);\n });\n }\n\n result.tables[tableName] = sortedTable;\n }\n\n return result;\n}\n\nfunction orderTopLevel(obj: Record<string, unknown>): Record<string, unknown> {\n const ordered: Record<string, unknown> = {};\n const remaining = new Set(Object.keys(obj));\n\n for (const key of TOP_LEVEL_ORDER) {\n if (remaining.has(key)) {\n ordered[key] = obj[key];\n remaining.delete(key);\n }\n }\n\n for (const key of Array.from(remaining).sort()) {\n ordered[key] = obj[key];\n }\n\n return ordered;\n}\n\nexport function canonicalizeContract(ir: CanonicalContractInput): string {\n const normalized: NormalizedContract = {\n schemaVersion: ir.schemaVersion,\n targetFamily: ir.targetFamily,\n target: ir.target,\n models: ir.models,\n relations: ir.relations,\n storage: ir.storage,\n ...ifDefined('execution', ir.execution),\n extensionPacks: ir.extensionPacks,\n capabilities: ir.capabilities,\n meta: ir.meta,\n };\n Object.assign(\n normalized,\n ifDefined('storageHash', ir.storageHash),\n ifDefined('executionHash', ir.executionHash),\n ifDefined('profileHash', ir.profileHash),\n );\n\n const withDefaultsOmitted = omitDefaults(normalized, []) as NormalizedContract;\n const withSortedIndexes = sortIndexesAndUniques(withDefaultsOmitted.storage);\n const withSortedStorage = { ...withDefaultsOmitted, storage: withSortedIndexes };\n const withSortedKeys = sortObjectKeys(withSortedStorage) as Record<string, unknown>;\n const withOrderedTopLevel = orderTopLevel(withSortedKeys);\n\n return JSON.stringify(withOrderedTopLevel, bigintJsonReplacer, 2);\n}\n","import { createHash } from 'node:crypto';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { CanonicalContractInput } from './canonicalization';\nimport { canonicalizeContract } from './canonicalization';\n\nfunction computeHash(content: string): string {\n const hash = createHash('sha256');\n hash.update(content);\n return `sha256:${hash.digest('hex')}`;\n}\n\nexport function computeStorageHash(contract: CanonicalContractInput): string {\n const storageContract = {\n schemaVersion: contract.schemaVersion,\n targetFamily: contract.targetFamily,\n target: contract.target,\n storage: contract.storage,\n models: {},\n relations: {},\n extensionPacks: {},\n capabilities: {},\n meta: {},\n };\n const canonical = canonicalizeContract(storageContract);\n return computeHash(canonical);\n}\n\nexport function computeProfileHash(contract: CanonicalContractInput): string {\n const profileContract = {\n schemaVersion: contract.schemaVersion,\n targetFamily: contract.targetFamily,\n target: contract.target,\n models: {},\n relations: {},\n storage: {},\n extensionPacks: {},\n capabilities: contract.capabilities,\n meta: {},\n };\n const canonical = canonicalizeContract(profileContract);\n return computeHash(canonical);\n}\n\nexport function computeExecutionHash(contract: CanonicalContractInput): string {\n const executionContract = {\n schemaVersion: contract.schemaVersion,\n targetFamily: contract.targetFamily,\n target: contract.target,\n models: {},\n relations: {},\n storage: {},\n extensionPacks: {},\n capabilities: {},\n meta: {},\n ...ifDefined('execution', contract.execution),\n };\n const canonical = canonicalizeContract(executionContract);\n return computeHash(canonical);\n}\n","import type { ContractIR } from '@prisma-next/contract/ir';\nimport type { TargetFamilyHook, ValidationContext } from '@prisma-next/contract/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { type } from 'arktype';\nimport { format } from 'prettier';\nimport { canonicalizeContract } from './canonicalization';\nimport { computeExecutionHash, computeProfileHash, computeStorageHash } from './hashing';\nimport type { EmitOptions, EmitResult } from './types';\n\nconst CanonicalMetaSchema = type({\n '[string]': 'unknown',\n});\n\nconst CanonicalContractSchema = type({\n '+': 'reject',\n schemaVersion: 'string',\n targetFamily: 'string',\n target: 'string',\n models: type({ '[string]': 'unknown' }),\n relations: type({ '[string]': 'unknown' }),\n storage: type({ '[string]': 'unknown' }),\n 'execution?': type({ '[string]': 'unknown' }),\n extensionPacks: type({ '[string]': 'unknown' }),\n capabilities: type({\n '[string]': type({\n '[string]': 'boolean',\n }),\n }),\n meta: CanonicalMetaSchema,\n});\n\nfunction assertCanonicalArtifactShape(value: unknown): void {\n const result = CanonicalContractSchema(value);\n if (result instanceof type.errors) {\n const issues = result\n .map((error) => {\n const path = error.path?.toString() ?? '<root>';\n return `${path}: ${error.message}`;\n })\n .join('; ');\n throw new Error(`ContractIR canonical artifact validation failed: ${issues}`);\n }\n}\n\nfunction validateCoreStructure(ir: ContractIR): void {\n if (!ir.targetFamily) {\n throw new Error('ContractIR must have targetFamily');\n }\n if (!ir.target) {\n throw new Error('ContractIR must have target');\n }\n if (!ir.schemaVersion) {\n throw new Error('ContractIR must have schemaVersion');\n }\n if (!ir.models || typeof ir.models !== 'object') {\n throw new Error('ContractIR must have models');\n }\n if (!ir.storage || typeof ir.storage !== 'object') {\n throw new Error('ContractIR must have storage');\n }\n if (!ir.relations || typeof ir.relations !== 'object') {\n throw new Error('ContractIR must have relations');\n }\n if (!ir.extensionPacks || typeof ir.extensionPacks !== 'object') {\n throw new Error('ContractIR must have extensionPacks');\n }\n if (!ir.capabilities || typeof ir.capabilities !== 'object') {\n throw new Error('ContractIR must have capabilities');\n }\n if (!ir.meta || typeof ir.meta !== 'object') {\n throw new Error('ContractIR must have meta');\n }\n}\n\nexport async function emit(\n ir: ContractIR,\n options: EmitOptions,\n targetFamily: TargetFamilyHook,\n): Promise<EmitResult> {\n const {\n operationRegistry,\n codecTypeImports,\n operationTypeImports,\n extensionIds,\n parameterizedRenderers,\n parameterizedTypeImports,\n queryOperationTypeImports,\n } = options;\n\n validateCoreStructure(ir);\n\n const ctx: ValidationContext = {\n ...ifDefined('operationRegistry', operationRegistry),\n ...ifDefined('codecTypeImports', codecTypeImports),\n ...ifDefined('operationTypeImports', operationTypeImports),\n ...ifDefined('extensionIds', extensionIds),\n };\n targetFamily.validateTypes(ir, ctx);\n\n targetFamily.validateStructure(ir);\n\n const canonicalContract = {\n schemaVersion: ir.schemaVersion,\n targetFamily: ir.targetFamily,\n target: ir.target,\n models: ir.models,\n relations: ir.relations,\n storage: ir.storage,\n ...ifDefined('execution', ir.execution),\n extensionPacks: ir.extensionPacks,\n capabilities: ir.capabilities,\n meta: ir.meta,\n };\n assertCanonicalArtifactShape(canonicalContract);\n\n const storageHash = computeStorageHash(canonicalContract);\n const executionHash = canonicalContract.execution\n ? computeExecutionHash(canonicalContract)\n : undefined;\n const profileHash = computeProfileHash(canonicalContract);\n\n const contractWithHashes = {\n ...canonicalContract,\n storageHash,\n ...ifDefined('executionHash', executionHash),\n profileHash,\n };\n\n // Add _generated metadata to indicate this is a generated artifact\n // This ensures consistency between CLI emit and programmatic emit\n // Always add/update _generated with standard content for consistency\n const contractJsonObj = JSON.parse(canonicalizeContract(contractWithHashes)) as Record<\n string,\n unknown\n >;\n const contractJsonWithMeta = {\n ...contractJsonObj,\n _generated: {\n warning: '⚠️ GENERATED FILE - DO NOT EDIT',\n message: 'This file is automatically generated by \"prisma-next contract emit\".',\n regenerate: 'To regenerate, run: prisma-next contract emit',\n },\n };\n const contractJsonString = JSON.stringify(contractJsonWithMeta, null, 2);\n\n const generateOptions =\n parameterizedRenderers || parameterizedTypeImports || queryOperationTypeImports\n ? {\n ...ifDefined('parameterizedRenderers', parameterizedRenderers),\n ...ifDefined('parameterizedTypeImports', parameterizedTypeImports),\n ...ifDefined('queryOperationTypeImports', queryOperationTypeImports),\n }\n : undefined;\n\n const contractTypeHashes = {\n storageHash,\n ...ifDefined('executionHash', executionHash),\n profileHash,\n };\n const contractDtsRaw = targetFamily.generateContractTypes(\n ir,\n codecTypeImports ?? [],\n operationTypeImports ?? [],\n contractTypeHashes,\n generateOptions,\n );\n const contractDts = await format(contractDtsRaw, {\n parser: 'typescript',\n singleQuote: true,\n semi: true,\n printWidth: 100,\n });\n\n return {\n contractJson: contractJsonString,\n contractDts,\n storageHash,\n ...ifDefined('executionHash', executionHash),\n profileHash,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"emission.mjs","names":["result: Record<string, unknown>","sorted: Record<string, unknown>","result: StorageObject","sortedTable: TableObject","ordered: Record<string, unknown>","normalized: NormalizedContract","result: Record<string, Record<string, unknown>>","result: Record<string, unknown>","mergedStorageFields: Record<string, Record<string, unknown>>","cleanedFields: Record<string, Record<string, unknown>>","ctx: ValidationContext"],"sources":["../src/emission/canonicalization.ts","../src/emission/hashing.ts","../src/emission/emit.ts"],"sourcesContent":["import { bigintJsonReplacer } from '@prisma-next/contract/types';\nimport { isArrayEqual } from '@prisma-next/utils/array-equal';\nimport { ifDefined } from '@prisma-next/utils/defined';\n\ntype NormalizedContract = {\n schemaVersion: string;\n targetFamily: string;\n target: string;\n storageHash?: string;\n executionHash?: string;\n profileHash?: string;\n roots?: Record<string, string>;\n models: Record<string, unknown>;\n relations?: Record<string, unknown>;\n storage: Record<string, unknown>;\n execution?: Record<string, unknown>;\n extensionPacks: Record<string, unknown>;\n capabilities: Record<string, Record<string, boolean>>;\n meta: Record<string, unknown>;\n};\n\nexport type CanonicalContractInput = {\n schemaVersion: string;\n targetFamily: string;\n target: string;\n roots?: Record<string, string>;\n models: Record<string, unknown>;\n relations?: Record<string, unknown>;\n storage: Record<string, unknown>;\n execution?: Record<string, unknown>;\n extensionPacks: Record<string, unknown>;\n capabilities: Record<string, Record<string, boolean>>;\n meta: Record<string, unknown>;\n storageHash?: string;\n executionHash?: string;\n profileHash?: string;\n};\n\nconst TOP_LEVEL_ORDER = [\n 'schemaVersion',\n 'canonicalVersion',\n 'targetFamily',\n 'target',\n 'storageHash',\n 'executionHash',\n 'profileHash',\n 'roots',\n 'models',\n 'relations',\n 'storage',\n 'execution',\n 'capabilities',\n 'extensionPacks',\n 'meta',\n] as const;\n\nfunction isDefaultValue(value: unknown): boolean {\n if (value === false) return true;\n if (value === null) return false;\n if (value instanceof Date) return false;\n if (Array.isArray(value) && value.length === 0) return true;\n if (typeof value === 'object' && value !== null) {\n const keys = Object.keys(value);\n return keys.length === 0;\n }\n return false;\n}\n\nfunction omitDefaults(obj: unknown, path: readonly string[]): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (obj instanceof Date) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => omitDefaults(item, path));\n }\n\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n const currentPath = [...path, key];\n\n // Exclude metadata fields from canonicalization\n if (key === '_generated') {\n continue;\n }\n\n if (key === 'nullable' && value === false) {\n continue;\n }\n\n if (key === 'generated' && value === false) {\n continue;\n }\n\n // Strip 'noAction' referential actions (the database default) for hash stability.\n // A contract with explicit `onDelete: 'noAction'` is semantically identical to\n // one that omits `onDelete` entirely, so they should produce the same hash.\n if ((key === 'onDelete' || key === 'onUpdate') && value === 'noAction') {\n continue;\n }\n\n if (isDefaultValue(value)) {\n const isRequiredModels = isArrayEqual(currentPath, ['models']);\n const isRequiredTables = isArrayEqual(currentPath, ['storage', 'tables']);\n const isRequiredRelations = isArrayEqual(currentPath, ['relations']);\n const isRequiredRoots = isArrayEqual(currentPath, ['roots']);\n const isRequiredExtensionPacks = isArrayEqual(currentPath, ['extensionPacks']);\n const isRequiredCapabilities = isArrayEqual(currentPath, ['capabilities']);\n const isRequiredMeta = isArrayEqual(currentPath, ['meta']);\n const isRequiredExecutionDefaults = isArrayEqual(currentPath, [\n 'execution',\n 'mutations',\n 'defaults',\n ]);\n const isExtensionNamespace = currentPath.length === 2 && currentPath[0] === 'extensionPacks';\n const isModelRelations =\n currentPath.length === 3 &&\n isArrayEqual([currentPath[0], currentPath[2]], ['models', 'relations']);\n const isTableUniques =\n currentPath.length === 4 &&\n isArrayEqual(\n [currentPath[0], currentPath[1], currentPath[3]],\n ['storage', 'tables', 'uniques'],\n );\n const isTableIndexes =\n currentPath.length === 4 &&\n isArrayEqual(\n [currentPath[0], currentPath[1], currentPath[3]],\n ['storage', 'tables', 'indexes'],\n );\n const isTableForeignKeys =\n currentPath.length === 4 &&\n isArrayEqual(\n [currentPath[0], currentPath[1], currentPath[3]],\n ['storage', 'tables', 'foreignKeys'],\n );\n\n // Preserve per-FK `constraint` and `index` booleans (even when `false`)\n // so that hash distinguishes `false` from absent.\n // Path: ['storage', 'tables', <tableName>, 'foreignKeys', 'constraint' | 'index']\n const isFkBooleanField =\n currentPath.length === 5 &&\n currentPath[0] === 'storage' &&\n currentPath[1] === 'tables' &&\n currentPath[3] === 'foreignKeys' &&\n (key === 'constraint' || key === 'index');\n\n if (\n !isRequiredModels &&\n !isRequiredTables &&\n !isRequiredRelations &&\n !isRequiredRoots &&\n !isRequiredExtensionPacks &&\n !isRequiredCapabilities &&\n !isRequiredMeta &&\n !isRequiredExecutionDefaults &&\n !isExtensionNamespace &&\n !isModelRelations &&\n !isTableUniques &&\n !isTableIndexes &&\n !isTableForeignKeys &&\n !isFkBooleanField\n ) {\n continue;\n }\n }\n\n result[key] = omitDefaults(value, currentPath);\n }\n\n return result;\n}\n\nfunction sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (obj instanceof Date) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => sortObjectKeys(item));\n }\n\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(obj).sort();\n for (const key of keys) {\n sorted[key] = sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n\n return sorted;\n}\n\ntype StorageObject = {\n tables?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\ntype TableObject = {\n indexes?: unknown[];\n uniques?: unknown[];\n [key: string]: unknown;\n};\n\nfunction sortIndexesAndUniques(storage: unknown): unknown {\n if (!storage || typeof storage !== 'object') {\n return storage;\n }\n\n const storageObj = storage as StorageObject;\n if (!storageObj.tables || typeof storageObj.tables !== 'object') {\n return storage;\n }\n\n const tables = storageObj.tables;\n const result: StorageObject = { ...storageObj };\n\n result.tables = {};\n // Sort table names to ensure deterministic ordering\n const sortedTableNames = Object.keys(tables).sort();\n for (const tableName of sortedTableNames) {\n const table = tables[tableName];\n if (!table || typeof table !== 'object') {\n result.tables[tableName] = table;\n continue;\n }\n\n const tableObj = table as TableObject;\n const sortedTable: TableObject = { ...tableObj };\n\n if (Array.isArray(tableObj.indexes)) {\n sortedTable.indexes = [...tableObj.indexes].sort((a, b) => {\n const nameA = (a as { name?: string })?.name || '';\n const nameB = (b as { name?: string })?.name || '';\n return nameA.localeCompare(nameB);\n });\n }\n\n if (Array.isArray(tableObj.uniques)) {\n sortedTable.uniques = [...tableObj.uniques].sort((a, b) => {\n const nameA = (a as { name?: string })?.name || '';\n const nameB = (b as { name?: string })?.name || '';\n return nameA.localeCompare(nameB);\n });\n }\n\n result.tables[tableName] = sortedTable;\n }\n\n return result;\n}\n\nfunction orderTopLevel(obj: Record<string, unknown>): Record<string, unknown> {\n const ordered: Record<string, unknown> = {};\n const remaining = new Set(Object.keys(obj));\n\n for (const key of TOP_LEVEL_ORDER) {\n if (remaining.has(key)) {\n ordered[key] = obj[key];\n remaining.delete(key);\n }\n }\n\n for (const key of Array.from(remaining).sort()) {\n ordered[key] = obj[key];\n }\n\n return ordered;\n}\n\nexport function canonicalizeContract(ir: CanonicalContractInput): string {\n const normalized: NormalizedContract = {\n schemaVersion: ir.schemaVersion,\n targetFamily: ir.targetFamily,\n target: ir.target,\n ...ifDefined('roots', ir.roots),\n models: ir.models,\n ...ifDefined('relations', ir.relations),\n storage: ir.storage,\n ...ifDefined('execution', ir.execution),\n extensionPacks: ir.extensionPacks,\n capabilities: ir.capabilities,\n meta: ir.meta,\n };\n Object.assign(\n normalized,\n ifDefined('storageHash', ir.storageHash),\n ifDefined('executionHash', ir.executionHash),\n ifDefined('profileHash', ir.profileHash),\n );\n\n const withDefaultsOmitted = omitDefaults(normalized, []) as NormalizedContract;\n const withSortedIndexes = sortIndexesAndUniques(withDefaultsOmitted.storage);\n const withSortedStorage = { ...withDefaultsOmitted, storage: withSortedIndexes };\n const withSortedKeys = sortObjectKeys(withSortedStorage) as Record<string, unknown>;\n const withOrderedTopLevel = orderTopLevel(withSortedKeys);\n\n return JSON.stringify(withOrderedTopLevel, bigintJsonReplacer, 2);\n}\n","import { createHash } from 'node:crypto';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { CanonicalContractInput } from './canonicalization';\nimport { canonicalizeContract } from './canonicalization';\n\nfunction computeHash(content: string): string {\n const hash = createHash('sha256');\n hash.update(content);\n return `sha256:${hash.digest('hex')}`;\n}\n\nexport function computeStorageHash(contract: CanonicalContractInput): string {\n const storageContract = {\n schemaVersion: contract.schemaVersion,\n targetFamily: contract.targetFamily,\n target: contract.target,\n storage: contract.storage,\n models: {},\n relations: {},\n extensionPacks: {},\n capabilities: {},\n meta: {},\n };\n const canonical = canonicalizeContract(storageContract);\n return computeHash(canonical);\n}\n\nexport function computeProfileHash(contract: CanonicalContractInput): string {\n const profileContract = {\n schemaVersion: contract.schemaVersion,\n targetFamily: contract.targetFamily,\n target: contract.target,\n models: {},\n relations: {},\n storage: {},\n extensionPacks: {},\n capabilities: contract.capabilities,\n meta: {},\n };\n const canonical = canonicalizeContract(profileContract);\n return computeHash(canonical);\n}\n\nexport function computeExecutionHash(contract: CanonicalContractInput): string {\n const executionContract = {\n schemaVersion: contract.schemaVersion,\n targetFamily: contract.targetFamily,\n target: contract.target,\n models: {},\n relations: {},\n storage: {},\n extensionPacks: {},\n capabilities: {},\n meta: {},\n ...ifDefined('execution', contract.execution),\n };\n const canonical = canonicalizeContract(executionContract);\n return computeHash(canonical);\n}\n","import type { ContractIR } from '@prisma-next/contract/ir';\nimport type { TargetFamilyHook, ValidationContext } from '@prisma-next/contract/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { type } from 'arktype';\nimport { format } from 'prettier';\nimport { canonicalizeContract } from './canonicalization';\nimport { computeExecutionHash, computeProfileHash, computeStorageHash } from './hashing';\nimport type { EmitOptions, EmitResult } from './types';\n\nfunction stripStrategyFromRelations(\n relations: Record<string, Record<string, unknown>> | undefined,\n): Record<string, Record<string, unknown>> | undefined {\n if (!relations) return undefined;\n const result: Record<string, Record<string, unknown>> = {};\n for (const [relName, rel] of Object.entries(relations)) {\n const { strategy: _, ...rest } = rel;\n result[relName] = rest;\n }\n return result;\n}\n\nfunction toDomainModel(models: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [modelName, modelUnknown] of Object.entries(models)) {\n const model = modelUnknown as Record<string, unknown>;\n const relations = model['relations'] as Record<string, Record<string, unknown>> | undefined;\n const cleanedRelations = stripStrategyFromRelations(relations);\n\n const fields = model['fields'] as Record<string, Record<string, unknown>> | undefined;\n if (!fields) {\n result[modelName] = {\n ...model,\n ...(cleanedRelations !== undefined ? { relations: cleanedRelations } : {}),\n };\n continue;\n }\n\n const hasEnrichedFields = Object.values(fields).some((f) => f['codecId'] !== undefined);\n if (!hasEnrichedFields) {\n result[modelName] = {\n ...model,\n ...(cleanedRelations !== undefined ? { relations: cleanedRelations } : {}),\n };\n continue;\n }\n\n const storage = (model['storage'] ?? {}) as Record<string, unknown>;\n const existingStorageFields = (storage['fields'] ?? {}) as Record<\n string,\n Record<string, unknown>\n >;\n const mergedStorageFields: Record<string, Record<string, unknown>> = {\n ...existingStorageFields,\n };\n\n const cleanedFields: Record<string, Record<string, unknown>> = {};\n for (const [fieldName, field] of Object.entries(fields)) {\n const { column, ...domainOnly } = field;\n if (domainOnly['nullable'] === undefined) {\n domainOnly['nullable'] = false;\n }\n cleanedFields[fieldName] = domainOnly;\n\n if (column !== undefined && !mergedStorageFields[fieldName]) {\n mergedStorageFields[fieldName] = { column };\n }\n }\n\n result[modelName] = {\n ...model,\n fields: cleanedFields,\n ...(cleanedRelations !== undefined ? { relations: cleanedRelations } : {}),\n storage: { ...storage, fields: mergedStorageFields },\n };\n }\n return result;\n}\n\nconst CanonicalMetaSchema = type({\n '[string]': 'unknown',\n});\n\nconst CanonicalContractSchema = type({\n '+': 'reject',\n schemaVersion: 'string',\n targetFamily: 'string',\n target: 'string',\n models: type({ '[string]': 'unknown' }),\n 'relations?': type({ '[string]': 'unknown' }),\n 'roots?': 'Record<string, string>',\n storage: type({ '[string]': 'unknown' }),\n 'execution?': type({ '[string]': 'unknown' }),\n extensionPacks: type({ '[string]': 'unknown' }),\n capabilities: type({\n '[string]': type({\n '[string]': 'boolean',\n }),\n }),\n meta: CanonicalMetaSchema,\n});\n\nfunction assertCanonicalArtifactShape(value: unknown): void {\n const result = CanonicalContractSchema(value);\n if (result instanceof type.errors) {\n const issues = result\n .map((error) => {\n const path = error.path?.toString() ?? '<root>';\n return `${path}: ${error.message}`;\n })\n .join('; ');\n throw new Error(`ContractIR canonical artifact validation failed: ${issues}`);\n }\n}\n\nfunction validateCoreStructure(ir: ContractIR): void {\n if (!ir.targetFamily) {\n throw new Error('ContractIR must have targetFamily');\n }\n if (!ir.target) {\n throw new Error('ContractIR must have target');\n }\n if (!ir.schemaVersion) {\n throw new Error('ContractIR must have schemaVersion');\n }\n if (!ir.models || typeof ir.models !== 'object') {\n throw new Error('ContractIR must have models');\n }\n if (!ir.storage || typeof ir.storage !== 'object') {\n throw new Error('ContractIR must have storage');\n }\n if (ir.relations !== undefined && typeof ir.relations !== 'object') {\n throw new Error('ContractIR relations must be an object when provided');\n }\n if (!ir.extensionPacks || typeof ir.extensionPacks !== 'object') {\n throw new Error('ContractIR must have extensionPacks');\n }\n if (!ir.capabilities || typeof ir.capabilities !== 'object') {\n throw new Error('ContractIR must have capabilities');\n }\n if (!ir.meta || typeof ir.meta !== 'object') {\n throw new Error('ContractIR must have meta');\n }\n}\n\nexport async function emit(\n ir: ContractIR,\n options: EmitOptions,\n targetFamily: TargetFamilyHook,\n): Promise<EmitResult> {\n const {\n operationRegistry,\n codecTypeImports,\n operationTypeImports,\n extensionIds,\n parameterizedRenderers,\n parameterizedTypeImports,\n queryOperationTypeImports,\n } = options;\n\n validateCoreStructure(ir);\n\n const ctx: ValidationContext = {\n ...ifDefined('operationRegistry', operationRegistry),\n ...ifDefined('codecTypeImports', codecTypeImports),\n ...ifDefined('operationTypeImports', operationTypeImports),\n ...ifDefined('extensionIds', extensionIds),\n };\n targetFamily.validateTypes(ir, ctx);\n\n targetFamily.validateStructure(ir);\n\n const canonicalContract = {\n schemaVersion: ir.schemaVersion,\n targetFamily: ir.targetFamily,\n target: ir.target,\n ...ifDefined('roots', ir.roots),\n models: toDomainModel(ir.models as Record<string, unknown>),\n ...ifDefined('relations', ir.relations),\n storage: ir.storage,\n ...ifDefined('execution', ir.execution),\n extensionPacks: ir.extensionPacks,\n capabilities: ir.capabilities,\n meta: ir.meta,\n };\n assertCanonicalArtifactShape(canonicalContract);\n\n const storageHash = computeStorageHash(canonicalContract);\n const executionHash = canonicalContract.execution\n ? computeExecutionHash(canonicalContract)\n : undefined;\n const profileHash = computeProfileHash(canonicalContract);\n\n const contractWithHashes = {\n ...canonicalContract,\n storageHash,\n ...ifDefined('executionHash', executionHash),\n profileHash,\n };\n\n // Add _generated metadata to indicate this is a generated artifact\n // This ensures consistency between CLI emit and programmatic emit\n // Always add/update _generated with standard content for consistency\n const contractJsonObj = JSON.parse(canonicalizeContract(contractWithHashes)) as Record<\n string,\n unknown\n >;\n const contractJsonWithMeta = {\n ...contractJsonObj,\n _generated: {\n warning: '⚠️ GENERATED FILE - DO NOT EDIT',\n message: 'This file is automatically generated by \"prisma-next contract emit\".',\n regenerate: 'To regenerate, run: prisma-next contract emit',\n },\n };\n const contractJsonString = JSON.stringify(contractJsonWithMeta, null, 2);\n\n const generateOptions =\n parameterizedRenderers || parameterizedTypeImports || queryOperationTypeImports\n ? {\n ...ifDefined('parameterizedRenderers', parameterizedRenderers),\n ...ifDefined('parameterizedTypeImports', parameterizedTypeImports),\n ...ifDefined('queryOperationTypeImports', queryOperationTypeImports),\n }\n : undefined;\n\n const contractTypeHashes = {\n storageHash,\n ...ifDefined('executionHash', executionHash),\n profileHash,\n };\n const contractDtsRaw = targetFamily.generateContractTypes(\n ir,\n codecTypeImports ?? [],\n operationTypeImports ?? [],\n contractTypeHashes,\n generateOptions,\n );\n const contractDts = await format(contractDtsRaw, {\n parser: 'typescript',\n singleQuote: true,\n semi: true,\n printWidth: 100,\n });\n\n return {\n contractJson: contractJsonString,\n contractDts,\n storageHash,\n ...ifDefined('executionHash', executionHash),\n profileHash,\n };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@prisma-next/core-control-plane",
3
- "version": "0.3.0-dev.123",
3
+ "version": "0.3.0-dev.125",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Control-plane migration/emission primitives and structured error utilities",
7
7
  "dependencies": {
8
8
  "arktype": "^2.1.26",
9
9
  "prettier": "^3.3.3",
10
- "@prisma-next/operations": "0.3.0-dev.123",
11
- "@prisma-next/contract": "0.3.0-dev.123",
12
- "@prisma-next/utils": "0.3.0-dev.123"
10
+ "@prisma-next/contract": "0.3.0-dev.125",
11
+ "@prisma-next/operations": "0.3.0-dev.125",
12
+ "@prisma-next/utils": "0.3.0-dev.125"
13
13
  },
14
14
  "devDependencies": {
15
15
  "tsdown": "0.18.4",
@@ -9,8 +9,9 @@ type NormalizedContract = {
9
9
  storageHash?: string;
10
10
  executionHash?: string;
11
11
  profileHash?: string;
12
+ roots?: Record<string, string>;
12
13
  models: Record<string, unknown>;
13
- relations: Record<string, unknown>;
14
+ relations?: Record<string, unknown>;
14
15
  storage: Record<string, unknown>;
15
16
  execution?: Record<string, unknown>;
16
17
  extensionPacks: Record<string, unknown>;
@@ -22,8 +23,9 @@ export type CanonicalContractInput = {
22
23
  schemaVersion: string;
23
24
  targetFamily: string;
24
25
  target: string;
26
+ roots?: Record<string, string>;
25
27
  models: Record<string, unknown>;
26
- relations: Record<string, unknown>;
28
+ relations?: Record<string, unknown>;
27
29
  storage: Record<string, unknown>;
28
30
  execution?: Record<string, unknown>;
29
31
  extensionPacks: Record<string, unknown>;
@@ -42,6 +44,7 @@ const TOP_LEVEL_ORDER = [
42
44
  'storageHash',
43
45
  'executionHash',
44
46
  'profileHash',
47
+ 'roots',
45
48
  'models',
46
49
  'relations',
47
50
  'storage',
@@ -105,6 +108,7 @@ function omitDefaults(obj: unknown, path: readonly string[]): unknown {
105
108
  const isRequiredModels = isArrayEqual(currentPath, ['models']);
106
109
  const isRequiredTables = isArrayEqual(currentPath, ['storage', 'tables']);
107
110
  const isRequiredRelations = isArrayEqual(currentPath, ['relations']);
111
+ const isRequiredRoots = isArrayEqual(currentPath, ['roots']);
108
112
  const isRequiredExtensionPacks = isArrayEqual(currentPath, ['extensionPacks']);
109
113
  const isRequiredCapabilities = isArrayEqual(currentPath, ['capabilities']);
110
114
  const isRequiredMeta = isArrayEqual(currentPath, ['meta']);
@@ -150,6 +154,7 @@ function omitDefaults(obj: unknown, path: readonly string[]): unknown {
150
154
  !isRequiredModels &&
151
155
  !isRequiredTables &&
152
156
  !isRequiredRelations &&
157
+ !isRequiredRoots &&
153
158
  !isRequiredExtensionPacks &&
154
159
  !isRequiredCapabilities &&
155
160
  !isRequiredMeta &&
@@ -275,8 +280,9 @@ export function canonicalizeContract(ir: CanonicalContractInput): string {
275
280
  schemaVersion: ir.schemaVersion,
276
281
  targetFamily: ir.targetFamily,
277
282
  target: ir.target,
283
+ ...ifDefined('roots', ir.roots),
278
284
  models: ir.models,
279
- relations: ir.relations,
285
+ ...ifDefined('relations', ir.relations),
280
286
  storage: ir.storage,
281
287
  ...ifDefined('execution', ir.execution),
282
288
  extensionPacks: ir.extensionPacks,
@@ -7,6 +7,75 @@ import { canonicalizeContract } from './canonicalization';
7
7
  import { computeExecutionHash, computeProfileHash, computeStorageHash } from './hashing';
8
8
  import type { EmitOptions, EmitResult } from './types';
9
9
 
10
+ function stripStrategyFromRelations(
11
+ relations: Record<string, Record<string, unknown>> | undefined,
12
+ ): Record<string, Record<string, unknown>> | undefined {
13
+ if (!relations) return undefined;
14
+ const result: Record<string, Record<string, unknown>> = {};
15
+ for (const [relName, rel] of Object.entries(relations)) {
16
+ const { strategy: _, ...rest } = rel;
17
+ result[relName] = rest;
18
+ }
19
+ return result;
20
+ }
21
+
22
+ function toDomainModel(models: Record<string, unknown>): Record<string, unknown> {
23
+ const result: Record<string, unknown> = {};
24
+ for (const [modelName, modelUnknown] of Object.entries(models)) {
25
+ const model = modelUnknown as Record<string, unknown>;
26
+ const relations = model['relations'] as Record<string, Record<string, unknown>> | undefined;
27
+ const cleanedRelations = stripStrategyFromRelations(relations);
28
+
29
+ const fields = model['fields'] as Record<string, Record<string, unknown>> | undefined;
30
+ if (!fields) {
31
+ result[modelName] = {
32
+ ...model,
33
+ ...(cleanedRelations !== undefined ? { relations: cleanedRelations } : {}),
34
+ };
35
+ continue;
36
+ }
37
+
38
+ const hasEnrichedFields = Object.values(fields).some((f) => f['codecId'] !== undefined);
39
+ if (!hasEnrichedFields) {
40
+ result[modelName] = {
41
+ ...model,
42
+ ...(cleanedRelations !== undefined ? { relations: cleanedRelations } : {}),
43
+ };
44
+ continue;
45
+ }
46
+
47
+ const storage = (model['storage'] ?? {}) as Record<string, unknown>;
48
+ const existingStorageFields = (storage['fields'] ?? {}) as Record<
49
+ string,
50
+ Record<string, unknown>
51
+ >;
52
+ const mergedStorageFields: Record<string, Record<string, unknown>> = {
53
+ ...existingStorageFields,
54
+ };
55
+
56
+ const cleanedFields: Record<string, Record<string, unknown>> = {};
57
+ for (const [fieldName, field] of Object.entries(fields)) {
58
+ const { column, ...domainOnly } = field;
59
+ if (domainOnly['nullable'] === undefined) {
60
+ domainOnly['nullable'] = false;
61
+ }
62
+ cleanedFields[fieldName] = domainOnly;
63
+
64
+ if (column !== undefined && !mergedStorageFields[fieldName]) {
65
+ mergedStorageFields[fieldName] = { column };
66
+ }
67
+ }
68
+
69
+ result[modelName] = {
70
+ ...model,
71
+ fields: cleanedFields,
72
+ ...(cleanedRelations !== undefined ? { relations: cleanedRelations } : {}),
73
+ storage: { ...storage, fields: mergedStorageFields },
74
+ };
75
+ }
76
+ return result;
77
+ }
78
+
10
79
  const CanonicalMetaSchema = type({
11
80
  '[string]': 'unknown',
12
81
  });
@@ -17,7 +86,8 @@ const CanonicalContractSchema = type({
17
86
  targetFamily: 'string',
18
87
  target: 'string',
19
88
  models: type({ '[string]': 'unknown' }),
20
- relations: type({ '[string]': 'unknown' }),
89
+ 'relations?': type({ '[string]': 'unknown' }),
90
+ 'roots?': 'Record<string, string>',
21
91
  storage: type({ '[string]': 'unknown' }),
22
92
  'execution?': type({ '[string]': 'unknown' }),
23
93
  extensionPacks: type({ '[string]': 'unknown' }),
@@ -58,8 +128,8 @@ function validateCoreStructure(ir: ContractIR): void {
58
128
  if (!ir.storage || typeof ir.storage !== 'object') {
59
129
  throw new Error('ContractIR must have storage');
60
130
  }
61
- if (!ir.relations || typeof ir.relations !== 'object') {
62
- throw new Error('ContractIR must have relations');
131
+ if (ir.relations !== undefined && typeof ir.relations !== 'object') {
132
+ throw new Error('ContractIR relations must be an object when provided');
63
133
  }
64
134
  if (!ir.extensionPacks || typeof ir.extensionPacks !== 'object') {
65
135
  throw new Error('ContractIR must have extensionPacks');
@@ -103,8 +173,9 @@ export async function emit(
103
173
  schemaVersion: ir.schemaVersion,
104
174
  targetFamily: ir.targetFamily,
105
175
  target: ir.target,
106
- models: ir.models,
107
- relations: ir.relations,
176
+ ...ifDefined('roots', ir.roots),
177
+ models: toDomainModel(ir.models as Record<string, unknown>),
178
+ ...ifDefined('relations', ir.relations),
108
179
  storage: ir.storage,
109
180
  ...ifDefined('execution', ir.execution),
110
181
  extensionPacks: ir.extensionPacks,