@prisma-next/core-control-plane 0.3.0-dev.130 → 0.3.0-dev.132
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/emission.d.mts
CHANGED
|
@@ -9,7 +9,6 @@ type CanonicalContractInput = {
|
|
|
9
9
|
target: string;
|
|
10
10
|
roots?: Record<string, string>;
|
|
11
11
|
models: Record<string, unknown>;
|
|
12
|
-
relations?: Record<string, unknown>;
|
|
13
12
|
storage: Record<string, unknown>;
|
|
14
13
|
execution?: Record<string, unknown>;
|
|
15
14
|
extensionPacks: Record<string, unknown>;
|
package/dist/emission.d.mts.map
CHANGED
|
@@ -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":";;;;;
|
|
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,MAAA,EAKF,MALE,CAAA,MAAA,EAAA,OAAsB,CAAA;EAIxB,OAAA,EAEC,MAFD,CAAA,MAAA,EAAA,OAAA,CAAA;EACA,SAAA,CAAA,EAEI,MAFJ,CAAA,MAAA,EAAA,OAAA,CAAA;EACC,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;AAwPE,iBAAA,oBAAA,CAAyB,EAAA,EAAA,sBAAsB,CAAA,EAAA,MAAA;;;UCnR9C,WAAA;;+BAEc;EDenB,SAAA,gBAAsB,CAAA,ECdJ,aDcI,CCdU,eDcV,CAAA;EAIxB,SAAA,oBAAA,CAAA,ECjBwB,aDiBxB,CCjBsC,eDiBtC,CAAA;EACA,SAAA,YAAA,CAAA,ECjBgB,aDiBhB,CAAA,MAAA,CAAA;EACC;;;;EAGK,SAAA,sBAAA,CAAA,EChBoB,GDgBpB,CAAA,MAAA,EChBgC,eDgBhC,CAAA;EACR;;AAwPR;;sCCpQsC,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;;;;iBCgFhB,IAAA,KAChB,qBACK,2BACK,mBACb,QAAQ;;;iBC3FK,kBAAA,WAA6B;iBAe7B,kBAAA,WAA6B;iBAe7B,oBAAA,WAA+B"}
|
package/dist/emission.mjs
CHANGED
|
@@ -16,7 +16,6 @@ const TOP_LEVEL_ORDER = [
|
|
|
16
16
|
"profileHash",
|
|
17
17
|
"roots",
|
|
18
18
|
"models",
|
|
19
|
-
"relations",
|
|
20
19
|
"storage",
|
|
21
20
|
"execution",
|
|
22
21
|
"capabilities",
|
|
@@ -47,7 +46,6 @@ function omitDefaults(obj, path) {
|
|
|
47
46
|
const isRequiredTables = isArrayEqual(currentPath, ["storage", "tables"]);
|
|
48
47
|
const isRequiredCollections = isArrayEqual(currentPath, ["storage", "collections"]);
|
|
49
48
|
const isCollectionEntry = currentPath.length === 3 && isArrayEqual([currentPath[0], currentPath[1]], ["storage", "collections"]);
|
|
50
|
-
const isRequiredRelations = isArrayEqual(currentPath, ["relations"]);
|
|
51
49
|
const isRequiredRoots = isArrayEqual(currentPath, ["roots"]);
|
|
52
50
|
const isRequiredExtensionPacks = isArrayEqual(currentPath, ["extensionPacks"]);
|
|
53
51
|
const isRequiredCapabilities = isArrayEqual(currentPath, ["capabilities"]);
|
|
@@ -87,7 +85,7 @@ function omitDefaults(obj, path) {
|
|
|
87
85
|
"foreignKeys"
|
|
88
86
|
]);
|
|
89
87
|
const isFkBooleanField = currentPath.length === 5 && currentPath[0] === "storage" && currentPath[1] === "tables" && currentPath[3] === "foreignKeys" && (key === "constraint" || key === "index");
|
|
90
|
-
if (!isRequiredModels && !isRequiredTables && !isRequiredCollections && !isCollectionEntry && !
|
|
88
|
+
if (!isRequiredModels && !isRequiredTables && !isRequiredCollections && !isCollectionEntry && !isRequiredRoots && !isRequiredExtensionPacks && !isRequiredCapabilities && !isRequiredMeta && !isRequiredExecutionDefaults && !isExtensionNamespace && !isModelRelations && !isTableUniques && !isTableIndexes && !isTableForeignKeys && !isFkBooleanField) continue;
|
|
91
89
|
}
|
|
92
90
|
result[key] = omitDefaults(value, currentPath);
|
|
93
91
|
}
|
|
@@ -149,7 +147,6 @@ function canonicalizeContract(ir) {
|
|
|
149
147
|
target: ir.target,
|
|
150
148
|
...ifDefined("roots", ir.roots),
|
|
151
149
|
models: ir.models,
|
|
152
|
-
...ifDefined("relations", ir.relations),
|
|
153
150
|
storage: ir.storage,
|
|
154
151
|
...ifDefined("execution", ir.execution),
|
|
155
152
|
extensionPacks: ir.extensionPacks,
|
|
@@ -180,7 +177,6 @@ function computeStorageHash(contract) {
|
|
|
180
177
|
target: contract.target,
|
|
181
178
|
storage: contract.storage,
|
|
182
179
|
models: {},
|
|
183
|
-
relations: {},
|
|
184
180
|
extensionPacks: {},
|
|
185
181
|
capabilities: {},
|
|
186
182
|
meta: {}
|
|
@@ -192,7 +188,6 @@ function computeProfileHash(contract) {
|
|
|
192
188
|
targetFamily: contract.targetFamily,
|
|
193
189
|
target: contract.target,
|
|
194
190
|
models: {},
|
|
195
|
-
relations: {},
|
|
196
191
|
storage: {},
|
|
197
192
|
extensionPacks: {},
|
|
198
193
|
capabilities: contract.capabilities,
|
|
@@ -205,7 +200,6 @@ function computeExecutionHash(contract) {
|
|
|
205
200
|
targetFamily: contract.targetFamily,
|
|
206
201
|
target: contract.target,
|
|
207
202
|
models: {},
|
|
208
|
-
relations: {},
|
|
209
203
|
storage: {},
|
|
210
204
|
extensionPacks: {},
|
|
211
205
|
capabilities: {},
|
|
@@ -225,44 +219,15 @@ function stripStrategyFromRelations(relations) {
|
|
|
225
219
|
}
|
|
226
220
|
return result;
|
|
227
221
|
}
|
|
228
|
-
function
|
|
222
|
+
function stripRelationStrategies(models) {
|
|
229
223
|
const result = {};
|
|
230
224
|
for (const [modelName, modelUnknown] of Object.entries(models)) {
|
|
231
225
|
const model = modelUnknown;
|
|
232
226
|
const relations = model["relations"];
|
|
233
227
|
const cleanedRelations = stripStrategyFromRelations(relations);
|
|
234
|
-
const fields = model["fields"];
|
|
235
|
-
if (!fields) {
|
|
236
|
-
result[modelName] = {
|
|
237
|
-
...model,
|
|
238
|
-
...cleanedRelations !== void 0 ? { relations: cleanedRelations } : {}
|
|
239
|
-
};
|
|
240
|
-
continue;
|
|
241
|
-
}
|
|
242
|
-
if (!Object.values(fields).some((f) => f["codecId"] !== void 0)) {
|
|
243
|
-
result[modelName] = {
|
|
244
|
-
...model,
|
|
245
|
-
...cleanedRelations !== void 0 ? { relations: cleanedRelations } : {}
|
|
246
|
-
};
|
|
247
|
-
continue;
|
|
248
|
-
}
|
|
249
|
-
const storage = model["storage"] ?? {};
|
|
250
|
-
const mergedStorageFields = { ...storage["fields"] ?? {} };
|
|
251
|
-
const cleanedFields = {};
|
|
252
|
-
for (const [fieldName, field] of Object.entries(fields)) {
|
|
253
|
-
const { column, ...domainOnly } = field;
|
|
254
|
-
if (domainOnly["nullable"] === void 0) domainOnly["nullable"] = false;
|
|
255
|
-
cleanedFields[fieldName] = domainOnly;
|
|
256
|
-
if (column !== void 0 && !mergedStorageFields[fieldName]) mergedStorageFields[fieldName] = { column };
|
|
257
|
-
}
|
|
258
228
|
result[modelName] = {
|
|
259
229
|
...model,
|
|
260
|
-
|
|
261
|
-
...cleanedRelations !== void 0 ? { relations: cleanedRelations } : {},
|
|
262
|
-
storage: {
|
|
263
|
-
...storage,
|
|
264
|
-
fields: mergedStorageFields
|
|
265
|
-
}
|
|
230
|
+
...cleanedRelations !== void 0 ? { relations: cleanedRelations } : {}
|
|
266
231
|
};
|
|
267
232
|
}
|
|
268
233
|
return result;
|
|
@@ -274,7 +239,6 @@ const CanonicalContractSchema = type({
|
|
|
274
239
|
targetFamily: "string",
|
|
275
240
|
target: "string",
|
|
276
241
|
models: type({ "[string]": "unknown" }),
|
|
277
|
-
"relations?": type({ "[string]": "unknown" }),
|
|
278
242
|
"roots?": "Record<string, string>",
|
|
279
243
|
storage: type({ "[string]": "unknown" }),
|
|
280
244
|
"execution?": type({ "[string]": "unknown" }),
|
|
@@ -297,7 +261,6 @@ function validateCoreStructure(ir) {
|
|
|
297
261
|
if (!ir.schemaVersion) throw new Error("ContractIR must have schemaVersion");
|
|
298
262
|
if (!ir.models || typeof ir.models !== "object") throw new Error("ContractIR must have models");
|
|
299
263
|
if (!ir.storage || typeof ir.storage !== "object") throw new Error("ContractIR must have storage");
|
|
300
|
-
if (ir.relations !== void 0 && typeof ir.relations !== "object") throw new Error("ContractIR relations must be an object when provided");
|
|
301
264
|
if (!ir.extensionPacks || typeof ir.extensionPacks !== "object") throw new Error("ContractIR must have extensionPacks");
|
|
302
265
|
if (!ir.capabilities || typeof ir.capabilities !== "object") throw new Error("ContractIR must have capabilities");
|
|
303
266
|
if (!ir.meta || typeof ir.meta !== "object") throw new Error("ContractIR must have meta");
|
|
@@ -318,8 +281,7 @@ async function emit(ir, options, targetFamily) {
|
|
|
318
281
|
targetFamily: ir.targetFamily,
|
|
319
282
|
target: ir.target,
|
|
320
283
|
...ifDefined("roots", ir.roots),
|
|
321
|
-
models:
|
|
322
|
-
...ifDefined("relations", ir.relations),
|
|
284
|
+
models: stripRelationStrategies(ir.models),
|
|
323
285
|
storage: ir.storage,
|
|
324
286
|
...ifDefined("execution", ir.execution),
|
|
325
287
|
extensionPacks: ir.extensionPacks,
|
package/dist/emission.mjs.map
CHANGED
|
@@ -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","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 isRequiredCollections = isArrayEqual(currentPath, ['storage', 'collections']);\n const isCollectionEntry =\n currentPath.length === 3 &&\n isArrayEqual([currentPath[0], currentPath[1]], ['storage', 'collections']);\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 !isRequiredCollections &&\n !isCollectionEntry &&\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":";;;;;;;;AAsCA,MAAM,kBAAkB;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,SAAS,eAAe,OAAyB;AAC/C,KAAI,UAAU,MAAO,QAAO;AAC5B,KAAI,UAAU,KAAM,QAAO;AAC3B,KAAI,iBAAiB,KAAM,QAAO;AAClC,KAAI,MAAM,QAAQ,MAAM,IAAI,MAAM,WAAW,EAAG,QAAO;AACvD,KAAI,OAAO,UAAU,YAAY,UAAU,KAEzC,QADa,OAAO,KAAK,MAAM,CACnB,WAAW;AAEzB,QAAO;;AAGT,SAAS,aAAa,KAAc,MAAkC;AACpE,KAAI,QAAQ,QAAQ,OAAO,QAAQ,SACjC,QAAO;AAGT,KAAI,eAAe,KACjB,QAAO;AAGT,KAAI,MAAM,QAAQ,IAAI,CACpB,QAAO,IAAI,KAAK,SAAS,aAAa,MAAM,KAAK,CAAC;CAGpD,MAAMA,SAAkC,EAAE;AAE1C,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,EAAE;EAC9C,MAAM,cAAc,CAAC,GAAG,MAAM,IAAI;AAGlC,MAAI,QAAQ,aACV;AAGF,MAAI,QAAQ,cAAc,UAAU,MAClC;AAGF,MAAI,QAAQ,eAAe,UAAU,MACnC;AAMF,OAAK,QAAQ,cAAc,QAAQ,eAAe,UAAU,WAC1D;AAGF,MAAI,eAAe,MAAM,EAAE;GACzB,MAAM,mBAAmB,aAAa,aAAa,CAAC,SAAS,CAAC;GAC9D,MAAM,mBAAmB,aAAa,aAAa,CAAC,WAAW,SAAS,CAAC;GACzE,MAAM,wBAAwB,aAAa,aAAa,CAAC,WAAW,cAAc,CAAC;GACnF,MAAM,oBACJ,YAAY,WAAW,KACvB,aAAa,CAAC,YAAY,IAAI,YAAY,GAAG,EAAE,CAAC,WAAW,cAAc,CAAC;GAC5E,MAAM,sBAAsB,aAAa,aAAa,CAAC,YAAY,CAAC;GACpE,MAAM,kBAAkB,aAAa,aAAa,CAAC,QAAQ,CAAC;GAC5D,MAAM,2BAA2B,aAAa,aAAa,CAAC,iBAAiB,CAAC;GAC9E,MAAM,yBAAyB,aAAa,aAAa,CAAC,eAAe,CAAC;GAC1E,MAAM,iBAAiB,aAAa,aAAa,CAAC,OAAO,CAAC;GAC1D,MAAM,8BAA8B,aAAa,aAAa;IAC5D;IACA;IACA;IACD,CAAC;GACF,MAAM,uBAAuB,YAAY,WAAW,KAAK,YAAY,OAAO;GAC5E,MAAM,mBACJ,YAAY,WAAW,KACvB,aAAa,CAAC,YAAY,IAAI,YAAY,GAAG,EAAE,CAAC,UAAU,YAAY,CAAC;GACzE,MAAM,iBACJ,YAAY,WAAW,KACvB,aACE;IAAC,YAAY;IAAI,YAAY;IAAI,YAAY;IAAG,EAChD;IAAC;IAAW;IAAU;IAAU,CACjC;GACH,MAAM,iBACJ,YAAY,WAAW,KACvB,aACE;IAAC,YAAY;IAAI,YAAY;IAAI,YAAY;IAAG,EAChD;IAAC;IAAW;IAAU;IAAU,CACjC;GACH,MAAM,qBACJ,YAAY,WAAW,KACvB,aACE;IAAC,YAAY;IAAI,YAAY;IAAI,YAAY;IAAG,EAChD;IAAC;IAAW;IAAU;IAAc,CACrC;GAKH,MAAM,mBACJ,YAAY,WAAW,KACvB,YAAY,OAAO,aACnB,YAAY,OAAO,YACnB,YAAY,OAAO,kBAClB,QAAQ,gBAAgB,QAAQ;AAEnC,OACE,CAAC,oBACD,CAAC,oBACD,CAAC,yBACD,CAAC,qBACD,CAAC,uBACD,CAAC,mBACD,CAAC,4BACD,CAAC,0BACD,CAAC,kBACD,CAAC,+BACD,CAAC,wBACD,CAAC,oBACD,CAAC,kBACD,CAAC,kBACD,CAAC,sBACD,CAAC,iBAED;;AAIJ,SAAO,OAAO,aAAa,OAAO,YAAY;;AAGhD,QAAO;;AAGT,SAAS,eAAe,KAAuB;AAC7C,KAAI,QAAQ,QAAQ,OAAO,QAAQ,SACjC,QAAO;AAGT,KAAI,eAAe,KACjB,QAAO;AAGT,KAAI,MAAM,QAAQ,IAAI,CACpB,QAAO,IAAI,KAAK,SAAS,eAAe,KAAK,CAAC;CAGhD,MAAMC,SAAkC,EAAE;CAC1C,MAAM,OAAO,OAAO,KAAK,IAAI,CAAC,MAAM;AACpC,MAAK,MAAM,OAAO,KAChB,QAAO,OAAO,eAAgB,IAAgC,KAAK;AAGrE,QAAO;;AAcT,SAAS,sBAAsB,SAA2B;AACxD,KAAI,CAAC,WAAW,OAAO,YAAY,SACjC,QAAO;CAGT,MAAM,aAAa;AACnB,KAAI,CAAC,WAAW,UAAU,OAAO,WAAW,WAAW,SACrD,QAAO;CAGT,MAAM,SAAS,WAAW;CAC1B,MAAMC,SAAwB,EAAE,GAAG,YAAY;AAE/C,QAAO,SAAS,EAAE;CAElB,MAAM,mBAAmB,OAAO,KAAK,OAAO,CAAC,MAAM;AACnD,MAAK,MAAM,aAAa,kBAAkB;EACxC,MAAM,QAAQ,OAAO;AACrB,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,UAAO,OAAO,aAAa;AAC3B;;EAGF,MAAM,WAAW;EACjB,MAAMC,cAA2B,EAAE,GAAG,UAAU;AAEhD,MAAI,MAAM,QAAQ,SAAS,QAAQ,CACjC,aAAY,UAAU,CAAC,GAAG,SAAS,QAAQ,CAAC,MAAM,GAAG,MAAM;GACzD,MAAM,QAAS,GAAyB,QAAQ;GAChD,MAAM,QAAS,GAAyB,QAAQ;AAChD,UAAO,MAAM,cAAc,MAAM;IACjC;AAGJ,MAAI,MAAM,QAAQ,SAAS,QAAQ,CACjC,aAAY,UAAU,CAAC,GAAG,SAAS,QAAQ,CAAC,MAAM,GAAG,MAAM;GACzD,MAAM,QAAS,GAAyB,QAAQ;GAChD,MAAM,QAAS,GAAyB,QAAQ;AAChD,UAAO,MAAM,cAAc,MAAM;IACjC;AAGJ,SAAO,OAAO,aAAa;;AAG7B,QAAO;;AAGT,SAAS,cAAc,KAAuD;CAC5E,MAAMC,UAAmC,EAAE;CAC3C,MAAM,YAAY,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC;AAE3C,MAAK,MAAM,OAAO,gBAChB,KAAI,UAAU,IAAI,IAAI,EAAE;AACtB,UAAQ,OAAO,IAAI;AACnB,YAAU,OAAO,IAAI;;AAIzB,MAAK,MAAM,OAAO,MAAM,KAAK,UAAU,CAAC,MAAM,CAC5C,SAAQ,OAAO,IAAI;AAGrB,QAAO;;AAGT,SAAgB,qBAAqB,IAAoC;CACvE,MAAMC,aAAiC;EACrC,eAAe,GAAG;EAClB,cAAc,GAAG;EACjB,QAAQ,GAAG;EACX,GAAG,UAAU,SAAS,GAAG,MAAM;EAC/B,QAAQ,GAAG;EACX,GAAG,UAAU,aAAa,GAAG,UAAU;EACvC,SAAS,GAAG;EACZ,GAAG,UAAU,aAAa,GAAG,UAAU;EACvC,gBAAgB,GAAG;EACnB,cAAc,GAAG;EACjB,MAAM,GAAG;EACV;AACD,QAAO,OACL,YACA,UAAU,eAAe,GAAG,YAAY,EACxC,UAAU,iBAAiB,GAAG,cAAc,EAC5C,UAAU,eAAe,GAAG,YAAY,CACzC;CAED,MAAM,sBAAsB,aAAa,YAAY,EAAE,CAAC;CACxD,MAAM,oBAAoB,sBAAsB,oBAAoB,QAAQ;CAG5E,MAAM,sBAAsB,cADL,eADG;EAAE,GAAG;EAAqB,SAAS;EAAmB,CACxB,CACC;AAEzD,QAAO,KAAK,UAAU,qBAAqB,oBAAoB,EAAE;;;;;ACjTnE,SAAS,YAAY,SAAyB;CAC5C,MAAM,OAAO,WAAW,SAAS;AACjC,MAAK,OAAO,QAAQ;AACpB,QAAO,UAAU,KAAK,OAAO,MAAM;;AAGrC,SAAgB,mBAAmB,UAA0C;AAa3E,QAAO,YADW,qBAXM;EACtB,eAAe,SAAS;EACxB,cAAc,SAAS;EACvB,QAAQ,SAAS;EACjB,SAAS,SAAS;EAClB,QAAQ,EAAE;EACV,WAAW,EAAE;EACb,gBAAgB,EAAE;EAClB,cAAc,EAAE;EAChB,MAAM,EAAE;EACT,CACsD,CAC1B;;AAG/B,SAAgB,mBAAmB,UAA0C;AAa3E,QAAO,YADW,qBAXM;EACtB,eAAe,SAAS;EACxB,cAAc,SAAS;EACvB,QAAQ,SAAS;EACjB,QAAQ,EAAE;EACV,WAAW,EAAE;EACb,SAAS,EAAE;EACX,gBAAgB,EAAE;EAClB,cAAc,SAAS;EACvB,MAAM,EAAE;EACT,CACsD,CAC1B;;AAG/B,SAAgB,qBAAqB,UAA0C;AAc7E,QAAO,YADW,qBAZQ;EACxB,eAAe,SAAS;EACxB,cAAc,SAAS;EACvB,QAAQ,SAAS;EACjB,QAAQ,EAAE;EACV,WAAW,EAAE;EACb,SAAS,EAAE;EACX,gBAAgB,EAAE;EAClB,cAAc,EAAE;EAChB,MAAM,EAAE;EACR,GAAG,UAAU,aAAa,SAAS,UAAU;EAC9C,CACwD,CAC5B;;;;;AChD/B,SAAS,2BACP,WACqD;AACrD,KAAI,CAAC,UAAW,QAAO;CACvB,MAAMC,SAAkD,EAAE;AAC1D,MAAK,MAAM,CAAC,SAAS,QAAQ,OAAO,QAAQ,UAAU,EAAE;EACtD,MAAM,EAAE,UAAU,GAAG,GAAG,SAAS;AACjC,SAAO,WAAW;;AAEpB,QAAO;;AAGT,SAAS,cAAc,QAA0D;CAC/E,MAAMC,SAAkC,EAAE;AAC1C,MAAK,MAAM,CAAC,WAAW,iBAAiB,OAAO,QAAQ,OAAO,EAAE;EAC9D,MAAM,QAAQ;EACd,MAAM,YAAY,MAAM;EACxB,MAAM,mBAAmB,2BAA2B,UAAU;EAE9D,MAAM,SAAS,MAAM;AACrB,MAAI,CAAC,QAAQ;AACX,UAAO,aAAa;IAClB,GAAG;IACH,GAAI,qBAAqB,SAAY,EAAE,WAAW,kBAAkB,GAAG,EAAE;IAC1E;AACD;;AAIF,MAAI,CADsB,OAAO,OAAO,OAAO,CAAC,MAAM,MAAM,EAAE,eAAe,OAAU,EAC/D;AACtB,UAAO,aAAa;IAClB,GAAG;IACH,GAAI,qBAAqB,SAAY,EAAE,WAAW,kBAAkB,GAAG,EAAE;IAC1E;AACD;;EAGF,MAAM,UAAW,MAAM,cAAc,EAAE;EAKvC,MAAMC,sBAA+D,EACnE,GAL6B,QAAQ,aAAa,EAAE,EAMrD;EAED,MAAMC,gBAAyD,EAAE;AACjE,OAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,OAAO,EAAE;GACvD,MAAM,EAAE,QAAQ,GAAG,eAAe;AAClC,OAAI,WAAW,gBAAgB,OAC7B,YAAW,cAAc;AAE3B,iBAAc,aAAa;AAE3B,OAAI,WAAW,UAAa,CAAC,oBAAoB,WAC/C,qBAAoB,aAAa,EAAE,QAAQ;;AAI/C,SAAO,aAAa;GAClB,GAAG;GACH,QAAQ;GACR,GAAI,qBAAqB,SAAY,EAAE,WAAW,kBAAkB,GAAG,EAAE;GACzE,SAAS;IAAE,GAAG;IAAS,QAAQ;IAAqB;GACrD;;AAEH,QAAO;;AAGT,MAAM,sBAAsB,KAAK,EAC/B,YAAY,WACb,CAAC;AAEF,MAAM,0BAA0B,KAAK;CACnC,KAAK;CACL,eAAe;CACf,cAAc;CACd,QAAQ;CACR,QAAQ,KAAK,EAAE,YAAY,WAAW,CAAC;CACvC,cAAc,KAAK,EAAE,YAAY,WAAW,CAAC;CAC7C,UAAU;CACV,SAAS,KAAK,EAAE,YAAY,WAAW,CAAC;CACxC,cAAc,KAAK,EAAE,YAAY,WAAW,CAAC;CAC7C,gBAAgB,KAAK,EAAE,YAAY,WAAW,CAAC;CAC/C,cAAc,KAAK,EACjB,YAAY,KAAK,EACf,YAAY,WACb,CAAC,EACH,CAAC;CACF,MAAM;CACP,CAAC;AAEF,SAAS,6BAA6B,OAAsB;CAC1D,MAAM,SAAS,wBAAwB,MAAM;AAC7C,KAAI,kBAAkB,KAAK,QAAQ;EACjC,MAAM,SAAS,OACZ,KAAK,UAAU;AAEd,UAAO,GADM,MAAM,MAAM,UAAU,IAAI,SACxB,IAAI,MAAM;IACzB,CACD,KAAK,KAAK;AACb,QAAM,IAAI,MAAM,oDAAoD,SAAS;;;AAIjF,SAAS,sBAAsB,IAAsB;AACnD,KAAI,CAAC,GAAG,aACN,OAAM,IAAI,MAAM,oCAAoC;AAEtD,KAAI,CAAC,GAAG,OACN,OAAM,IAAI,MAAM,8BAA8B;AAEhD,KAAI,CAAC,GAAG,cACN,OAAM,IAAI,MAAM,qCAAqC;AAEvD,KAAI,CAAC,GAAG,UAAU,OAAO,GAAG,WAAW,SACrC,OAAM,IAAI,MAAM,8BAA8B;AAEhD,KAAI,CAAC,GAAG,WAAW,OAAO,GAAG,YAAY,SACvC,OAAM,IAAI,MAAM,+BAA+B;AAEjD,KAAI,GAAG,cAAc,UAAa,OAAO,GAAG,cAAc,SACxD,OAAM,IAAI,MAAM,uDAAuD;AAEzE,KAAI,CAAC,GAAG,kBAAkB,OAAO,GAAG,mBAAmB,SACrD,OAAM,IAAI,MAAM,sCAAsC;AAExD,KAAI,CAAC,GAAG,gBAAgB,OAAO,GAAG,iBAAiB,SACjD,OAAM,IAAI,MAAM,oCAAoC;AAEtD,KAAI,CAAC,GAAG,QAAQ,OAAO,GAAG,SAAS,SACjC,OAAM,IAAI,MAAM,4BAA4B;;AAIhD,eAAsB,KACpB,IACA,SACA,cACqB;CACrB,MAAM,EACJ,mBACA,kBACA,sBACA,cACA,wBACA,0BACA,8BACE;AAEJ,uBAAsB,GAAG;CAEzB,MAAMC,MAAyB;EAC7B,GAAG,UAAU,qBAAqB,kBAAkB;EACpD,GAAG,UAAU,oBAAoB,iBAAiB;EAClD,GAAG,UAAU,wBAAwB,qBAAqB;EAC1D,GAAG,UAAU,gBAAgB,aAAa;EAC3C;AACD,cAAa,cAAc,IAAI,IAAI;AAEnC,cAAa,kBAAkB,GAAG;CAElC,MAAM,oBAAoB;EACxB,eAAe,GAAG;EAClB,cAAc,GAAG;EACjB,QAAQ,GAAG;EACX,GAAG,UAAU,SAAS,GAAG,MAAM;EAC/B,QAAQ,cAAc,GAAG,OAAkC;EAC3D,GAAG,UAAU,aAAa,GAAG,UAAU;EACvC,SAAS,GAAG;EACZ,GAAG,UAAU,aAAa,GAAG,UAAU;EACvC,gBAAgB,GAAG;EACnB,cAAc,GAAG;EACjB,MAAM,GAAG;EACV;AACD,8BAA6B,kBAAkB;CAE/C,MAAM,cAAc,mBAAmB,kBAAkB;CACzD,MAAM,gBAAgB,kBAAkB,YACpC,qBAAqB,kBAAkB,GACvC;CACJ,MAAM,cAAc,mBAAmB,kBAAkB;CAEzD,MAAM,qBAAqB;EACzB,GAAG;EACH;EACA,GAAG,UAAU,iBAAiB,cAAc;EAC5C;EACD;CASD,MAAM,uBAAuB;EAC3B,GALsB,KAAK,MAAM,qBAAqB,mBAAmB,CAAC;EAM1E,YAAY;GACV,SAAS;GACT,SAAS;GACT,YAAY;GACb;EACF;CACD,MAAM,qBAAqB,KAAK,UAAU,sBAAsB,MAAM,EAAE;CAExE,MAAM,kBACJ,0BAA0B,4BAA4B,4BAClD;EACE,GAAG,UAAU,0BAA0B,uBAAuB;EAC9D,GAAG,UAAU,4BAA4B,yBAAyB;EAClE,GAAG,UAAU,6BAA6B,0BAA0B;EACrE,GACD;CAEN,MAAM,qBAAqB;EACzB;EACA,GAAG,UAAU,iBAAiB,cAAc;EAC5C;EACD;AAeD,QAAO;EACL,cAAc;EACd,aATkB,MAAM,OAPH,aAAa,sBAClC,IACA,oBAAoB,EAAE,EACtB,wBAAwB,EAAE,EAC1B,oBACA,gBACD,EACgD;GAC/C,QAAQ;GACR,aAAa;GACb,MAAM;GACN,YAAY;GACb,CAAC;EAKA;EACA,GAAG,UAAU,iBAAiB,cAAc;EAC5C;EACD"}
|
|
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>","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 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 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 '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 isRequiredCollections = isArrayEqual(currentPath, ['storage', 'collections']);\n const isCollectionEntry =\n currentPath.length === 3 &&\n isArrayEqual([currentPath[0], currentPath[1]], ['storage', 'collections']);\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 !isRequiredCollections &&\n !isCollectionEntry &&\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 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 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 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 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 stripRelationStrategies(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 result[modelName] = {\n ...model,\n ...(cleanedRelations !== undefined ? { relations: cleanedRelations } : {}),\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 '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.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: stripRelationStrategies(ir.models as Record<string, unknown>),\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.
|
|
3
|
+
"version": "0.3.0-dev.132",
|
|
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/
|
|
11
|
-
"@prisma-next/
|
|
12
|
-
"@prisma-next/
|
|
10
|
+
"@prisma-next/operations": "0.3.0-dev.132",
|
|
11
|
+
"@prisma-next/utils": "0.3.0-dev.132",
|
|
12
|
+
"@prisma-next/contract": "0.3.0-dev.132"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"tsdown": "0.18.4",
|
|
@@ -11,7 +11,6 @@ type NormalizedContract = {
|
|
|
11
11
|
profileHash?: string;
|
|
12
12
|
roots?: Record<string, string>;
|
|
13
13
|
models: Record<string, unknown>;
|
|
14
|
-
relations?: Record<string, unknown>;
|
|
15
14
|
storage: Record<string, unknown>;
|
|
16
15
|
execution?: Record<string, unknown>;
|
|
17
16
|
extensionPacks: Record<string, unknown>;
|
|
@@ -25,7 +24,6 @@ export type CanonicalContractInput = {
|
|
|
25
24
|
target: string;
|
|
26
25
|
roots?: Record<string, string>;
|
|
27
26
|
models: Record<string, unknown>;
|
|
28
|
-
relations?: Record<string, unknown>;
|
|
29
27
|
storage: Record<string, unknown>;
|
|
30
28
|
execution?: Record<string, unknown>;
|
|
31
29
|
extensionPacks: Record<string, unknown>;
|
|
@@ -46,7 +44,6 @@ const TOP_LEVEL_ORDER = [
|
|
|
46
44
|
'profileHash',
|
|
47
45
|
'roots',
|
|
48
46
|
'models',
|
|
49
|
-
'relations',
|
|
50
47
|
'storage',
|
|
51
48
|
'execution',
|
|
52
49
|
'capabilities',
|
|
@@ -111,7 +108,6 @@ function omitDefaults(obj: unknown, path: readonly string[]): unknown {
|
|
|
111
108
|
const isCollectionEntry =
|
|
112
109
|
currentPath.length === 3 &&
|
|
113
110
|
isArrayEqual([currentPath[0], currentPath[1]], ['storage', 'collections']);
|
|
114
|
-
const isRequiredRelations = isArrayEqual(currentPath, ['relations']);
|
|
115
111
|
const isRequiredRoots = isArrayEqual(currentPath, ['roots']);
|
|
116
112
|
const isRequiredExtensionPacks = isArrayEqual(currentPath, ['extensionPacks']);
|
|
117
113
|
const isRequiredCapabilities = isArrayEqual(currentPath, ['capabilities']);
|
|
@@ -159,7 +155,6 @@ function omitDefaults(obj: unknown, path: readonly string[]): unknown {
|
|
|
159
155
|
!isRequiredTables &&
|
|
160
156
|
!isRequiredCollections &&
|
|
161
157
|
!isCollectionEntry &&
|
|
162
|
-
!isRequiredRelations &&
|
|
163
158
|
!isRequiredRoots &&
|
|
164
159
|
!isRequiredExtensionPacks &&
|
|
165
160
|
!isRequiredCapabilities &&
|
|
@@ -288,7 +283,6 @@ export function canonicalizeContract(ir: CanonicalContractInput): string {
|
|
|
288
283
|
target: ir.target,
|
|
289
284
|
...ifDefined('roots', ir.roots),
|
|
290
285
|
models: ir.models,
|
|
291
|
-
...ifDefined('relations', ir.relations),
|
|
292
286
|
storage: ir.storage,
|
|
293
287
|
...ifDefined('execution', ir.execution),
|
|
294
288
|
extensionPacks: ir.extensionPacks,
|
package/src/emission/emit.ts
CHANGED
|
@@ -19,58 +19,16 @@ function stripStrategyFromRelations(
|
|
|
19
19
|
return result;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
function
|
|
22
|
+
function stripRelationStrategies(models: Record<string, unknown>): Record<string, unknown> {
|
|
23
23
|
const result: Record<string, unknown> = {};
|
|
24
24
|
for (const [modelName, modelUnknown] of Object.entries(models)) {
|
|
25
25
|
const model = modelUnknown as Record<string, unknown>;
|
|
26
26
|
const relations = model['relations'] as Record<string, Record<string, unknown>> | undefined;
|
|
27
27
|
const cleanedRelations = stripStrategyFromRelations(relations);
|
|
28
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
29
|
result[modelName] = {
|
|
70
30
|
...model,
|
|
71
|
-
fields: cleanedFields,
|
|
72
31
|
...(cleanedRelations !== undefined ? { relations: cleanedRelations } : {}),
|
|
73
|
-
storage: { ...storage, fields: mergedStorageFields },
|
|
74
32
|
};
|
|
75
33
|
}
|
|
76
34
|
return result;
|
|
@@ -86,7 +44,6 @@ const CanonicalContractSchema = type({
|
|
|
86
44
|
targetFamily: 'string',
|
|
87
45
|
target: 'string',
|
|
88
46
|
models: type({ '[string]': 'unknown' }),
|
|
89
|
-
'relations?': type({ '[string]': 'unknown' }),
|
|
90
47
|
'roots?': 'Record<string, string>',
|
|
91
48
|
storage: type({ '[string]': 'unknown' }),
|
|
92
49
|
'execution?': type({ '[string]': 'unknown' }),
|
|
@@ -128,9 +85,6 @@ function validateCoreStructure(ir: ContractIR): void {
|
|
|
128
85
|
if (!ir.storage || typeof ir.storage !== 'object') {
|
|
129
86
|
throw new Error('ContractIR must have storage');
|
|
130
87
|
}
|
|
131
|
-
if (ir.relations !== undefined && typeof ir.relations !== 'object') {
|
|
132
|
-
throw new Error('ContractIR relations must be an object when provided');
|
|
133
|
-
}
|
|
134
88
|
if (!ir.extensionPacks || typeof ir.extensionPacks !== 'object') {
|
|
135
89
|
throw new Error('ContractIR must have extensionPacks');
|
|
136
90
|
}
|
|
@@ -174,8 +128,7 @@ export async function emit(
|
|
|
174
128
|
targetFamily: ir.targetFamily,
|
|
175
129
|
target: ir.target,
|
|
176
130
|
...ifDefined('roots', ir.roots),
|
|
177
|
-
models:
|
|
178
|
-
...ifDefined('relations', ir.relations),
|
|
131
|
+
models: stripRelationStrategies(ir.models as Record<string, unknown>),
|
|
179
132
|
storage: ir.storage,
|
|
180
133
|
...ifDefined('execution', ir.execution),
|
|
181
134
|
extensionPacks: ir.extensionPacks,
|
package/src/emission/hashing.ts
CHANGED
|
@@ -16,7 +16,6 @@ export function computeStorageHash(contract: CanonicalContractInput): string {
|
|
|
16
16
|
target: contract.target,
|
|
17
17
|
storage: contract.storage,
|
|
18
18
|
models: {},
|
|
19
|
-
relations: {},
|
|
20
19
|
extensionPacks: {},
|
|
21
20
|
capabilities: {},
|
|
22
21
|
meta: {},
|
|
@@ -31,7 +30,6 @@ export function computeProfileHash(contract: CanonicalContractInput): string {
|
|
|
31
30
|
targetFamily: contract.targetFamily,
|
|
32
31
|
target: contract.target,
|
|
33
32
|
models: {},
|
|
34
|
-
relations: {},
|
|
35
33
|
storage: {},
|
|
36
34
|
extensionPacks: {},
|
|
37
35
|
capabilities: contract.capabilities,
|
|
@@ -47,7 +45,6 @@ export function computeExecutionHash(contract: CanonicalContractInput): string {
|
|
|
47
45
|
targetFamily: contract.targetFamily,
|
|
48
46
|
target: contract.target,
|
|
49
47
|
models: {},
|
|
50
|
-
relations: {},
|
|
51
48
|
storage: {},
|
|
52
49
|
extensionPacks: {},
|
|
53
50
|
capabilities: {},
|