@prisma-next/sql-contract-ts 0.12.0 → 0.13.0-dev.2

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.
@@ -1,9 +1,9 @@
1
- import { t as buildSqlContractFromDefinition } from "./build-contract-BCYW3_wE.mjs";
1
+ import { t as buildSqlContractFromDefinition } from "./build-contract-C-x2pfu4.mjs";
2
2
  import { blindCast } from "@prisma-next/utils/casts";
3
+ import { ifDefined } from "@prisma-next/utils/defined";
3
4
  import { isColumnDefault } from "@prisma-next/contract/types";
4
5
  import { createEntityHelpersFromNamespace } from "@prisma-next/contract-authoring";
5
6
  import { isPostgresEnumStorageEntry, toStorageTypeInstance } from "@prisma-next/sql-contract/types";
6
- import { ifDefined } from "@prisma-next/utils/defined";
7
7
  import { assertNoCrossRegistryCollisions, instantiateAuthoringFieldPreset, instantiateAuthoringTypeConstructor, isAuthoringEntityTypeDescriptor, isAuthoringFieldPresetDescriptor, isAuthoringTypeConstructorDescriptor, mergeAuthoringNamespaces, validateAuthoringHelperArguments } from "@prisma-next/framework-components/authoring";
8
8
  //#region src/authoring-helper-runtime.ts
9
9
  function isNamedConstraintOptionsLike(value) {
@@ -79,6 +79,61 @@ function createFieldHelpersFromNamespace(namespace, createLeafHelper, path = [])
79
79
  return helpers;
80
80
  }
81
81
  //#endregion
82
+ //#region src/enum-type.ts
83
+ function member(name, value) {
84
+ return {
85
+ name,
86
+ value: blindCast(value ?? name)
87
+ };
88
+ }
89
+ /**
90
+ * Internal brand that identifies an EnumTypeHandle in the lowering pipeline.
91
+ * Not exported — callers only interact with `EnumTypeHandle`.
92
+ */
93
+ const ENUM_TYPE_HANDLE_BRAND = Symbol("EnumTypeHandle");
94
+ function enumType(name, codec, ...members) {
95
+ if (members.length === 0) throw new Error(`enumType("${name}"): must have at least one member.`);
96
+ const seenNames = /* @__PURE__ */ new Set();
97
+ const seenValues = /* @__PURE__ */ new Set();
98
+ for (const m of members) {
99
+ if (seenNames.has(m.name)) throw new Error(`enumType("${name}"): duplicate member name "${m.name}". Member names must be unique.`);
100
+ seenNames.add(m.name);
101
+ if (seenValues.has(m.value)) throw new Error(`enumType("${name}"): duplicate member value "${m.value}". Member values must be unique.`);
102
+ seenValues.add(m.value);
103
+ }
104
+ const values = Object.freeze(members.map((m) => m.value));
105
+ const names = Object.freeze(members.map((m) => m.name));
106
+ const enumMembers = Object.freeze(members.map((m) => ({
107
+ name: m.name,
108
+ value: m.value
109
+ })));
110
+ const membersAccessor = Object.freeze(Object.fromEntries(members.map((m) => [m.name, m.value])));
111
+ const valueSet = new Set(values);
112
+ const valueToName = new Map(members.map((m) => [m.value, m.name]));
113
+ const valueToOrdinal = new Map(values.map((v, i) => [v, i]));
114
+ return {
115
+ [ENUM_TYPE_HANDLE_BRAND]: true,
116
+ enumName: name,
117
+ codecId: codec.codecId,
118
+ nativeType: codec.nativeType,
119
+ enumMembers,
120
+ values,
121
+ names,
122
+ members: membersAccessor,
123
+ has: (v) => valueSet.has(v),
124
+ nameOf: (v) => valueToName.get(v),
125
+ ordinalOf: (v) => valueToOrdinal.get(v) ?? -1
126
+ };
127
+ }
128
+ /**
129
+ * Returns true when the value is an `EnumTypeHandle` produced by
130
+ * `enumType()`. Used in the lowering pipeline to detect enum handles
131
+ * in field state without importing the BRAND symbol at every call site.
132
+ */
133
+ function isEnumTypeHandle(value) {
134
+ return typeof value === "object" && value !== null && Reflect.get(value, ENUM_TYPE_HANDLE_BRAND) === true;
135
+ }
136
+ //#endregion
82
137
  //#region src/contract-dsl.ts
