@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.
- package/dist/emission.d.mts +2 -1
- package/dist/emission.d.mts.map +1 -1
- package/dist/emission.mjs +62 -6
- package/dist/emission.mjs.map +1 -1
- package/package.json +4 -4
- package/src/emission/canonicalization.ts +9 -3
- package/src/emission/emit.ts +76 -5
package/dist/emission.d.mts
CHANGED
|
@@ -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
|
|
12
|
+
relations?: Record<string, unknown>;
|
|
12
13
|
storage: Record<string, unknown>;
|
|
13
14
|
execution?: Record<string, unknown>;
|
|
14
15
|
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":";;;;;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
|
|
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 (
|
|
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
|
-
|
|
264
|
-
|
|
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,
|
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","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.
|
|
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/
|
|
11
|
-
"@prisma-next/
|
|
12
|
-
"@prisma-next/utils": "0.3.0-dev.
|
|
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
|
|
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
|
|
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
|
|
285
|
+
...ifDefined('relations', ir.relations),
|
|
280
286
|
storage: ir.storage,
|
|
281
287
|
...ifDefined('execution', ir.execution),
|
|
282
288
|
extensionPacks: ir.extensionPacks,
|
package/src/emission/emit.ts
CHANGED
|
@@ -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 (
|
|
62
|
-
throw new Error('ContractIR must
|
|
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
|
-
|
|
107
|
-
|
|
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,
|