@prisma-next/contract 0.11.0-dev.67 → 0.11.0-dev.69
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/{canonicalization-C3dTO0j1.d.mts → canonicalization-DFE0HJkI.d.mts} +2 -2
- package/dist/canonicalization-DFE0HJkI.d.mts.map +1 -0
- package/dist/canonicalization-path-match-b2jFuEso.mjs +25 -0
- package/dist/canonicalization-path-match-b2jFuEso.mjs.map +1 -0
- package/dist/{contract-types-CZPm4Ooy.d.mts → contract-types-xgwKtd7y.d.mts} +13 -74
- package/dist/contract-types-xgwKtd7y.d.mts.map +1 -0
- package/dist/contract-validation-error-ClZaKqMW.mjs +20 -0
- package/dist/contract-validation-error-ClZaKqMW.mjs.map +1 -0
- package/dist/contract-validation-error-T5LH4DW-.d.mts +13 -0
- package/dist/contract-validation-error-T5LH4DW-.d.mts.map +1 -0
- package/dist/contract-validation-error.d.mts +2 -10
- package/dist/contract-validation-error.mjs +2 -2
- package/dist/domain-envelope-4hyFtJ4_.d.mts +110 -0
- package/dist/domain-envelope-4hyFtJ4_.d.mts.map +1 -0
- package/dist/hashing-utils.d.mts +1 -1
- package/dist/hashing-utils.mjs +1 -22
- package/dist/hashing-utils.mjs.map +1 -1
- package/dist/hashing.d.mts +2 -2
- package/dist/hashing.mjs +175 -1
- package/dist/hashing.mjs.map +1 -0
- package/dist/namespace-id-CVpkSFUK.mjs +9 -0
- package/dist/namespace-id-CVpkSFUK.mjs.map +1 -0
- package/dist/types.d.mts +4 -3
- package/dist/types.mjs +73 -7
- package/dist/types.mjs.map +1 -1
- package/dist/validate-domain.d.mts +2 -6
- package/dist/validate-domain.d.mts.map +1 -1
- package/dist/validate-domain.mjs +98 -61
- package/dist/validate-domain.mjs.map +1 -1
- package/package.json +4 -6
- package/src/canonicalization.ts +41 -25
- package/src/contract-types.ts +31 -6
- package/src/contract-validation-error.ts +7 -0
- package/src/domain-envelope.ts +87 -0
- package/src/domain-types.ts +8 -12
- package/src/exports/contract-validation-error.ts +1 -0
- package/src/exports/types.ts +18 -1
- package/src/hashing.ts +1 -1
- package/src/validate-domain.ts +154 -93
- package/dist/canonicalization-C3dTO0j1.d.mts.map +0 -1
- package/dist/contract-types-CZPm4Ooy.d.mts.map +0 -1
- package/dist/contract-validation-error-Dp2vHZt5.mjs +0 -14
- package/dist/contract-validation-error-Dp2vHZt5.mjs.map +0 -1
- package/dist/contract-validation-error.d.mts.map +0 -1
- package/dist/cross-reference-t0TDbBTP.d.mts +0 -18
- package/dist/cross-reference-t0TDbBTP.d.mts.map +0 -1
- package/dist/hashing-C25nwocN.mjs +0 -151
- package/dist/hashing-C25nwocN.mjs.map +0 -1
- package/dist/testing.d.mts +0 -36
- package/dist/testing.d.mts.map +0 -1
- package/dist/testing.mjs +0 -65
- package/dist/testing.mjs.map +0 -1
- package/dist/types-CVGwkRLa.mjs +0 -46
- package/dist/types-CVGwkRLa.mjs.map +0 -1
- package/src/exports/testing.ts +0 -1
- package/src/testing-factories.ts +0 -121
package/src/validate-domain.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ContractValidationError } from './contract-validation-error';
|
|
2
2
|
import type { CrossReference } from './cross-reference';
|
|
3
|
+
import type { ContractWithDomain } from './domain-envelope';
|
|
4
|
+
import { asNamespaceId, type NamespaceId } from './namespace-id';
|
|
3
5
|
|
|
4
6
|
export interface DomainModelShape {
|
|
5
7
|
readonly fields: Record<string, unknown>;
|
|
@@ -10,23 +12,57 @@ export interface DomainModelShape {
|
|
|
10
12
|
readonly owner?: string;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
export interface DomainContractShape {
|
|
15
|
+
export interface DomainContractShape extends ContractWithDomain {
|
|
14
16
|
readonly roots: Record<string, CrossReference>;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface IndexedModel {
|
|
20
|
+
readonly namespaceId: NamespaceId;
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly model: DomainModelShape;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type ModelIndex = Map<NamespaceId, Map<string, IndexedModel>>;
|
|
26
|
+
|
|
27
|
+
function indexDomainModels(contract: DomainContractShape): ModelIndex {
|
|
28
|
+
const index: ModelIndex = new Map();
|
|
29
|
+
for (const [namespaceKey, namespace] of Object.entries(contract.domain.namespaces)) {
|
|
30
|
+
const namespaceId = asNamespaceId(namespaceKey);
|
|
31
|
+
let modelsInNamespace = index.get(namespaceId);
|
|
32
|
+
if (modelsInNamespace === undefined) {
|
|
33
|
+
modelsInNamespace = new Map();
|
|
34
|
+
index.set(namespaceId, modelsInNamespace);
|
|
35
|
+
}
|
|
36
|
+
for (const [name, model] of Object.entries(namespace.models)) {
|
|
37
|
+
modelsInNamespace.set(name, { namespaceId, name, model });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return index;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function lookupModel(index: ModelIndex, ref: CrossReference): IndexedModel | undefined {
|
|
44
|
+
return index.get(ref.namespace)?.get(ref.model);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function* iterateIndexedModels(index: ModelIndex): IterableIterator<IndexedModel> {
|
|
48
|
+
for (const modelsInNamespace of index.values()) {
|
|
49
|
+
for (const entry of modelsInNamespace.values()) {
|
|
50
|
+
yield entry;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
17
53
|
}
|
|
18
54
|
|
|
19
55
|
export function validateContractDomain(contract: DomainContractShape): void {
|
|
20
56
|
const errors: string[] = [];
|
|
21
|
-
const
|
|
57
|
+
const modelIndex = indexDomainModels(contract);
|
|
22
58
|
|
|
23
|
-
validateRoots(contract,
|
|
24
|
-
validateVariantsAndBases(
|
|
25
|
-
validateRelationTargets(
|
|
26
|
-
validateDiscriminators(
|
|
27
|
-
validateOwnership(contract,
|
|
59
|
+
validateRoots(contract, modelIndex, errors);
|
|
60
|
+
validateVariantsAndBases(modelIndex, errors);
|
|
61
|
+
validateRelationTargets(modelIndex, errors);
|
|
62
|
+
validateDiscriminators(modelIndex, errors);
|
|
63
|
+
validateOwnership(contract, modelIndex, errors);
|
|
28
64
|
validateValueObjectReferences(contract, errors);
|
|
29
|
-
validateFieldModifiers(contract, errors);
|
|
65
|
+
validateFieldModifiers(modelIndex, contract, errors);
|
|
30
66
|
|
|
31
67
|
if (errors.length > 0) {
|
|
32
68
|
throw new ContractValidationError(
|
|
@@ -38,111 +74,104 @@ export function validateContractDomain(contract: DomainContractShape): void {
|
|
|
38
74
|
|
|
39
75
|
function validateRoots(
|
|
40
76
|
contract: DomainContractShape,
|
|
41
|
-
|
|
77
|
+
modelIndex: ModelIndex,
|
|
42
78
|
errors: string[],
|
|
43
79
|
): void {
|
|
44
|
-
const
|
|
80
|
+
const seenRootTargets = new Map<NamespaceId, Set<string>>();
|
|
45
81
|
for (const [rootKey, crossRef] of Object.entries(contract.roots)) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
82
|
+
let modelsInNamespace = seenRootTargets.get(crossRef.namespace);
|
|
83
|
+
if (modelsInNamespace === undefined) {
|
|
84
|
+
modelsInNamespace = new Set();
|
|
85
|
+
seenRootTargets.set(crossRef.namespace, modelsInNamespace);
|
|
50
86
|
}
|
|
51
|
-
|
|
87
|
+
if (modelsInNamespace.has(crossRef.model)) {
|
|
88
|
+
errors.push(
|
|
89
|
+
`Duplicate root value: "${crossRef.namespace}:${crossRef.model}" is mapped by multiple root keys`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
modelsInNamespace.add(crossRef.model);
|
|
52
93
|
|
|
53
|
-
if (!
|
|
94
|
+
if (!lookupModel(modelIndex, crossRef)) {
|
|
54
95
|
errors.push(
|
|
55
|
-
`Root "${rootKey}" references model "${
|
|
96
|
+
`Root "${rootKey}" references model "${crossRef.namespace}:${crossRef.model}" which does not exist in domain.namespaces`,
|
|
56
97
|
);
|
|
57
98
|
}
|
|
58
99
|
}
|
|
59
100
|
}
|
|
60
101
|
|
|
61
|
-
function validateVariantsAndBases(
|
|
62
|
-
|
|
63
|
-
modelNames: Set<string>,
|
|
64
|
-
errors: string[],
|
|
65
|
-
): void {
|
|
66
|
-
const models = new Map(Object.entries(contract.models));
|
|
67
|
-
|
|
68
|
-
for (const [modelName, model] of models) {
|
|
102
|
+
function validateVariantsAndBases(modelIndex: ModelIndex, errors: string[]): void {
|
|
103
|
+
for (const { namespaceId, name: modelName, model } of iterateIndexedModels(modelIndex)) {
|
|
69
104
|
if (model.variants) {
|
|
70
105
|
for (const variantName of Object.keys(model.variants)) {
|
|
71
|
-
|
|
106
|
+
const variantRef: CrossReference = { namespace: namespaceId, model: variantName };
|
|
107
|
+
const variantEntry = lookupModel(modelIndex, variantRef);
|
|
108
|
+
if (!variantEntry) {
|
|
72
109
|
errors.push(
|
|
73
|
-
`Model "${modelName}" lists variant "${variantName}" which does not exist
|
|
110
|
+
`Model "${namespaceId}:${modelName}" lists variant "${variantName}" which does not exist at that namespace coordinate`,
|
|
74
111
|
);
|
|
75
112
|
continue;
|
|
76
113
|
}
|
|
77
|
-
const
|
|
78
|
-
if (
|
|
79
|
-
if (variantModel.base?.model !== modelName) {
|
|
114
|
+
const variantBase = variantEntry.model.base;
|
|
115
|
+
if (variantBase?.namespace !== namespaceId || variantBase?.model !== modelName) {
|
|
80
116
|
errors.push(
|
|
81
|
-
`Variant "${variantName}" has base "${
|
|
117
|
+
`Variant "${namespaceId}:${variantName}" has base "${variantBase?.namespace ?? '?'}:${variantBase?.model ?? '(none)'}" but expected "${namespaceId}:${modelName}"`,
|
|
82
118
|
);
|
|
83
119
|
}
|
|
84
120
|
}
|
|
85
121
|
}
|
|
86
122
|
|
|
87
123
|
if (model.base) {
|
|
88
|
-
const
|
|
89
|
-
if (!
|
|
124
|
+
const baseEntry = lookupModel(modelIndex, model.base);
|
|
125
|
+
if (!baseEntry) {
|
|
90
126
|
errors.push(
|
|
91
|
-
`Model "${modelName}" has base "${
|
|
127
|
+
`Model "${namespaceId}:${modelName}" has base "${model.base.namespace}:${model.base.model}" which does not exist in domain.namespaces`,
|
|
92
128
|
);
|
|
93
129
|
continue;
|
|
94
130
|
}
|
|
95
|
-
|
|
96
|
-
if (!baseModel) continue;
|
|
97
|
-
if (!baseModel.variants || !Object.hasOwn(baseModel.variants, modelName)) {
|
|
131
|
+
if (!baseEntry.model.variants || !Object.hasOwn(baseEntry.model.variants, modelName)) {
|
|
98
132
|
errors.push(
|
|
99
|
-
`Model "${modelName}" has base "${
|
|
133
|
+
`Model "${namespaceId}:${modelName}" has base "${model.base.namespace}:${model.base.model}" which does not list it as a variant`,
|
|
100
134
|
);
|
|
101
135
|
}
|
|
102
136
|
}
|
|
103
137
|
}
|
|
104
138
|
}
|
|
105
139
|
|
|
106
|
-
function validateRelationTargets(
|
|
107
|
-
|
|
108
|
-
modelNames: Set<string>,
|
|
109
|
-
errors: string[],
|
|
110
|
-
): void {
|
|
111
|
-
for (const [modelName, model] of Object.entries(contract.models)) {
|
|
140
|
+
function validateRelationTargets(modelIndex: ModelIndex, errors: string[]): void {
|
|
141
|
+
for (const { namespaceId, name: modelName, model } of iterateIndexedModels(modelIndex)) {
|
|
112
142
|
for (const [relName, relation] of Object.entries(model.relations ?? {})) {
|
|
113
|
-
|
|
114
|
-
if (!modelNames.has(targetModelName)) {
|
|
143
|
+
if (!lookupModel(modelIndex, relation.to)) {
|
|
115
144
|
errors.push(
|
|
116
|
-
`Relation "${relName}" on model "${modelName}" targets "${
|
|
145
|
+
`Relation "${relName}" on model "${namespaceId}:${modelName}" targets "${relation.to.namespace}:${relation.to.model}" which does not exist in domain.namespaces`,
|
|
117
146
|
);
|
|
118
147
|
}
|
|
119
148
|
}
|
|
120
149
|
}
|
|
121
150
|
}
|
|
122
151
|
|
|
123
|
-
function validateDiscriminators(
|
|
124
|
-
for (const
|
|
152
|
+
function validateDiscriminators(modelIndex: ModelIndex, errors: string[]): void {
|
|
153
|
+
for (const { namespaceId, name: modelName, model } of iterateIndexedModels(modelIndex)) {
|
|
125
154
|
if (model.discriminator) {
|
|
126
155
|
if (!model.variants || Object.keys(model.variants).length === 0) {
|
|
127
|
-
errors.push(`Model "${modelName}" has discriminator but no variants`);
|
|
156
|
+
errors.push(`Model "${namespaceId}:${modelName}" has discriminator but no variants`);
|
|
128
157
|
}
|
|
129
158
|
if (!Object.hasOwn(model.fields, model.discriminator.field)) {
|
|
130
159
|
errors.push(
|
|
131
|
-
`Discriminator field "${model.discriminator.field}" is not a field on model "${modelName}"`,
|
|
160
|
+
`Discriminator field "${model.discriminator.field}" is not a field on model "${namespaceId}:${modelName}"`,
|
|
132
161
|
);
|
|
133
162
|
}
|
|
134
163
|
}
|
|
135
164
|
|
|
136
165
|
if (model.variants && Object.keys(model.variants).length > 0 && !model.discriminator) {
|
|
137
|
-
errors.push(`Model "${modelName}" has variants but no discriminator`);
|
|
166
|
+
errors.push(`Model "${namespaceId}:${modelName}" has variants but no discriminator`);
|
|
138
167
|
}
|
|
139
168
|
|
|
140
169
|
if (model.base) {
|
|
141
170
|
if (model.discriminator) {
|
|
142
|
-
errors.push(`Model "${modelName}" has base and must not have discriminator`);
|
|
171
|
+
errors.push(`Model "${namespaceId}:${modelName}" has base and must not have discriminator`);
|
|
143
172
|
}
|
|
144
173
|
if (model.variants && Object.keys(model.variants).length > 0) {
|
|
145
|
-
errors.push(`Model "${modelName}" has base and must not have variants`);
|
|
174
|
+
errors.push(`Model "${namespaceId}:${modelName}" has base and must not have variants`);
|
|
146
175
|
}
|
|
147
176
|
}
|
|
148
177
|
}
|
|
@@ -150,24 +179,27 @@ function validateDiscriminators(contract: DomainContractShape, errors: string[])
|
|
|
150
179
|
|
|
151
180
|
function validateOwnership(
|
|
152
181
|
contract: DomainContractShape,
|
|
153
|
-
|
|
182
|
+
modelIndex: ModelIndex,
|
|
154
183
|
errors: string[],
|
|
155
184
|
): void {
|
|
156
|
-
for (const
|
|
185
|
+
for (const { namespaceId, name: modelName, model } of iterateIndexedModels(modelIndex)) {
|
|
157
186
|
if (!model.owner) continue;
|
|
158
187
|
|
|
159
188
|
if (model.owner === modelName) {
|
|
160
|
-
errors.push(`Model "${modelName}" cannot own itself`);
|
|
189
|
+
errors.push(`Model "${namespaceId}:${modelName}" cannot own itself`);
|
|
161
190
|
}
|
|
162
191
|
|
|
163
|
-
|
|
164
|
-
|
|
192
|
+
const ownerRef: CrossReference = { namespace: namespaceId, model: model.owner };
|
|
193
|
+
if (!lookupModel(modelIndex, ownerRef)) {
|
|
194
|
+
errors.push(
|
|
195
|
+
`Model "${namespaceId}:${modelName}" has owner "${namespaceId}:${model.owner}" which does not exist in domain.namespaces`,
|
|
196
|
+
);
|
|
165
197
|
}
|
|
166
198
|
|
|
167
199
|
for (const [rootKey, rootRef] of Object.entries(contract.roots)) {
|
|
168
|
-
if (rootRef.model === modelName) {
|
|
200
|
+
if (rootRef.namespace === namespaceId && rootRef.model === modelName) {
|
|
169
201
|
errors.push(
|
|
170
|
-
`Owned model "${modelName}" must not appear in roots (found as root "${rootKey}")`,
|
|
202
|
+
`Owned model "${namespaceId}:${modelName}" must not appear in roots (found as root "${rootKey}")`,
|
|
171
203
|
);
|
|
172
204
|
}
|
|
173
205
|
}
|
|
@@ -186,49 +218,78 @@ interface FieldLike {
|
|
|
186
218
|
readonly dict?: boolean;
|
|
187
219
|
}
|
|
188
220
|
|
|
189
|
-
function forEachContractField(
|
|
190
|
-
contract: DomainContractShape,
|
|
191
|
-
callback: (field: unknown, location: string) => void,
|
|
192
|
-
): void {
|
|
193
|
-
for (const [modelName, model] of Object.entries(contract.models)) {
|
|
194
|
-
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
195
|
-
callback(field, `Model "${modelName}" field "${fieldName}"`);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
for (const [voName, vo] of Object.entries(contract.valueObjects ?? {})) {
|
|
199
|
-
for (const [fieldName, field] of Object.entries(vo.fields)) {
|
|
200
|
-
callback(field, `Value object "${voName}" field "${fieldName}"`);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
221
|
function validateValueObjectReferences(contract: DomainContractShape, errors: string[]): void {
|
|
206
|
-
const
|
|
222
|
+
const voNamesByNamespace = new Map<NamespaceId, Set<string>>();
|
|
223
|
+
for (const [namespaceKey, namespace] of Object.entries(contract.domain.namespaces)) {
|
|
224
|
+
const namespaceId = asNamespaceId(namespaceKey);
|
|
225
|
+
voNamesByNamespace.set(namespaceId, new Set(Object.keys(namespace.valueObjects ?? {})));
|
|
226
|
+
}
|
|
207
227
|
|
|
208
|
-
function checkType(
|
|
228
|
+
function checkType(
|
|
229
|
+
type: FieldTypeLike | undefined,
|
|
230
|
+
location: string,
|
|
231
|
+
namespaceId: NamespaceId,
|
|
232
|
+
): void {
|
|
209
233
|
if (!type) return;
|
|
234
|
+
const voNames = voNamesByNamespace.get(namespaceId) ?? new Set<string>();
|
|
210
235
|
if (type.kind === 'valueObject' && type.name && !voNames.has(type.name)) {
|
|
211
236
|
errors.push(
|
|
212
|
-
`${location} references value object "${type.name}" which does not exist in valueObjects`,
|
|
237
|
+
`${location} references value object "${namespaceId}:${type.name}" which does not exist in that namespace's valueObjects`,
|
|
213
238
|
);
|
|
214
239
|
return;
|
|
215
240
|
}
|
|
216
241
|
if (type.kind === 'union') {
|
|
217
|
-
for (const member of type.members ?? []) checkType(member, location);
|
|
242
|
+
for (const member of type.members ?? []) checkType(member, location, namespaceId);
|
|
218
243
|
}
|
|
219
244
|
}
|
|
220
245
|
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
246
|
+
for (const [namespaceKey, namespace] of Object.entries(contract.domain.namespaces)) {
|
|
247
|
+
const namespaceId = asNamespaceId(namespaceKey);
|
|
248
|
+
for (const [modelName, model] of Object.entries(namespace.models)) {
|
|
249
|
+
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
250
|
+
const f = field as FieldLike | undefined;
|
|
251
|
+
checkType(f?.type, `Model "${namespaceId}:${modelName}" field "${fieldName}"`, namespaceId);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
for (const [voName, vo] of Object.entries(namespace.valueObjects ?? {})) {
|
|
255
|
+
for (const [fieldName, field] of Object.entries(vo.fields)) {
|
|
256
|
+
const f = field as FieldLike | undefined;
|
|
257
|
+
checkType(
|
|
258
|
+
f?.type,
|
|
259
|
+
`Value object "${namespaceId}:${voName}" field "${fieldName}"`,
|
|
260
|
+
namespaceId,
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
225
265
|
}
|
|
226
266
|
|
|
227
|
-
function validateFieldModifiers(
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
267
|
+
function validateFieldModifiers(
|
|
268
|
+
modelIndex: ModelIndex,
|
|
269
|
+
contract: DomainContractShape,
|
|
270
|
+
errors: string[],
|
|
271
|
+
): void {
|
|
272
|
+
for (const { namespaceId, name: modelName, model } of iterateIndexedModels(modelIndex)) {
|
|
273
|
+
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
274
|
+
const f = field as FieldLike | undefined;
|
|
275
|
+
if (f?.many && f?.dict) {
|
|
276
|
+
errors.push(
|
|
277
|
+
`Model "${namespaceId}:${modelName}" field "${fieldName}" cannot have both "many" and "dict" modifiers`,
|
|
278
|
+
);
|
|
279
|
+
}
|
|
232
280
|
}
|
|
233
|
-
}
|
|
281
|
+
}
|
|
282
|
+
for (const [namespaceKey, namespace] of Object.entries(contract.domain.namespaces)) {
|
|
283
|
+
const namespaceId = asNamespaceId(namespaceKey);
|
|
284
|
+
for (const [voName, vo] of Object.entries(namespace.valueObjects ?? {})) {
|
|
285
|
+
for (const [fieldName, field] of Object.entries(vo.fields)) {
|
|
286
|
+
const f = field as FieldLike | undefined;
|
|
287
|
+
if (f?.many && f?.dict) {
|
|
288
|
+
errors.push(
|
|
289
|
+
`Value object "${namespaceId}:${voName}" field "${fieldName}" cannot have both "many" and "dict" modifiers`,
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
234
295
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"canonicalization-C3dTO0j1.d.mts","names":[],"sources":["../src/canonicalization.ts"],"mappings":";;;;;;AAcA;;;;;;KAAY,iBAAA,IAAqB,QAAA,EAAU,QAAA,KAAa,UAAU;;AAAA;AAUlE;;;;AAA6D;AAS7D;KATY,sBAAA,IAA0B,IAAuB;;;AASlB;AA2J3C;;;;KA3JY,WAAA,IAAe,OAAgB;AAAA,UA2J1B,2BAAA;EAAA,SACN,aAAA;EAAA;;;;;;;;AA0ByB;AAQpC;EAlCW,SAWA,iBAAA,EAAmB,iBAAA;;;;;;;WAOnB,mBAAA,GAAsB,sBAAA;EAiB/B;;;;;AAEO;AA4BT;EA9BE,SATS,WAAA,GAAc,WAAA;AAAA;;;;;;iBAQT,4BAAA,CACd,QAAA,EAAU,QAAA,EACV,OAAA,EAAS,2BAAA,GACR,MAAA;AAAA,iBA4Ba,oBAAA,CACd,QAAA,EAAU,QAAA,EACV,OAAA,EAAS,2BAA2B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contract-types-CZPm4Ooy.d.mts","names":[],"sources":["../src/domain-types.ts","../src/types.ts","../src/contract-types.ts"],"mappings":"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"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
//#region src/contract-validation-error.ts
|
|
2
|
-
var ContractValidationError = class extends Error {
|
|
3
|
-
code = "CONTRACT.VALIDATION_FAILED";
|
|
4
|
-
phase;
|
|
5
|
-
constructor(message, phase) {
|
|
6
|
-
super(message);
|
|
7
|
-
this.name = "ContractValidationError";
|
|
8
|
-
this.phase = phase;
|
|
9
|
-
}
|
|
10
|
-
};
|
|
11
|
-
//#endregion
|
|
12
|
-
export { ContractValidationError as t };
|
|
13
|
-
|
|
14
|
-
//# sourceMappingURL=contract-validation-error-Dp2vHZt5.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contract-validation-error-Dp2vHZt5.mjs","names":[],"sources":["../src/contract-validation-error.ts"],"sourcesContent":["export type ContractValidationPhase = 'structural' | 'domain' | 'storage';\n\nexport class ContractValidationError extends Error {\n readonly code = 'CONTRACT.VALIDATION_FAILED';\n readonly phase: ContractValidationPhase;\n\n constructor(message: string, phase: ContractValidationPhase) {\n super(message);\n this.name = 'ContractValidationError';\n this.phase = phase;\n }\n}\n"],"mappings":";AAEA,IAAa,0BAAb,cAA6C,MAAM;CACjD,OAAgB;CAChB;CAEA,YAAY,SAAiB,OAAgC;EAC3D,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,QAAQ;CACf;AACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contract-validation-error.d.mts","names":[],"sources":["../src/contract-validation-error.ts"],"mappings":";KAAY,uBAAA;AAAA,cAEC,uBAAA,SAAgC,KAAA;EAAA,SAClC,IAAA;EAAA,SACA,KAAA,EAAO,uBAAA;cAEJ,OAAA,UAAiB,KAAA,EAAO,uBAAA;AAAA"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import * as _$arktype_internal_variants_object_ts0 from "arktype/internal/variants/object.ts";
|
|
2
|
-
|
|
3
|
-
//#region src/namespace-id.d.ts
|
|
4
|
-
type NamespaceId = string & {
|
|
5
|
-
readonly __brand: 'NamespaceId';
|
|
6
|
-
};
|
|
7
|
-
declare function asNamespaceId(value: string): NamespaceId;
|
|
8
|
-
//#endregion
|
|
9
|
-
//#region src/cross-reference.d.ts
|
|
10
|
-
interface CrossReference {
|
|
11
|
-
readonly namespace: NamespaceId;
|
|
12
|
-
readonly model: string;
|
|
13
|
-
}
|
|
14
|
-
declare const CrossReferenceSchema: _$arktype_internal_variants_object_ts0.ObjectType<CrossReference, {}>;
|
|
15
|
-
declare function crossRef(model: string, namespace?: string): CrossReference;
|
|
16
|
-
//#endregion
|
|
17
|
-
export { asNamespaceId as a, NamespaceId as i, CrossReferenceSchema as n, crossRef as r, CrossReference as t };
|
|
18
|
-
//# sourceMappingURL=cross-reference-t0TDbBTP.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cross-reference-t0TDbBTP.d.mts","names":[],"sources":["../src/namespace-id.ts","../src/cross-reference.ts"],"mappings":";;;KAEY,WAAA;EAAA,SAAkC,OAAO;AAAA;AAAA,iBAErC,aAAA,CAAc,KAAA,WAAgB,WAAW;;;UCAxC,cAAA;EAAA,SACN,SAAA,EAAW,WAAW;EAAA,SACtB,KAAA;AAAA;AAAA,cAGE,oBAAA,EAAoB,sCAAA,CAAA,UAAA,CAAA,cAAA;AAAA,iBAajB,QAAA,CACd,KAAA,UACA,SAAA,YACC,cAAc"}
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { isArrayEqual } from "@prisma-next/utils/array-equal";
|
|
2
|
-
import { ifDefined } from "@prisma-next/utils/defined";
|
|
3
|
-
import { createHash } from "node:crypto";
|
|
4
|
-
//#region src/canonicalization.ts
|
|
5
|
-
const TOP_LEVEL_ORDER = [
|
|
6
|
-
"schemaVersion",
|
|
7
|
-
"canonicalVersion",
|
|
8
|
-
"targetFamily",
|
|
9
|
-
"target",
|
|
10
|
-
"profileHash",
|
|
11
|
-
"roots",
|
|
12
|
-
"models",
|
|
13
|
-
"valueObjects",
|
|
14
|
-
"domain",
|
|
15
|
-
"storage",
|
|
16
|
-
"execution",
|
|
17
|
-
"capabilities",
|
|
18
|
-
"extensionPacks",
|
|
19
|
-
"meta"
|
|
20
|
-
];
|
|
21
|
-
function isDefaultValue(value) {
|
|
22
|
-
if (value === false) return true;
|
|
23
|
-
if (value === null) return false;
|
|
24
|
-
if (Array.isArray(value) && value.length === 0) return true;
|
|
25
|
-
if (typeof value === "object" && value !== null) return Object.keys(value).length === 0;
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
function omitDefaults(obj, path, shouldPreserveEmpty) {
|
|
29
|
-
if (obj === null || typeof obj !== "object") return obj;
|
|
30
|
-
if (Array.isArray(obj)) return obj.map((item) => omitDefaults(item, path, shouldPreserveEmpty));
|
|
31
|
-
const result = {};
|
|
32
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
33
|
-
const currentPath = [...path, key];
|
|
34
|
-
if (key === "_generated") continue;
|
|
35
|
-
if (key === "generated" && value === false) continue;
|
|
36
|
-
if ((key === "onDelete" || key === "onUpdate") && value === "noAction") continue;
|
|
37
|
-
if (isDefaultValue(value)) {
|
|
38
|
-
const isRequiredModels = isArrayEqual(currentPath, ["models"]);
|
|
39
|
-
const isRequiredNamespaces = isArrayEqual(currentPath, ["storage", "namespaces"]);
|
|
40
|
-
const isNamespaceSlot = currentPath.length === 3 && isArrayEqual([currentPath[0], currentPath[1]], ["storage", "namespaces"]);
|
|
41
|
-
const isRequiredRoots = isArrayEqual(currentPath, ["roots"]);
|
|
42
|
-
const isRequiredExtensionPacks = isArrayEqual(currentPath, ["extensionPacks"]);
|
|
43
|
-
const isRequiredCapabilities = isArrayEqual(currentPath, ["capabilities"]);
|
|
44
|
-
const isRequiredMeta = isArrayEqual(currentPath, ["meta"]);
|
|
45
|
-
const isRequiredExecutionDefaults = isArrayEqual(currentPath, [
|
|
46
|
-
"execution",
|
|
47
|
-
"mutations",
|
|
48
|
-
"defaults"
|
|
49
|
-
]);
|
|
50
|
-
const isExtensionNamespace = currentPath.length === 2 && currentPath[0] === "extensionPacks";
|
|
51
|
-
const isModelRelations = currentPath.length === 3 && isArrayEqual([currentPath[0], currentPath[2]], ["models", "relations"]);
|
|
52
|
-
const isModelStorage = currentPath.length === 3 && isArrayEqual([currentPath[0], currentPath[2]], ["models", "storage"]);
|
|
53
|
-
const isDomainUnboundTypeParams = currentPath.length === 5 && currentPath[0] === "domain" && currentPath[2] === "types" && key === "typeParams";
|
|
54
|
-
const isNullableField = key === "nullable";
|
|
55
|
-
const isFamilyPreserved = shouldPreserveEmpty?.(currentPath) ?? false;
|
|
56
|
-
if (!isRequiredModels && !isRequiredNamespaces && !isNamespaceSlot && !isRequiredRoots && !isRequiredExtensionPacks && !isRequiredCapabilities && !isRequiredMeta && !isRequiredExecutionDefaults && !isExtensionNamespace && !isModelRelations && !isModelStorage && !isNullableField && !isDomainUnboundTypeParams && !isFamilyPreserved) continue;
|
|
57
|
-
}
|
|
58
|
-
result[key] = omitDefaults(value, currentPath, shouldPreserveEmpty);
|
|
59
|
-
}
|
|
60
|
-
return result;
|
|
61
|
-
}
|
|
62
|
-
function sortObjectKeys(obj) {
|
|
63
|
-
if (obj === null || typeof obj !== "object") return obj;
|
|
64
|
-
if (Array.isArray(obj)) return obj.map((item) => sortObjectKeys(item));
|
|
65
|
-
const sorted = {};
|
|
66
|
-
const keys = Object.keys(obj).sort();
|
|
67
|
-
for (const key of keys) sorted[key] = sortObjectKeys(obj[key]);
|
|
68
|
-
return sorted;
|
|
69
|
-
}
|
|
70
|
-
function orderTopLevel(obj) {
|
|
71
|
-
const ordered = {};
|
|
72
|
-
const remaining = new Set(Object.keys(obj));
|
|
73
|
-
for (const key of TOP_LEVEL_ORDER) if (remaining.has(key)) {
|
|
74
|
-
ordered[key] = obj[key];
|
|
75
|
-
remaining.delete(key);
|
|
76
|
-
}
|
|
77
|
-
for (const key of Array.from(remaining).sort()) ordered[key] = obj[key];
|
|
78
|
-
return ordered;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Object-form variant of {@link canonicalizeContract}. Exported because the
|
|
82
|
-
* emitter writes the canonical contract through a separate JSON-stringify
|
|
83
|
-
* pass and consumes the structured object directly.
|
|
84
|
-
*/
|
|
85
|
-
function canonicalizeContractToObject(contract, options) {
|
|
86
|
-
const serialized = options.serializeContract(contract);
|
|
87
|
-
const withDefaultsOmitted = omitDefaults({
|
|
88
|
-
...ifDefined("schemaVersion", options.schemaVersion),
|
|
89
|
-
targetFamily: serialized["targetFamily"],
|
|
90
|
-
target: serialized["target"],
|
|
91
|
-
profileHash: serialized["profileHash"],
|
|
92
|
-
roots: serialized["roots"],
|
|
93
|
-
models: serialized["models"],
|
|
94
|
-
...ifDefined("valueObjects", serialized["valueObjects"]),
|
|
95
|
-
...ifDefined("domain", serialized["domain"]),
|
|
96
|
-
storage: serialized["storage"],
|
|
97
|
-
...ifDefined("execution", serialized["execution"]),
|
|
98
|
-
extensionPacks: serialized["extensionPacks"],
|
|
99
|
-
capabilities: serialized["capabilities"],
|
|
100
|
-
meta: serialized["meta"]
|
|
101
|
-
}, [], options.shouldPreserveEmpty);
|
|
102
|
-
return orderTopLevel(sortObjectKeys(options.sortStorage ? {
|
|
103
|
-
...withDefaultsOmitted,
|
|
104
|
-
storage: options.sortStorage(withDefaultsOmitted["storage"])
|
|
105
|
-
} : withDefaultsOmitted));
|
|
106
|
-
}
|
|
107
|
-
function canonicalizeContract(contract, options) {
|
|
108
|
-
return JSON.stringify(canonicalizeContractToObject(contract, options), null, 2);
|
|
109
|
-
}
|
|
110
|
-
//#endregion
|
|
111
|
-
//#region src/hashing.ts
|
|
112
|
-
const SCHEMA_VERSION = "1";
|
|
113
|
-
function sha256(content) {
|
|
114
|
-
const hash = createHash("sha256");
|
|
115
|
-
hash.update(content);
|
|
116
|
-
return `sha256:${hash.digest("hex")}`;
|
|
117
|
-
}
|
|
118
|
-
function hashContract(section) {
|
|
119
|
-
const { shouldPreserveEmpty, sortStorage, ...sectionData } = section;
|
|
120
|
-
return canonicalizeContract({
|
|
121
|
-
targetFamily: sectionData["targetFamily"],
|
|
122
|
-
target: sectionData["target"],
|
|
123
|
-
roots: {},
|
|
124
|
-
models: {},
|
|
125
|
-
storage: sectionData["storage"] ?? {},
|
|
126
|
-
execution: sectionData["execution"],
|
|
127
|
-
extensionPacks: {},
|
|
128
|
-
capabilities: sectionData["capabilities"] ?? {},
|
|
129
|
-
meta: {},
|
|
130
|
-
profileHash: "",
|
|
131
|
-
...sectionData
|
|
132
|
-
}, {
|
|
133
|
-
schemaVersion: SCHEMA_VERSION,
|
|
134
|
-
serializeContract: (c) => JSON.parse(JSON.stringify(c)),
|
|
135
|
-
...ifDefined("shouldPreserveEmpty", shouldPreserveEmpty),
|
|
136
|
-
...ifDefined("sortStorage", sortStorage)
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
function computeStorageHash(args) {
|
|
140
|
-
return sha256(hashContract(args));
|
|
141
|
-
}
|
|
142
|
-
function computeExecutionHash(args) {
|
|
143
|
-
return sha256(hashContract(args));
|
|
144
|
-
}
|
|
145
|
-
function computeProfileHash(args) {
|
|
146
|
-
return sha256(hashContract(args));
|
|
147
|
-
}
|
|
148
|
-
//#endregion
|
|
149
|
-
export { canonicalizeContractToObject as a, canonicalizeContract as i, computeProfileHash as n, computeStorageHash as r, computeExecutionHash as t };
|
|
150
|
-
|
|
151
|
-
//# sourceMappingURL=hashing-C25nwocN.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hashing-C25nwocN.mjs","names":[],"sources":["../src/canonicalization.ts","../src/hashing.ts"],"sourcesContent":["import { isArrayEqual } from '@prisma-next/utils/array-equal';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { JsonObject } from '@prisma-next/utils/json';\n\nimport type { Contract } from './contract-types';\n\n/**\n * Per-target contract serializer hook. The framework canonicalizer uses\n * this to convert an in-memory contract (which may carry class-instance\n * IR nodes whose runtime-only fields must not appear in the on-disk\n * envelope) into a plain JsonObject before applying the family-agnostic\n * canonical-key ordering / default-omission / sort steps. Targets whose\n * contract is JSON-clean by construction return the contract unchanged.\n */\nexport type SerializeContract = (contract: Contract) => JsonObject;\n\n/**\n * Family-contributed predicate for the default-omission walk. Called when\n * a value at `path` is a default (empty object/array or `false`); if this\n * returns `true` the value is kept rather than stripped.\n *\n * The framework only calls the predicate inside the `isDefaultValue` branch,\n * so there is no need to guard against non-default values.\n */\nexport type PreserveEmptyPredicate = (path: readonly string[]) => boolean;\n\n/**\n * Family-contributed storage sort. Applied to the serialized `storage`\n * subtree after the default-omission walk; the result replaces the\n * `storage` field before the final key sort. Use to establish a\n * deterministic order for storage arrays (indexes, uniques) that the\n * family-agnostic `sortObjectKeys` pass cannot handle.\n */\nexport type StorageSort = (storage: unknown) => unknown;\n\nconst TOP_LEVEL_ORDER = [\n 'schemaVersion',\n 'canonicalVersion',\n 'targetFamily',\n 'target',\n 'profileHash',\n 'roots',\n 'models',\n 'valueObjects',\n 'domain',\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 (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(\n obj: unknown,\n path: readonly string[],\n shouldPreserveEmpty: PreserveEmptyPredicate | undefined,\n): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => omitDefaults(item, path, shouldPreserveEmpty));\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 if (key === '_generated') {\n continue;\n }\n\n if (key === 'generated' && value === false) {\n continue;\n }\n\n if ((key === 'onDelete' || key === 'onUpdate') && value === 'noAction') {\n continue;\n }\n\n if (isDefaultValue(value)) {\n const isRequiredModels = isArrayEqual(currentPath, ['models']);\n const isRequiredNamespaces = isArrayEqual(currentPath, ['storage', 'namespaces']);\n const isNamespaceSlot =\n currentPath.length === 3 &&\n isArrayEqual([currentPath[0], currentPath[1]], ['storage', 'namespaces']);\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 isModelStorage =\n currentPath.length === 3 &&\n isArrayEqual([currentPath[0], currentPath[2]], ['models', 'storage']);\n\n const isDomainUnboundTypeParams =\n currentPath.length === 5 &&\n currentPath[0] === 'domain' &&\n currentPath[2] === 'types' &&\n key === 'typeParams';\n\n const isNullableField = key === 'nullable';\n\n const isFamilyPreserved = shouldPreserveEmpty?.(currentPath) ?? false;\n\n if (\n !isRequiredModels &&\n !isRequiredNamespaces &&\n !isNamespaceSlot &&\n !isRequiredRoots &&\n !isRequiredExtensionPacks &&\n !isRequiredCapabilities &&\n !isRequiredMeta &&\n !isRequiredExecutionDefaults &&\n !isExtensionNamespace &&\n !isModelRelations &&\n !isModelStorage &&\n !isNullableField &&\n !isDomainUnboundTypeParams &&\n !isFamilyPreserved\n ) {\n continue;\n }\n }\n\n result[key] = omitDefaults(value, currentPath, shouldPreserveEmpty);\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 (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\nexport function 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 interface CanonicalizeContractOptions {\n readonly schemaVersion?: string;\n /**\n * Per-target hook that converts the in-memory contract (which may\n * carry class-instance IR nodes) into a plain JsonObject before the\n * family-agnostic canonicalization steps run.\n *\n * Routing through the hook is what lets each target decide which\n * fields appear in the on-disk envelope; runtime-only class API\n * fields stay invisible to the canonicalization walk by virtue of\n * the per-target serializer not putting them in the JSON shape.\n */\n readonly serializeContract: SerializeContract;\n /**\n * Family-contributed preserve-empty predicate. When the walk encounters a\n * default value (empty object/array or `false`) at `path`, calling this\n * with the full path allows the family to veto the omission. If absent,\n * only the framework's family-agnostic required-slot rules apply.\n */\n readonly shouldPreserveEmpty?: PreserveEmptyPredicate;\n /**\n * Family-contributed storage sort. Applied to the serialized `storage`\n * subtree after the default-omission walk, before the final key sort.\n * SQL family uses this to impose a deterministic order on `indexes` and\n * `uniques` arrays within each namespace table. Families that require no\n * special storage ordering omit this hook.\n */\n readonly sortStorage?: StorageSort;\n}\n\n/**\n * Object-form variant of {@link canonicalizeContract}. Exported because the\n * emitter writes the canonical contract through a separate JSON-stringify\n * pass and consumes the structured object directly.\n */\nexport function canonicalizeContractToObject(\n contract: Contract,\n options: CanonicalizeContractOptions,\n): Record<string, unknown> {\n const serialized = options.serializeContract(contract);\n const normalized: Record<string, unknown> = {\n ...ifDefined('schemaVersion', options.schemaVersion),\n targetFamily: serialized['targetFamily'],\n target: serialized['target'],\n profileHash: serialized['profileHash'],\n roots: serialized['roots'],\n models: serialized['models'],\n ...ifDefined('valueObjects', serialized['valueObjects']),\n ...ifDefined('domain', serialized['domain']),\n storage: serialized['storage'],\n ...ifDefined('execution', serialized['execution']),\n extensionPacks: serialized['extensionPacks'],\n capabilities: serialized['capabilities'],\n meta: serialized['meta'],\n };\n const withDefaultsOmitted = omitDefaults(normalized, [], options.shouldPreserveEmpty) as Record<\n string,\n unknown\n >;\n const withSortedStorage = options.sortStorage\n ? { ...withDefaultsOmitted, storage: options.sortStorage(withDefaultsOmitted['storage']) }\n : withDefaultsOmitted;\n const withSortedKeys = sortObjectKeys(withSortedStorage) as Record<string, unknown>;\n return orderTopLevel(withSortedKeys);\n}\n\nexport function canonicalizeContract(\n contract: Contract,\n options: CanonicalizeContractOptions,\n): string {\n return JSON.stringify(canonicalizeContractToObject(contract, options), null, 2);\n}\n","import { createHash } from 'node:crypto';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { JsonObject } from '@prisma-next/utils/json';\nimport {\n canonicalizeContract,\n type PreserveEmptyPredicate,\n type StorageSort,\n} from './canonicalization';\nimport type { Contract } from './contract-types';\nimport type { ExecutionHashBase, ProfileHashBase, StorageHashBase } from './types';\n\nconst SCHEMA_VERSION = '1';\n\nfunction sha256(content: string): string {\n const hash = createHash('sha256');\n hash.update(content);\n return `sha256:${hash.digest('hex')}`;\n}\n\ntype HashContractSection = Record<string, unknown> & {\n readonly shouldPreserveEmpty?: PreserveEmptyPredicate;\n readonly sortStorage?: StorageSort;\n};\n\nfunction hashContract(section: HashContractSection): string {\n const { shouldPreserveEmpty, sortStorage, ...sectionData } = section;\n // Blind cast: the synthesised object is a hash-only stand-in\n // — never returned to callers, never executed as a Contract.\n // `canonicalizeContract` only walks the storage / execution /\n // capabilities slices, all of which are populated above, so the\n // missing precise Contract typing on the other slots is\n // immaterial for the hash result.\n const contract = {\n targetFamily: sectionData['targetFamily'],\n target: sectionData['target'],\n roots: {},\n models: {},\n storage: sectionData['storage'] ?? {},\n execution: sectionData['execution'],\n extensionPacks: {},\n capabilities: sectionData['capabilities'] ?? {},\n meta: {},\n profileHash: '',\n ...sectionData,\n } as unknown as Contract;\n return canonicalizeContract(contract, {\n schemaVersion: SCHEMA_VERSION,\n serializeContract: (c) => JSON.parse(JSON.stringify(c)) as JsonObject,\n ...ifDefined('shouldPreserveEmpty', shouldPreserveEmpty),\n ...ifDefined('sortStorage', sortStorage),\n });\n}\n\nexport type ComputeStorageHashArgs = {\n target: string;\n targetFamily: string;\n storage: Record<string, unknown>;\n readonly shouldPreserveEmpty?: PreserveEmptyPredicate;\n readonly sortStorage?: StorageSort;\n};\n\nexport function computeStorageHash(args: ComputeStorageHashArgs): StorageHashBase<string> {\n return sha256(hashContract(args)) as StorageHashBase<string>;\n}\n\nexport function computeExecutionHash(args: {\n target: string;\n targetFamily: string;\n execution: Record<string, unknown>;\n}): ExecutionHashBase<string> {\n return sha256(hashContract(args)) as ExecutionHashBase<string>;\n}\n\nexport function computeProfileHash(args: {\n target: string;\n targetFamily: string;\n capabilities: Record<string, Record<string, boolean>>;\n}): ProfileHashBase<string> {\n return sha256(hashContract(args)) as ProfileHashBase<string>;\n}\n"],"mappings":"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"}
|