@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.
Files changed (56) hide show
  1. package/dist/{canonicalization-C3dTO0j1.d.mts → canonicalization-DFE0HJkI.d.mts} +2 -2
  2. package/dist/canonicalization-DFE0HJkI.d.mts.map +1 -0
  3. package/dist/canonicalization-path-match-b2jFuEso.mjs +25 -0
  4. package/dist/canonicalization-path-match-b2jFuEso.mjs.map +1 -0
  5. package/dist/{contract-types-CZPm4Ooy.d.mts → contract-types-xgwKtd7y.d.mts} +13 -74
  6. package/dist/contract-types-xgwKtd7y.d.mts.map +1 -0
  7. package/dist/contract-validation-error-ClZaKqMW.mjs +20 -0
  8. package/dist/contract-validation-error-ClZaKqMW.mjs.map +1 -0
  9. package/dist/contract-validation-error-T5LH4DW-.d.mts +13 -0
  10. package/dist/contract-validation-error-T5LH4DW-.d.mts.map +1 -0
  11. package/dist/contract-validation-error.d.mts +2 -10
  12. package/dist/contract-validation-error.mjs +2 -2
  13. package/dist/domain-envelope-4hyFtJ4_.d.mts +110 -0
  14. package/dist/domain-envelope-4hyFtJ4_.d.mts.map +1 -0
  15. package/dist/hashing-utils.d.mts +1 -1
  16. package/dist/hashing-utils.mjs +1 -22
  17. package/dist/hashing-utils.mjs.map +1 -1
  18. package/dist/hashing.d.mts +2 -2
  19. package/dist/hashing.mjs +175 -1
  20. package/dist/hashing.mjs.map +1 -0
  21. package/dist/namespace-id-CVpkSFUK.mjs +9 -0
  22. package/dist/namespace-id-CVpkSFUK.mjs.map +1 -0
  23. package/dist/types.d.mts +4 -3
  24. package/dist/types.mjs +73 -7
  25. package/dist/types.mjs.map +1 -1
  26. package/dist/validate-domain.d.mts +2 -6
  27. package/dist/validate-domain.d.mts.map +1 -1
  28. package/dist/validate-domain.mjs +98 -61
  29. package/dist/validate-domain.mjs.map +1 -1
  30. package/package.json +4 -6
  31. package/src/canonicalization.ts +41 -25
  32. package/src/contract-types.ts +31 -6
  33. package/src/contract-validation-error.ts +7 -0
  34. package/src/domain-envelope.ts +87 -0
  35. package/src/domain-types.ts +8 -12
  36. package/src/exports/contract-validation-error.ts +1 -0
  37. package/src/exports/types.ts +18 -1
  38. package/src/hashing.ts +1 -1
  39. package/src/validate-domain.ts +154 -93
  40. package/dist/canonicalization-C3dTO0j1.d.mts.map +0 -1
  41. package/dist/contract-types-CZPm4Ooy.d.mts.map +0 -1
  42. package/dist/contract-validation-error-Dp2vHZt5.mjs +0 -14
  43. package/dist/contract-validation-error-Dp2vHZt5.mjs.map +0 -1
  44. package/dist/contract-validation-error.d.mts.map +0 -1
  45. package/dist/cross-reference-t0TDbBTP.d.mts +0 -18
  46. package/dist/cross-reference-t0TDbBTP.d.mts.map +0 -1
  47. package/dist/hashing-C25nwocN.mjs +0 -151
  48. package/dist/hashing-C25nwocN.mjs.map +0 -1
  49. package/dist/testing.d.mts +0 -36
  50. package/dist/testing.d.mts.map +0 -1
  51. package/dist/testing.mjs +0 -65
  52. package/dist/testing.mjs.map +0 -1
  53. package/dist/types-CVGwkRLa.mjs +0 -46
  54. package/dist/types-CVGwkRLa.mjs.map +0 -1
  55. package/src/exports/testing.ts +0 -1
  56. package/src/testing-factories.ts +0 -121