83
138
  function toColumnDefault(value) {
84
139
  if (isColumnDefault(value)) return value;
@@ -92,6 +147,15 @@ var ScalarFieldBuilder = class ScalarFieldBuilder {
92
147
  constructor(state) {
93
148
  this.state = state;
94
149
  }
150
+ /**
151
+ * Returns the physical column name when `.column(name)` was called, or
152
+ * `undefined` when the field uses the default (logical field name) mapping.
153
+ * Used by cross-space FK lowering to stamp the physical column name onto
154
+ * `TargetFieldRef.columnName` so FK target columns are resolved correctly.
155
+ */
156
+ get physicalColumnName() {
157
+ return this.state.columnName;
158
+ }
95
159
  optional() {
96
160
  return new ScalarFieldBuilder({
97
161
  ...this.state,
@@ -166,6 +230,11 @@ function generatedField(spec) {
166
230
  });
167
231
  }
168
232
  function namedTypeField(typeRef) {
233
+ if (isEnumTypeHandle(typeRef)) return new ScalarFieldBuilder({
234
+ kind: "scalar",
235
+ typeRef,
236
+ nullable: false
237
+ });
169
238
  return new ScalarFieldBuilder({
170
239
  kind: "scalar",
171
240
  typeRef,
@@ -208,10 +277,16 @@ function normalizeTargetFieldRefInput(input) {
208
277
  const [first] = refs;
209
278
  if (!first) throw new Error("Expected at least one target ref");
210
279
  if (refs.some((ref) => ref.modelName !== first.modelName)) throw new Error("All target refs in a foreign key must point to the same model");
280
+ if (refs.some((ref) => ref.spaceId !== first.spaceId)) throw new Error(`All target refs in a compound foreign key must share the same spaceId (found mismatch: "${first.spaceId ?? "<local>"}" vs "${refs.find((r) => r.spaceId !== first.spaceId)?.spaceId ?? "<local>"}")`);
281
+ if (refs.some((ref) => ref.namespaceId !== first.namespaceId)) throw new Error("All target refs in a compound foreign key must share the same namespaceId (found mismatch)");
282
+ if (refs.some((ref) => ref.tableName !== first.tableName)) throw new Error("All target refs in a compound foreign key must share the same tableName (found mismatch)");
211
283
  return {
212
284
  modelName: first.modelName,
213
- fieldNames: refs.map((ref) => ref.fieldName),
214
- source: refs.some((ref) => ref.source === "string") ? "string" : "token"
285
+ fieldNames: refs.map((ref) => ref.columnName ?? ref.fieldName),
286
+ source: refs.some((ref) => ref.source === "string") ? "string" : "token",
287
+ spaceId: first.spaceId,
288
+ namespaceId: first.namespaceId,
289
+ tableName: first.tableName
215
290
  };
216
291
  }
217
292
  function createConstraintsDsl() {
@@ -254,6 +329,9 @@ function createConstraintsDsl() {
254
329
  targetModel: normalizedTarget.modelName,
255
330
  targetFields: normalizedTarget.fieldNames,
256
331
  targetSource: normalizedTarget.source,
332
+ ...normalizedTarget.spaceId !== void 0 ? { targetSpaceId: normalizedTarget.spaceId } : {},
333
+ ...normalizedTarget.namespaceId !== void 0 ? { targetNamespaceId: normalizedTarget.namespaceId } : {},
334
+ ...normalizedTarget.tableName !== void 0 ? { targetTableName: normalizedTarget.tableName } : {},
257
335
  ...options?.name ? { name: options.name } : {},
258
336
  ...options?.onDelete ? { onDelete: options.onDelete } : {},
259
337
  ...options?.onUpdate ? { onUpdate: options.onUpdate } : {},
@@ -277,14 +355,23 @@ function createFieldRefs(fields) {
277
355
  };
278
356
  return refs;
279
357
  }
280
- function createModelTokenRefs(modelName, fields) {
358
+ function createModelTokenRefs(modelName, fields, crossSpaceCoordinate) {
281
359
  const refs = {};
282
- for (const fieldName of Object.keys(fields)) refs[fieldName] = {
283
- kind: "targetFieldRef",
284
- source: "token",
285
- modelName,
286
- fieldName
287
- };
360
+ for (const [fieldName, fieldBuilder] of Object.entries(fields)) {
361
+ const physicalColumn = crossSpaceCoordinate !== void 0 ? fieldBuilder.physicalColumnName : void 0;
362
+ refs[fieldName] = {
363
+ kind: "targetFieldRef",
364
+ source: "token",
365
+ modelName,
366
+ fieldName,
367
+ ...crossSpaceCoordinate !== void 0 ? {
368
+ spaceId: crossSpaceCoordinate.spaceId,
369
+ ...crossSpaceCoordinate.namespaceId !== void 0 ? { namespaceId: crossSpaceCoordinate.namespaceId } : {},
370
+ ...crossSpaceCoordinate.tableName !== void 0 ? { tableName: crossSpaceCoordinate.tableName } : {},
371
+ ...physicalColumn !== void 0 ? { columnName: physicalColumn } : {}
372
+ } : {}
373
+ };
374
+ }
288
375
  return refs;
289
376
  }
290
377
  function buildStageSpec(stageInput, context) {
@@ -316,12 +403,21 @@ var ContractModelBuilder = class ContractModelBuilder {
316
403
  stageOne;
317
404
  attributesFactory;
318
405
  sqlFactory;
406
+ spaceId;
407
+ tableName;
319
408
  refs;
320
- constructor(stageOne, attributesFactory, sqlFactory) {
409
+ constructor(stageOne, attributesFactory, sqlFactory, spaceId, tableName) {
321
410
  this.stageOne = stageOne;
322
411
  this.attributesFactory = attributesFactory;
323
412
  this.sqlFactory = sqlFactory;
324
- this.refs = stageOne.modelName ? createModelTokenRefs(stageOne.modelName, stageOne.fields) : void 0;
413
+ this.spaceId = spaceId;
414
+ this.tableName = tableName;
415
+ const crossSpaceCoordinate = spaceId !== void 0 ? {
416
+ spaceId,
417
+ ...stageOne.namespace !== void 0 ? { namespaceId: stageOne.namespace } : {},
418
+ ...tableName !== void 0 ? { tableName } : {}
419
+ } : void 0;
420
+ this.refs = blindCast(stageOne.modelName ? createModelTokenRefs(stageOne.modelName, stageOne.fields, crossSpaceCoordinate) : void 0);
325
421
  }
326
422
  ref(fieldName) {
327
423
  const modelName = this.stageOne.modelName;
@@ -342,13 +438,14 @@ var ContractModelBuilder = class ContractModelBuilder {
342
438
  ...this.stageOne.relations,
343
439
  ...relations
344
440
  }
345
- }, this.attributesFactory, this.sqlFactory);
441
+ }, this.attributesFactory, this.sqlFactory, this.spaceId, this.tableName);
346
442
  }
347
443
  attributes(specOrFactory) {
348
- return new ContractModelBuilder(this.stageOne, specOrFactory, this.sqlFactory);
444
+ return new ContractModelBuilder(this.stageOne, specOrFactory, this.sqlFactory, this.spaceId, this.tableName);
349
445
  }
350
446
  sql(specOrFactory) {
351
- return new ContractModelBuilder(this.stageOne, this.attributesFactory, specOrFactory);
447
+ const nextTableName = typeof specOrFactory !== "function" ? specOrFactory.table : this.tableName;
448
+ return blindCast(new ContractModelBuilder(this.stageOne, this.attributesFactory, specOrFactory, this.spaceId, nextTableName));
352
449
  }
353
450
  buildAttributesSpec() {
354
451
  if (!this.attributesFactory) return;
@@ -400,12 +497,47 @@ function model(modelNameOrInput, maybeInput) {
400
497
  relations: input.relations ?? {}
401
498
  });
402
499
  }
500
+ /**
501
+ * Factory for building a standalone branded extension model handle.
502
+ *
503
+ * Use this instead of `new ContractModelBuilder(…)` when constructing handles
504
+ * for models that live in a foreign contract space (e.g. a Supabase extension
505
+ * model referenced by a user's contract). The `spaceId` brands the returned
506
+ * handle so `refs.<field>.spaceId` carries the foreign space identifier.
507
+ *
508
+ * @param name - The domain model name as declared in the foreign contract
509
+ * (e.g. `'AuthUser'`, not a bare table alias like `'User'`).
510
+ * @param input.namespace - The namespace within the foreign space (e.g. `'auth'`).
511
+ * @param input.fields - Field definitions (use `field.column(…)`).
512
+ * @param input.table - The physical table name in the foreign schema.
513
+ * @param spaceId - The extension space identifier (e.g. `'supabase'`).
514
+ */
515
+ function extensionModel(name, input, spaceId) {
516
+ return new ContractModelBuilder({
517
+ modelName: name,
518
+ namespace: input.namespace,
519
+ fields: input.fields,
520
+ relations: {}
521
+ }, void 0, void 0, spaceId, input.table);
522
+ }
523
+ function isCrossSpaceHandle(value) {
524
+ if (typeof value !== "object" || value === null) return false;
525
+ const rec = blindCast(value);
526
+ return typeof rec["spaceId"] === "string" && typeof rec["stageOne"] === "object" && rec["stageOne"] !== null;
527
+ }
403
528
  function belongsTo(toModel, options) {
529
+ const resolvedModel = typeof toModel === "function" ? toModel() : toModel;
530
+ const crossSpaceCoordinate = isCrossSpaceHandle(resolvedModel) ? {
531
+ spaceId: resolvedModel.spaceId,
532
+ ...resolvedModel.tableName !== void 0 ? { tableName: resolvedModel.tableName } : {},
533
+ ...resolvedModel.stageOne.namespace !== void 0 ? { namespaceId: resolvedModel.stageOne.namespace } : {}
534
+ } : void 0;
404
535
  return new RelationBuilder({
405
536
  kind: "belongsTo",
406
537
  toModel: normalizeRelationModelSource(toModel),
407
538
  from: options.from,
408
- to: options.to
539
+ to: options.to,
540
+ ...crossSpaceCoordinate !== void 0 ? crossSpaceCoordinate : {}
409
541
  });
410
542
  }
411
543
  function hasMany(toModel, options) {
@@ -677,6 +809,10 @@ function buildStorageTypeReverseLookup(storageTypes) {
677
809
  function resolveFieldDescriptor(modelName, fieldName, fieldState, storageTypes, storageTypeReverseLookup) {
678
810
  if ("descriptor" in fieldState && fieldState.descriptor) return fieldState.descriptor;
679
811
  if ("typeRef" in fieldState && fieldState.typeRef) {
812
+ if (isEnumTypeHandle(fieldState.typeRef)) return {
813
+ codecId: fieldState.typeRef.codecId,
814
+ nativeType: fieldState.typeRef.nativeType
815
+ };
680
816
  const typeRef = typeof fieldState.typeRef === "string" ? fieldState.typeRef : storageTypeReverseLookup.get(fieldState.typeRef);
681
817
  if (!typeRef) throw new Error(`Field "${modelName}.${fieldName}" references a storage type instance that is not present in definition.types`);
682
818
  const referencedType = storageTypes[typeRef];
@@ -751,6 +887,33 @@ function resolveRelationForeignKeys(spec, allSpecs) {
751
887
  const relation = relationBuilder.build();
752
888
  if (relation.kind !== "belongsTo" || !relation.sql?.fk) continue;
753
889
  const targetModelName = resolveRelationModelName(relation.toModel);
890
+ if (relation.spaceId !== void 0) {
891
+ const fields = normalizeRelationFieldNames(relation.from);
892
+ const targetFields = normalizeRelationFieldNames(relation.to);
893
+ assertRelationFieldArity({
894
+ modelName: spec.modelName,
895
+ relationName,
896
+ leftLabel: "source",
897
+ leftFields: fields,
898
+ rightLabel: "target",
899
+ rightFields: targetFields
900
+ });
901
+ foreignKeys.push({
902
+ kind: "fk",
903
+ fields,
904
+ targetModel: targetModelName,
905
+ targetFields,
906
+ targetSpaceId: relation.spaceId,
907
+ ...relation.namespaceId !== void 0 ? { targetNamespaceId: relation.namespaceId } : {},
908
+ ...relation.tableName !== void 0 ? { targetTableName: relation.tableName } : {},
909
+ ...relation.sql.fk.name ? { name: relation.sql.fk.name } : {},
910
+ ...relation.sql.fk.onDelete ? { onDelete: relation.sql.fk.onDelete } : {},
911
+ ...relation.sql.fk.onUpdate ? { onUpdate: relation.sql.fk.onUpdate } : {},
912
+ ...relation.sql.fk.constraint !== void 0 ? { constraint: relation.sql.fk.constraint } : {},
913
+ ...relation.sql.fk.index !== void 0 ? { index: relation.sql.fk.index } : {}
914
+ });
915
+ continue;
916
+ }
754
917
  if (!allSpecs.has(targetModelName)) throw new Error(`Relation "${spec.modelName}.${relationName}" references unknown model "${targetModelName}"`);
755
918
  const fields = normalizeRelationFieldNames(relation.from);
756
919
  const targetFields = normalizeRelationFieldNames(relation.to);
@@ -782,10 +945,8 @@ function resolveRelationAnchorFields(spec) {
782
945
  if ("id" in spec.fieldToColumn) return ["id"];
783
946
  throw new Error(`Model "${spec.modelName}" needs an explicit id or an "id" field to anchor non-owning relations`);
784
947
  }
785
- function lowerBelongsToRelation(relationName, relation, currentSpec, allSpecs) {
948
+ function lowerBelongsToRelation(relationName, relation, currentSpec, allSpecs, extensionPacks) {
786
949
  const targetModelName = resolveRelationModelName(relation.toModel);
787
- const targetSpec = allSpecs.get(targetModelName);
788
- if (!targetSpec) throw new Error(`Relation "${currentSpec.modelName}.${relationName}" references unknown model "${targetModelName}"`);
789
950
  const fromFields = normalizeRelationFieldNames(relation.from);
790
951
  const toFields = normalizeRelationFieldNames(relation.to);
791
952
  assertRelationFieldArity({
@@ -796,6 +957,27 @@ function lowerBelongsToRelation(relationName, relation, currentSpec, allSpecs) {
796
957
  rightLabel: "target",
797
958
  rightFields: toFields
798
959
  });
960
+ if (relation.spaceId !== void 0) {
961
+ assertKnownExtensionPack(extensionPacks, relation.spaceId, `Relation "${currentSpec.modelName}.${relationName}"`);
962
+ const targetTable = relation.tableName ?? targetModelName.toLowerCase();
963
+ const parentColumns = mapFieldNamesToColumnNames(currentSpec.modelName, fromFields, currentSpec.fieldToColumn);
964
+ return {
965
+ fieldName: relationName,
966
+ toModel: targetModelName,
967
+ toTable: targetTable,
968
+ cardinality: "N:1",
969
+ spaceId: relation.spaceId,
970
+ ...relation.namespaceId !== void 0 ? { namespaceId: relation.namespaceId } : {},
971
+ on: {
972
+ parentTable: currentSpec.tableName,
973
+ parentColumns,
974
+ childTable: targetTable,
975
+ childColumns: toFields
976
+ }
977
+ };
978
+ }
979
+ const targetSpec = allSpecs.get(targetModelName);
980
+ if (!targetSpec) throw new Error(`Relation "${currentSpec.modelName}.${relationName}" references unknown model "${targetModelName}"`);
799
981
  return {
800
982
  fieldName: relationName,
801
983
  toModel: targetModelName,
@@ -866,12 +1048,12 @@ function lowerManyToManyRelation(relationName, relation, currentSpec, allSpecs)
866
1048
  }
867
1049
  };
868
1050
  }
869
- function resolveRelationNode(relationName, relation, currentSpec, allSpecs) {
870
- if (relation.kind === "belongsTo") return lowerBelongsToRelation(relationName, relation, currentSpec, allSpecs);
1051
+ function resolveRelationNode(relationName, relation, currentSpec, allSpecs, extensionPacks) {
1052
+ if (relation.kind === "belongsTo") return lowerBelongsToRelation(relationName, relation, currentSpec, allSpecs, extensionPacks);
871
1053
  if (relation.kind === "hasMany" || relation.kind === "hasOne") return lowerHasOwnershipRelation(relationName, relation, currentSpec, allSpecs);
872
1054
  return lowerManyToManyRelation(relationName, relation, currentSpec, allSpecs);
873
1055
  }
874
- function lowerForeignKeyNode(spec, targetSpec, foreignKey) {
1056
+ function lowerLocalForeignKeyNode(spec, targetSpec, foreignKey) {
875
1057
  return {
876
1058
  columns: mapFieldNamesToColumnNames(spec.modelName, foreignKey.fields, spec.fieldToColumn),
877
1059
  references: {
@@ -886,33 +1068,70 @@ function lowerForeignKeyNode(spec, targetSpec, foreignKey) {
886
1068
  ...foreignKey.index !== void 0 ? { index: foreignKey.index } : {}
887
1069
  };
888
1070
  }
889
- function resolveForeignKeyNodes(spec, allSpecs) {
1071
+ function lowerCrossSpaceForeignKeyNode(spec, foreignKey) {
1072
+ return {
1073
+ columns: mapFieldNamesToColumnNames(spec.modelName, foreignKey.fields, spec.fieldToColumn),
1074
+ references: {
1075
+ model: foreignKey.targetModel,
1076
+ table: foreignKey.targetTableName ?? foreignKey.targetModel.toLowerCase(),
1077
+ columns: foreignKey.targetFields,
1078
+ ...foreignKey.targetNamespaceId !== void 0 ? { namespaceId: foreignKey.targetNamespaceId } : {},
1079
+ spaceId: foreignKey.targetSpaceId
1080
+ },
1081
+ ...foreignKey.name ? { name: foreignKey.name } : {},
1082
+ ...foreignKey.onDelete ? { onDelete: foreignKey.onDelete } : {},
1083
+ ...foreignKey.onUpdate ? { onUpdate: foreignKey.onUpdate } : {},
1084
+ ...foreignKey.constraint !== void 0 ? { constraint: foreignKey.constraint } : {},
1085
+ ...foreignKey.index !== void 0 ? { index: foreignKey.index } : {}
1086
+ };
1087
+ }
1088
+ function assertKnownExtensionPack(extensionPacks, spaceId, context) {
1089
+ if (extensionPacks !== void 0 && Object.hasOwn(extensionPacks, spaceId)) return;
1090
+ throw new Error(`${context} references contract space "${spaceId}" but "${spaceId}" is not declared in extensionPacks. Add the pack to extensionPacks.`);
1091
+ }
1092
+ function resolveForeignKeyNodes(spec, allSpecs, extensionPacks) {
890
1093
  const relationForeignKeys = resolveRelationForeignKeys(spec, allSpecs).map((foreignKey) => {
1094
+ if (foreignKey.targetSpaceId !== void 0) {
1095
+ assertKnownExtensionPack(extensionPacks, foreignKey.targetSpaceId, `Relation-derived foreign key on "${spec.modelName}"`);
1096
+ return lowerCrossSpaceForeignKeyNode(spec, {
1097
+ ...foreignKey,
1098
+ targetSpaceId: foreignKey.targetSpaceId
1099
+ });
1100
+ }
891
1101
  const targetSpec = allSpecs.get(foreignKey.targetModel);
892
1102
  if (!targetSpec) throw new Error(`Foreign key on "${spec.modelName}" references unknown model "${foreignKey.targetModel}"`);
893
- return lowerForeignKeyNode(spec, targetSpec, foreignKey);
1103
+ return lowerLocalForeignKeyNode(spec, targetSpec, foreignKey);
894
1104
  });
895
1105
  const sqlForeignKeys = (spec.sqlSpec?.foreignKeys ?? []).map((foreignKey) => {
1106
+ if (foreignKey.targetSpaceId !== void 0) {
1107
+ assertKnownExtensionPack(extensionPacks, foreignKey.targetSpaceId, `Foreign key on "${spec.modelName}"`);
1108
+ return lowerCrossSpaceForeignKeyNode(spec, {
1109
+ ...foreignKey,
1110
+ targetSpaceId: foreignKey.targetSpaceId
1111
+ });
1112
+ }
896
1113
  const targetSpec = allSpecs.get(foreignKey.targetModel);
897
1114
  if (!targetSpec) throw new Error(`Foreign key on "${spec.modelName}" references unknown model "${foreignKey.targetModel}"`);
898
- return lowerForeignKeyNode(spec, targetSpec, foreignKey);
1115
+ return lowerLocalForeignKeyNode(spec, targetSpec, foreignKey);
899
1116
  });
900
1117
  return [...relationForeignKeys, ...sqlForeignKeys];
901
1118
  }
902
- function resolveModelNode(spec, allSpecs, storageTypes, storageTypeReverseLookup) {
1119
+ function resolveModelNode(spec, allSpecs, storageTypes, storageTypeReverseLookup, extensionPacks) {
903
1120
  const fields = [];
904
1121
  for (const [fieldName, fieldBuilder] of Object.entries(spec.fieldBuilders)) {
905
1122
  const fieldState = fieldBuilder.build();
906
1123
  const descriptor = resolveFieldDescriptor(spec.modelName, fieldName, fieldState, storageTypes, storageTypeReverseLookup);
907
1124
  const columnName = spec.fieldToColumn[fieldName];
908
1125
  if (!columnName) throw new Error(`Column name resolution failed for "${spec.modelName}.${fieldName}"`);
1126
+ const enumHandle = "typeRef" in fieldState && isEnumTypeHandle(fieldState.typeRef) ? fieldState.typeRef : void 0;
909
1127
  fields.push({
910
1128
  fieldName,
911
1129
  columnName,
912
1130
  descriptor,
913
1131
  nullable: fieldState.nullable,
914
1132
  ...fieldState.default ? { default: fieldState.default } : {},
915
- ...fieldState.executionDefaults ? { executionDefaults: fieldState.executionDefaults } : {}
1133
+ ...fieldState.executionDefaults ? { executionDefaults: fieldState.executionDefaults } : {},
1134
+ ...enumHandle !== void 0 ? { enumTypeHandle: enumHandle } : {}
916
1135
  });
917
1136
  }
918
1137
  const { idConstraint } = spec;
@@ -926,8 +1145,8 @@ function resolveModelNode(spec, allSpecs, storageTypes, storageTypeReverseLookup
926
1145
  ...ifDefined("type", index.type),
927
1146
  ...ifDefined("options", index.options)
928
1147
  }));
929
- const foreignKeys = resolveForeignKeyNodes(spec, allSpecs);
930
- const relations = Object.entries(spec.relations).map(([relationName, relationBuilder]) => resolveRelationNode(relationName, relationBuilder.build(), spec, allSpecs));
1148
+ const foreignKeys = resolveForeignKeyNodes(spec, allSpecs, extensionPacks);
1149
+ const relations = Object.entries(spec.relations).map(([relationName, relationBuilder]) => resolveRelationNode(relationName, relationBuilder.build(), spec, allSpecs, extensionPacks));
931
1150
  return {
932
1151
  modelName: spec.modelName,
933
1152
  tableName: spec.tableName,
@@ -940,7 +1159,8 @@ function resolveModelNode(spec, allSpecs, storageTypes, storageTypeReverseLookup
940
1159
  ...uniques.length > 0 ? { uniques } : {},
941
1160
  ...indexes.length > 0 ? { indexes } : {},
942
1161
  ...foreignKeys.length > 0 ? { foreignKeys } : {},
943
- ...relations.length > 0 ? { relations } : {}
1162
+ ...relations.length > 0 ? { relations } : {},
1163
+ ...ifDefined("control", spec.sqlSpec?.control)
944
1164
  };
945
1165
  }
946
1166
  function collectRuntimeModelSpecs(definition) {
@@ -991,22 +1211,24 @@ function collectRuntimeModelSpecs(definition) {
991
1211
  modelSpecs
992
1212
  };
993
1213
  }
994
- function lowerModels(collection) {
1214
+ function lowerModels(collection, extensionPacks) {
995
1215
  emitTypedCrossModelFallbackWarnings(collection);
996
1216
  const storageTypeReverseLookup = buildStorageTypeReverseLookup(collection.storageTypes);
997
- return Array.from(collection.modelSpecs.values()).map((spec) => resolveModelNode(spec, collection.modelSpecs, collection.storageTypes, storageTypeReverseLookup));
1217
+ return Array.from(collection.modelSpecs.values()).map((spec) => resolveModelNode(spec, collection.modelSpecs, collection.storageTypes, storageTypeReverseLookup, extensionPacks));
998
1218
  }
999
1219
  function buildContractDefinition(definition) {
1000
1220
  const collection = collectRuntimeModelSpecs(definition);
1001
- const models = lowerModels(collection);
1221
+ const models = lowerModels(collection, definition.extensionPacks);
1002
1222
  return {
1003
1223
  target: definition.target,
1224
+ ...ifDefined("defaultControlPolicy", definition.defaultControlPolicy),
1004
1225
  ...definition.extensionPacks ? { extensionPacks: definition.extensionPacks } : {},
1005
1226
  ...definition.storageHash ? { storageHash: definition.storageHash } : {},
1006
1227
  ...definition.foreignKeyDefaults ? { foreignKeyDefaults: definition.foreignKeyDefaults } : {},
1007
1228
  ...Object.keys(collection.storageTypes).length > 0 ? { storageTypes: collection.storageTypes } : {},
1008
1229
  ...definition.namespaces ? { namespaces: definition.namespaces } : {},
1009
1230
  ...definition.createNamespace ? { createNamespace: definition.createNamespace } : {},
1231
+ ...definition.enums && Object.keys(definition.enums).length > 0 ? { enums: definition.enums } : {},
1010
1232
  models
1011
1233
  };
1012
1234
  }
@@ -1094,19 +1316,33 @@ function buildContractFromDsl(definition) {
1094
1316
  validatePerModelNamespaces(definition.target, definition.namespaces, definition.models ?? {});
1095
1317
  return blindCast(buildSqlContractFromDefinition(buildContractDefinition(definition), definition.codecLookup));
1096
1318
  }
1097
- function defineContract(definition, factory) {
1098
- if (!isContractInput(definition)) throw new TypeError("defineContract expects a contract definition object. Define your contract with defineContract({ family, target, models, ... }).");
1099
- if (!factory) return buildContractFromDsl(definition);
1100
- return buildContractFromDsl({
1319
+ /** Implementation. */
1320
+ function buildBoundContract(family, target, definition, factory) {
1321
+ const full = {
1101
1322
  ...definition,
1102
- ...factory(createComposedAuthoringHelpers({
1103
- family: definition.family,
1104
- target: definition.target,
1323
+ family,
1324
+ target
1325
+ };
1326
+ if (factory !== void 0) {
1327
+ const built = factory(createComposedAuthoringHelpers({
1328
+ family,
1329
+ target,
1105
1330
  extensionPacks: definition.extensionPacks
1106
- }))
1107
- });
1331
+ }));
1332
+ return buildContractFromDsl({
1333
+ ...full,
1334
+ ...ifDefined("types", built.types),
1335
+ ...ifDefined("models", built.models)
1336
+ });
1337
+ }
1338
+ return buildContractFromDsl(full);
1339
+ }
1340
+ function defineContract(definition, factory) {
1341
+ if (!isContractInput(definition)) throw new TypeError("defineContract expects a contract definition object. Define your contract with defineContract({ family, target, models, ... }).");
1342
+ if (factory !== void 0) return buildBoundContract(definition.family, definition.target, definition, factory);
1343
+ return buildBoundContract(definition.family, definition.target, definition);
1108
1344
  }
1109
1345
  //#endregion
1110
- export { buildSqlContractFromDefinition, defineContract, field, model, rel };
1346
+ export { buildBoundContract, buildSqlContractFromDefinition, defineContract, enumType, extensionModel, field, member, model, rel };
1111
1347
 
1112
1348
  //# sourceMappingURL=contract-builder.mjs.map