@@ -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
- readonly models: Record<string, DomainModelShape>;
16
- readonly valueObjects?: Record<string, { readonly fields: Record<string, unknown> }>;
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 modelNames = new Set(Object.keys(contract.models));
57
+ const modelIndex = indexDomainModels(contract);
22
58
 
23
- validateRoots(contract, modelNames, errors);
24
- validateVariantsAndBases(contract, modelNames, errors);
25
- validateRelationTargets(contract, modelNames, errors);
26
- validateDiscriminators(contract, errors);
27
- validateOwnership(contract, modelNames, errors);
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
- modelNames: Set<string>,
77
+ modelIndex: ModelIndex,
42
78
  errors: string[],
43
79
  ): void {
44
- const seenValues = new Set<string>();
80
+ const seenRootTargets = new Map<NamespaceId, Set<string>>();
45
81
  for (const [rootKey, crossRef] of Object.entries(contract.roots)) {
46
- const modelName = crossRef.model;
47
- const dedupeKey = `${crossRef.namespace}:${modelName}`;
48
- if (seenValues.has(dedupeKey)) {
49
- errors.push(`Duplicate root value: "${modelName}" is mapped by multiple root keys`);
82
+ let modelsInNamespace = seenRootTargets.get(crossRef.namespace);
83
+ if (modelsInNamespace === undefined) {
84
+ modelsInNamespace = new Set();
85
+ seenRootTargets.set(crossRef.namespace, modelsInNamespace);
50
86
  }
51
- seenValues.add(dedupeKey);
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 (!modelNames.has(modelName)) {
94
+ if (!lookupModel(modelIndex, crossRef)) {
54
95
  errors.push(
55
- `Root "${rootKey}" references model "${modelName}" which does not exist in models`,
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
- contract: DomainContractShape,
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
- if (!modelNames.has(variantName)) {
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 in models`,
110
+ `Model "${namespaceId}:${modelName}" lists variant "${variantName}" which does not exist at that namespace coordinate`,
74
111
  );
75
112
  continue;
76
113
  }
77
- const variantModel = models.get(variantName);
78
- if (!variantModel) continue;
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 "${variantModel.base?.model ?? '(none)'}" but expected "${modelName}"`,
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 baseModelName = model.base.model;
89
- if (!modelNames.has(baseModelName)) {
124
+ const baseEntry = lookupModel(modelIndex, model.base);
125
+ if (!baseEntry) {
90
126
  errors.push(
91
- `Model "${modelName}" has base "${baseModelName}" which does not exist in models`,
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
- const baseModel = models.get(baseModelName);
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 "${baseModelName}" which does not list it as a variant`,
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
- contract: DomainContractShape,
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
- const targetModelName = relation.to.model;
114
- if (!modelNames.has(targetModelName)) {
143
+ if (!lookupModel(modelIndex, relation.to)) {
115
144
  errors.push(
116
- `Relation "${relName}" on model "${modelName}" targets "${targetModelName}" which does not exist in models`,
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(contract: DomainContractShape, errors: string[]): void {
124
- for (const [modelName, model] of Object.entries(contract.models)) {
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
- modelNames: Set<string>,
182
+ modelIndex: ModelIndex,
154
183
  errors: string[],
155
184
  ): void {
156
- for (const [modelName, model] of Object.entries(contract.models)) {
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
- if (!modelNames.has(model.owner)) {
164
- errors.push(`Model "${modelName}" has owner "${model.owner}" which does not exist in models`);
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 voNames = new Set(Object.keys(contract.valueObjects ?? {}));
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(type: FieldTypeLike | undefined, location: string): void {
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
- forEachContractField(contract, (field, location) => {
222
- const f = field as FieldLike | undefined;
223
- checkType(f?.type, location);
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(contract: DomainContractShape, errors: string[]): void {
228
- forEachContractField(contract, (field, location) => {
229
- const f = field as FieldLike | undefined;
230
- if (f?.many && f?.dict) {
231
- errors.push(`${location} cannot have both "many" and "dict" modifiers`);
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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"}