@prisma-next/sql-contract-ts 0.3.0-dev.135 → 0.3.0-dev.146

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,218 +1,39 @@
1
+ import type { ForeignKeyDefaultsState } from '@prisma-next/contract-authoring';
2
+ import type { CodecLookup } from '@prisma-next/framework-components/codec';
1
3
  import type {
2
4
  ExtensionPackRef,
3
5
  FamilyPackRef,
4
6
  TargetPackRef,
5
- } from '@prisma-next/contract/framework-components';
6
- import type { ExecutionMutationDefaultValue } from '@prisma-next/contract/types';
7
- import type {
8
- ColumnBuilderState,
9
- ColumnTypeDescriptor,
10
- ContractBuilderState,
11
- ForeignKeyDefaultsState,
12
- ModelBuilderState,
13
- RelationDefinition,
14
- TableBuilderState,
15
- } from '@prisma-next/contract-authoring';
16
- import {
17
- type BuildModels,
18
- type BuildStorageColumn,
19
- ContractBuilder,
20
- createTable,
21
- type ExtractColumns,
22
- type ExtractPrimaryKey,
23
- ModelBuilder,
24
- TableBuilder,
25
- } from '@prisma-next/contract-authoring';
26
- import type {
27
- ContractWithTypeMaps,
28
- Index,
29
- ReferentialAction,
30
- SqlContract,
31
- StorageTypeInstance,
32
- TypeMaps,
33
- } from '@prisma-next/sql-contract/types';
7
+ } from '@prisma-next/framework-components/components';
8
+ import type { StorageTypeInstance } from '@prisma-next/sql-contract/types';
9
+ import { buildSqlContractFromDefinition } from './build-contract';
34
10
  import {
35
11
  type ComposedAuthoringHelpers,
36
12
  createComposedAuthoringHelpers,
37
13
  } from './composed-authoring-helpers';
38
14
  import {
39
- buildContractIR,
40
- buildSqlContractFromSemanticDefinition,
41
- type RuntimeBuilderState,
42
- } from './contract-ir-builder';
43
-
44
- export { buildSqlContractFromSemanticDefinition } from './contract-ir-builder';
45
-
46
- import {
15
+ type ContractInput,
16
+ type ContractModelBuilder,
47
17
  field,
48
- isStagedContractInput,
18
+ isContractInput,
49
19
  type ModelAttributesSpec,
50
20
  model,
51
21
  type RelationBuilder,
22
+ type RelationState,
52
23
  rel,
53
24
  type ScalarFieldBuilder,
54
25
  type SqlStageSpec,
55
- type StagedContractInput,
56
- type StagedModelBuilder,
57
- type RelationState as StagedRelationState,
58
- } from './staged-contract-dsl';
59
- import { buildStagedSemanticContractDefinition } from './staged-contract-lowering';
60
- import type {
61
- ExtractCodecTypesFromPack,
62
- MergeExtensionCodecTypes,
63
- MergeExtensionPackRefs,
64
- SqlContractResult,
65
- } from './staged-contract-types';
66
-
67
- type ColumnDefaultForCodec<
68
- CodecTypes extends Record<string, { output: unknown }>,
69
- CodecId extends string,
70
- > =
71
- | {
72
- readonly kind: 'literal';
73
- readonly value: CodecId extends keyof CodecTypes ? CodecTypes[CodecId]['output'] : unknown;
74
- }
75
- | { readonly kind: 'function'; readonly expression: string };
76
-
77
- type SqlNullableColumnOptions<
78
- Descriptor extends ColumnTypeDescriptor,
79
- CodecTypes extends Record<string, { output: unknown }>,
80
- > = {
81
- readonly type: Descriptor;
82
- readonly nullable: true;
83
- readonly typeParams?: Record<string, unknown>;
84
- readonly default?: ColumnDefaultForCodec<CodecTypes, Descriptor['codecId']>;
85
- };
86
-
87
- type SqlNonNullableColumnOptions<
88
- Descriptor extends ColumnTypeDescriptor,
89
- CodecTypes extends Record<string, { output: unknown }>,
90
- > = {
91
- readonly type: Descriptor;
92
- readonly nullable?: false;
93
- readonly typeParams?: Record<string, unknown>;
94
- readonly default?: ColumnDefaultForCodec<CodecTypes, Descriptor['codecId']>;
95
- };
96
-
97
- type SqlGeneratedColumnOptions<
98
- Descriptor extends ColumnTypeDescriptor,
99
- CodecTypes extends Record<string, { output: unknown }>,
100
- > = Omit<SqlNonNullableColumnOptions<Descriptor, CodecTypes>, 'default' | 'nullable'> & {
101
- readonly nullable?: false;
102
- readonly generated: ExecutionMutationDefaultValue;
103
- };
26
+ } from './contract-dsl';
27
+ import { buildContractDefinition } from './contract-lowering';
28
+ import type { SqlContractResult } from './contract-types';
104
29
 
105
- type SqlColumnOptions<
106
- Descriptor extends ColumnTypeDescriptor,
107
- CodecTypes extends Record<string, { output: unknown }>,
108
- > =
109
- | SqlNullableColumnOptions<Descriptor, CodecTypes>
110
- | SqlNonNullableColumnOptions<Descriptor, CodecTypes>;
30
+ export { buildSqlContractFromDefinition } from './build-contract';
111
31
 
112
- export interface SqlTableBuilder<
113
- Name extends string,
114
- CodecTypes extends Record<string, { output: unknown }>,
115
- Columns extends Record<string, ColumnBuilderState<string, boolean, string>> = Record<
116
- never,
117
- ColumnBuilderState<string, boolean, string>
118
- >,
119
- PrimaryKey extends readonly string[] | undefined = undefined,
120
- > extends Omit<TableBuilder<Name, Columns, PrimaryKey>, 'column' | 'generated'> {
121
- column<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
122
- name: ColName,
123
- options: SqlNullableColumnOptions<Descriptor, CodecTypes>,
124
- ): TableBuilder<
125
- Name,
126
- Columns & Record<ColName, ColumnBuilderState<ColName, true, Descriptor['codecId']>>,
127
- PrimaryKey
128
- >;
129
- column<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
130
- name: ColName,
131
- options: SqlNonNullableColumnOptions<Descriptor, CodecTypes>,
132
- ): TableBuilder<
133
- Name,
134
- Columns & Record<ColName, ColumnBuilderState<ColName, false, Descriptor['codecId']>>,
135
- PrimaryKey
136
- >;
137
- column<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
138
- name: ColName,
139
- options: SqlColumnOptions<Descriptor, CodecTypes>,
140
- ): TableBuilder<
141
- Name,
142
- Columns & Record<ColName, ColumnBuilderState<ColName, boolean, Descriptor['codecId']>>,
143
- PrimaryKey
144
- >;
145
- generated<ColName extends string, Descriptor extends ColumnTypeDescriptor>(
146
- name: ColName,
147
- options: SqlGeneratedColumnOptions<Descriptor, CodecTypes>,
148
- ): TableBuilder<
149
- Name,
150
- Columns & Record<ColName, ColumnBuilderState<ColName, false, Descriptor['codecId']>>,
151
- PrimaryKey
152
- >;
153
- }
154
-
155
- type BuildStorageTable<
156
- _TableName extends string,
157
- Columns extends Record<string, ColumnBuilderState<string, boolean, string>>,
158
- PK extends readonly string[] | undefined,
159
- > = {
160
- readonly columns: {
161
- readonly [K in keyof Columns]: Columns[K] extends ColumnBuilderState<
162
- string,
163
- infer Null,
164
- infer TType
165
- >
166
- ? BuildStorageColumn<Null & boolean, TType>
167
- : never;
168
- };
169
- readonly uniques: ReadonlyArray<{ readonly columns: readonly string[]; readonly name?: string }>;
170
- readonly indexes: ReadonlyArray<Index>;
171
- readonly foreignKeys: ReadonlyArray<{
172
- readonly columns: readonly string[];
173
- readonly references: { readonly table: string; readonly columns: readonly string[] };
174
- readonly name?: string;
175
- readonly onDelete?: ReferentialAction;
176
- readonly onUpdate?: ReferentialAction;
177
- readonly constraint: boolean;
178
- readonly index: boolean;
179
- }>;
180
- } & (PK extends readonly string[]
181
- ? { readonly primaryKey: { readonly columns: PK; readonly name?: string } }
182
- : Record<string, never>);
183
-
184
- type BuildStorage<
185
- Tables extends Record<
186
- string,
187
- TableBuilderState<
188
- string,
189
- Record<string, ColumnBuilderState<string, boolean, string>>,
190
- readonly string[] | undefined
191
- >
192
- >,
193
- Types extends Record<string, StorageTypeInstance>,
194
- > = {
195
- readonly tables: {
196
- readonly [K in keyof Tables]: BuildStorageTable<
197
- K & string,
198
- ExtractColumns<Tables[K]>,
199
- ExtractPrimaryKey<Tables[K]>
200
- >;
201
- };
202
- readonly types: Types;
203
- };
204
-
205
- export interface ColumnBuilder<Name extends string, Nullable extends boolean, Type extends string> {
206
- nullable<Value extends boolean>(value?: Value): ColumnBuilder<Name, Value, Type>;
207
- type<Id extends string>(id: Id): ColumnBuilder<Name, Nullable, Id>;
208
- build(): ColumnBuilderState<Name, Nullable, Type>;
209
- }
210
-
211
- type StagedModelLike = {
32
+ type ModelLike = {
212
33
  readonly stageOne: {
213
34
  readonly modelName?: string;
214
35
  readonly fields: Record<string, ScalarFieldBuilder>;
215
- readonly relations: Record<string, RelationBuilder<StagedRelationState>>;
36
+ readonly relations: Record<string, RelationBuilder<RelationState>>;
216
37
  };
217
38
  readonly __attributes: ModelAttributesSpec | undefined;
218
39
  readonly __sql: SqlStageSpec | undefined;
@@ -220,408 +41,14 @@ type StagedModelLike = {
220
41
  buildSqlSpec(): SqlStageSpec | undefined;
221
42
  };
222
43
 
223
- function buildStagedContract<Definition extends StagedContractInput>(
224
- definition: Definition,
225
- ): SqlContractResult<Definition> {
226
- return buildSqlContractFromSemanticDefinition(
227
- buildStagedSemanticContractDefinition(definition),
228
- ) as SqlContractResult<Definition>;
229
- }
230
-
231
- class SqlContractBuilder<
232
- CodecTypes extends Record<string, { output: unknown }> = Record<string, never>,
233
- Target extends string | undefined = undefined,
234
- Tables extends Record<
235
- string,
236
- TableBuilderState<
237
- string,
238
- Record<string, ColumnBuilderState<string, boolean, string>>,
239
- readonly string[] | undefined
240
- >
241
- > = Record<never, never>,
242
- Models extends Record<
243
- string,
244
- ModelBuilderState<string, string, Record<string, string>, Record<string, RelationDefinition>>
245
- > = Record<never, never>,
246
- Types extends Record<string, StorageTypeInstance> = Record<never, never>,
247
- StorageHash extends string | undefined = undefined,
248
- ExtensionPacks extends Record<string, unknown> | undefined = undefined,
249
- Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
250
- > extends ContractBuilder<Target, Tables, Models, StorageHash, ExtensionPacks, Capabilities> {
251
- protected declare readonly state: ContractBuilderState<
252
- Target,
253
- Tables,
254
- Models,
255
- StorageHash,
256
- ExtensionPacks,
257
- Capabilities
258
- > & {
259
- readonly storageTypes?: Types;
260
- };
261
- /**
262
- * This method is responsible for normalizing the contract IR by setting default values
263
- * for all required fields:
264
- * - `nullable`: defaults to `false` if not provided
265
- * - `uniques`: defaults to `[]` (empty array)
266
- * - `indexes`: defaults to `[]` (empty array)
267
- * - `foreignKeys`: defaults to `[]` (empty array)
268
- * - model `relations`: defaults to `{}` (empty object) when not populated by the builder
269
- * - `nativeType`: required field set from column type descriptor when columns are defined
270
- *
271
- * The contract builder is the **only** place where normalization should occur.
272
- * Validators, parsers, and emitters should assume the contract is already normalized.
273
- *
274
- * **Required**: Use column type descriptors (e.g., `int4Column`, `textColumn`) when defining columns.
275
- * This ensures `nativeType` is set correctly at build time.
276
- *
277
- * @returns A normalized SqlContract with all required fields present
278
- */
279
- build(): Target extends string
280
- ? ContractWithTypeMaps<
281
- SqlContract<BuildStorage<Tables, Types>, BuildModels<Models>> & {
282
- readonly schemaVersion: '1';
283
- readonly target: Target;
284
- readonly targetFamily: 'sql';
285
- readonly storageHash: StorageHash extends string ? StorageHash : string;
286
- } & (ExtensionPacks extends Record<string, unknown>
287
- ? { readonly extensionPacks: ExtensionPacks }
288
- : Record<string, never>) &
289
- (Capabilities extends Record<string, Record<string, boolean>>
290
- ? { readonly capabilities: Capabilities }
291
- : Record<string, never>),
292
- TypeMaps<CodecTypes, Record<string, never>>
293
- >
294
- : never {
295
- return buildContractIR(this.state as unknown as RuntimeBuilderState) as unknown as ReturnType<
296
- SqlContractBuilder<
297
- CodecTypes,
298
- Target,
299
- Tables,
300
- Models,
301
- Types,
302
- StorageHash,
303
- ExtensionPacks,
304
- Capabilities
305
- >['build']
306
- >;
307
- }
308
-
309
- override target<
310
- T extends string,
311
- TPack extends TargetPackRef<string, T> = TargetPackRef<string, T>,
312
- >(
313
- packRef: TPack & TargetPackRef<string, T>,
314
- ): SqlContractBuilder<
315
- ExtractCodecTypesFromPack<TPack> extends Record<string, never>
316
- ? CodecTypes
317
- : ExtractCodecTypesFromPack<TPack>,
318
- T,
319
- Tables,
320
- Models,
321
- Types,
322
- StorageHash,
323
- ExtensionPacks,
324
- Capabilities
325
- > {
326
- return new SqlContractBuilder<
327
- ExtractCodecTypesFromPack<TPack> extends Record<string, never>
328
- ? CodecTypes
329
- : ExtractCodecTypesFromPack<TPack>,
330
- T,
331
- Tables,
332
- Models,
333
- Types,
334
- StorageHash,
335
- ExtensionPacks,
336
- Capabilities
337
- >({
338
- ...this.state,
339
- target: packRef.targetId,
340
- }) as SqlContractBuilder<
341
- ExtractCodecTypesFromPack<TPack> extends Record<string, never>
342
- ? CodecTypes
343
- : ExtractCodecTypesFromPack<TPack>,
344
- T,
345
- Tables,
346
- Models,
347
- Types,
348
- StorageHash,
349
- ExtensionPacks,
350
- Capabilities
351
- >;
352
- }
353
-
354
- extensionPacks<const Packs extends Record<string, ExtensionPackRef<'sql', string>>>(
355
- packs: Packs,
356
- ): SqlContractBuilder<
357
- CodecTypes & MergeExtensionCodecTypes<Packs>,
358
- Target,
359
- Tables,
360
- Models,
361
- Types,
362
- StorageHash,
363
- MergeExtensionPackRefs<ExtensionPacks, Packs>,
364
- Capabilities
365
- > {
366
- if (!this.state.target) {
367
- throw new Error('extensionPacks() requires target() to be called first');
368
- }
369
-
370
- const namespaces = new Set(this.state.extensionNamespaces ?? []);
371
- const nextExtensionPacks = {
372
- ...(this.state.extensionPacks ?? {}),
373
- } as Record<string, unknown>;
374
-
375
- for (const [name, packRef] of Object.entries(packs) as Array<
376
- [keyof Packs & string, ExtensionPackRef<'sql', string>]
377
- >) {
378
- if (!packRef) continue;
379
-
380
- if (packRef.kind !== 'extension') {
381
- throw new Error(
382
- `extensionPacks() only accepts extension pack refs. Received kind "${packRef.kind}".`,
383
- );
384
- }
385
-
386
- if (packRef.familyId !== 'sql') {
387
- throw new Error(
388
- `extension pack "${packRef.id}" targets family "${packRef.familyId}" but this builder targets "sql".`,
389
- );
390
- }
391
-
392
- if (packRef.targetId && packRef.targetId !== this.state.target) {
393
- throw new Error(
394
- `extension pack "${packRef.id}" targets "${packRef.targetId}" but builder target is "${this.state.target}".`,
395
- );
396
- }
397
-
398
- namespaces.add(packRef.id);
399
- nextExtensionPacks[name] = packRef;
400
- }
401
-
402
- return new SqlContractBuilder<
403
- CodecTypes & MergeExtensionCodecTypes<Packs>,
404
- Target,
405
- Tables,
406
- Models,
407
- Types,
408
- StorageHash,
409
- MergeExtensionPackRefs<ExtensionPacks, Packs>,
410
- Capabilities
411
- >({
412
- ...this.state,
413
- extensionPacks: nextExtensionPacks as MergeExtensionPackRefs<ExtensionPacks, Packs>,
414
- extensionNamespaces: [...namespaces],
415
- });
416
- }
417
-
418
- override capabilities<C extends Record<string, Record<string, boolean>>>(
419
- capabilities: C,
420
- ): SqlContractBuilder<CodecTypes, Target, Tables, Models, Types, StorageHash, ExtensionPacks, C> {
421
- return new SqlContractBuilder<
422
- CodecTypes,
423
- Target,
424
- Tables,
425
- Models,
426
- Types,
427
- StorageHash,
428
- ExtensionPacks,
429
- C
430
- >({
431
- ...this.state,
432
- capabilities,
433
- });
434
- }
435
-
436
- override storageHash<H extends string>(
437
- hash: H,
438
- ): SqlContractBuilder<
439
- CodecTypes,
440
- Target,
441
- Tables,
442
- Models,
443
- Types,
444
- H,
445
- ExtensionPacks,
446
- Capabilities
447
- > {
448
- return new SqlContractBuilder<
449
- CodecTypes,
450
- Target,
451
- Tables,
452
- Models,
453
- Types,
454
- H,
455
- ExtensionPacks,
456
- Capabilities
457
- >({
458
- ...this.state,
459
- storageHash: hash,
460
- });
461
- }
462
-
463
- override table<
464
- TableName extends string,
465
- T extends TableBuilder<
466
- TableName,
467
- Record<string, ColumnBuilderState<string, boolean, string>>,
468
- readonly string[] | undefined
469
- >,
470
- >(
471
- name: TableName,
472
- callback: (t: TableBuilder<TableName>) => T | undefined,
473
- ): SqlContractBuilder<
474
- CodecTypes,
475
- Target,
476
- Tables & Record<TableName, ReturnType<T['build']>>,
477
- Models,
478
- Types,
479
- StorageHash,
480
- ExtensionPacks,
481
- Capabilities
482
- > {
483
- const tableBuilder = createTable(name);
484
- // Double cast: createTable returns an unparameterized builder; we first narrow
485
- // to SqlTableBuilder with the caller's generic params, then to the public
486
- // TableBuilder facade that the callback expects.
487
- const result = callback(
488
- tableBuilder as unknown as SqlTableBuilder<
489
- TableName,
490
- CodecTypes
491
- > as unknown as TableBuilder<TableName>,
492
- );
493
- const finalBuilder = result instanceof TableBuilder ? result : tableBuilder;
494
- const tableState = finalBuilder.build();
495
-
496
- return new SqlContractBuilder<
497
- CodecTypes,
498
- Target,
499
- Tables & Record<TableName, ReturnType<T['build']>>,
500
- Models,
501
- Types,
502
- StorageHash,
503
- ExtensionPacks,
504
- Capabilities
505
- >({
506
- ...this.state,
507
- tables: { ...this.state.tables, [name]: tableState } as Tables &
508
- Record<TableName, ReturnType<T['build']>>,
509
- });
510
- }
511
-
512
- override model<
513
- ModelName extends string,
514
- TableName extends string,
515
- M extends ModelBuilder<
516
- ModelName,
517
- TableName,
518
- Record<string, string>,
519
- Record<string, RelationDefinition>
520
- >,
521
- >(
522
- name: ModelName,
523
- table: TableName,
524
- callback: (
525
- m: ModelBuilder<ModelName, TableName, Record<never, never>, Record<never, never>>,
526
- ) => M | undefined,
527
- ): SqlContractBuilder<
528
- CodecTypes,
529
- Target,
530
- Tables,
531
- Models & Record<ModelName, ReturnType<M['build']>>,
532
- Types,
533
- StorageHash,
534
- ExtensionPacks,
535
- Capabilities
536
- > {
537
- const modelBuilder = new ModelBuilder<ModelName, TableName>(name, table);
538
- const result = callback(modelBuilder);
539
- const finalBuilder = result instanceof ModelBuilder ? result : modelBuilder;
540
- const modelState = finalBuilder.build();
541
-
542
- return new SqlContractBuilder<
543
- CodecTypes,
544
- Target,
545
- Tables,
546
- Models & Record<ModelName, ReturnType<M['build']>>,
547
- Types,
548
- StorageHash,
549
- ExtensionPacks,
550
- Capabilities
551
- >({
552
- ...this.state,
553
- models: { ...this.state.models, [name]: modelState } as Models &
554
- Record<ModelName, ReturnType<M['build']>>,
555
- });
556
- }
557
-
558
- override foreignKeyDefaults(
559
- config: ForeignKeyDefaultsState,
560
- ): SqlContractBuilder<
561
- CodecTypes,
562
- Target,
563
- Tables,
564
- Models,
565
- Types,
566
- StorageHash,
567
- ExtensionPacks,
568
- Capabilities
569
- > {
570
- return new SqlContractBuilder<
571
- CodecTypes,
572
- Target,
573
- Tables,
574
- Models,
575
- Types,
576
- StorageHash,
577
- ExtensionPacks,
578
- Capabilities
579
- >({
580
- ...this.state,
581
- foreignKeyDefaults: config,
582
- });
583
- }
584
-
585
- storageType<Name extends string, Type extends StorageTypeInstance>(
586
- name: Name,
587
- typeInstance: Type,
588
- ): SqlContractBuilder<
589
- CodecTypes,
590
- Target,
591
- Tables,
592
- Models,
593
- Types & Record<Name, Type>,
594
- StorageHash,
595
- ExtensionPacks,
596
- Capabilities
597
- > {
598
- return new SqlContractBuilder<
599
- CodecTypes,
600
- Target,
601
- Tables,
602
- Models,
603
- Types & Record<Name, Type>,
604
- StorageHash,
605
- ExtensionPacks,
606
- Capabilities
607
- >({
608
- ...this.state,
609
- storageTypes: {
610
- ...(this.state.storageTypes ?? {}),
611
- [name]: typeInstance,
612
- },
613
- });
614
- }
615
- }
616
-
617
- type StagedContractDefinition<
44
+ type ContractDefinition<
618
45
  Family extends FamilyPackRef<string>,
619
46
  Target extends TargetPackRef<'sql', string>,
620
47
  Types extends Record<string, StorageTypeInstance>,
621
- Models extends Record<string, StagedModelLike>,
48
+ Models extends Record<string, ModelLike>,
622
49
  ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
623
50
  Capabilities extends Record<string, Record<string, boolean>> | undefined,
624
- Naming extends StagedContractInput['naming'] | undefined,
51
+ Naming extends ContractInput['naming'] | undefined,
625
52
  StorageHash extends string | undefined,
626
53
  ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined,
627
54
  > = {
@@ -634,14 +61,15 @@ type StagedContractDefinition<
634
61
  readonly capabilities?: Capabilities;
635
62
  readonly types?: Types;
636
63
  readonly models?: Models;
64
+ readonly codecLookup?: CodecLookup;
637
65
  };
638
66
 
639
- type StagedContractScaffold<
67
+ type ContractScaffold<
640
68
  Family extends FamilyPackRef<string>,
641
69
  Target extends TargetPackRef<'sql', string>,
642
70
  ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
643
71
  Capabilities extends Record<string, Record<string, boolean>> | undefined,
644
- Naming extends StagedContractInput['naming'] | undefined,
72
+ Naming extends ContractInput['naming'] | undefined,
645
73
  StorageHash extends string | undefined,
646
74
  ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined,
647
75
  > = {
@@ -652,36 +80,96 @@ type StagedContractScaffold<
652
80
  readonly storageHash?: StorageHash;
653
81
  readonly foreignKeyDefaults?: ForeignKeyDefaults;
654
82
  readonly capabilities?: Capabilities;
83
+ readonly codecLookup?: CodecLookup;
655
84
  };
656
85
 
657
- type StagedContractFactory<
86
+ type ContractFactory<
658
87
  Family extends FamilyPackRef<string>,
659
88
  Target extends TargetPackRef<'sql', string>,
660
89
  Types extends Record<string, StorageTypeInstance>,
661
- Models extends Record<string, StagedModelLike>,
90
+ Models extends Record<string, ModelLike>,
662
91
  ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
663
92
  > = (helpers: ComposedAuthoringHelpers<Family, Target, ExtensionPacks>) => {
664
93
  readonly types?: Types;
665
94
  readonly models?: Models;
666
95
  };
667
96
 
668
- export function defineContract<
669
- CodecTypes extends Record<string, { output: unknown }> = Record<string, never>,
670
- >(): SqlContractBuilder<CodecTypes>;
97
+ function validateTargetPackRef(
98
+ family: FamilyPackRef<string>,
99
+ target: TargetPackRef<'sql', string>,
100
+ ): void {
101
+ if (family.familyId !== 'sql') {
102
+ throw new Error(
103
+ `defineContract only accepts SQL family packs. Received family "${family.familyId}".`,
104
+ );
105
+ }
106
+
107
+ if (target.familyId !== family.familyId) {
108
+ throw new Error(
109
+ `target pack "${target.id}" targets family "${target.familyId}" but contract family is "${family.familyId}".`,
110
+ );
111
+ }
112
+ }
113
+
114
+ function validateExtensionPackRefs(
115
+ target: TargetPackRef<'sql', string>,
116
+ extensionPacks?: Record<string, ExtensionPackRef<'sql', string>>,
117
+ ): void {
118
+ if (!extensionPacks) {
119
+ return;
120
+ }
121
+
122
+ for (const packRef of Object.values(extensionPacks)) {
123
+ if (packRef.kind !== 'extension') {
124
+ throw new Error(
125
+ `defineContract only accepts extension pack refs in extensionPacks. Received kind "${packRef.kind}".`,
126
+ );
127
+ }
128
+
129
+ if (packRef.familyId !== target.familyId) {
130
+ throw new Error(
131
+ `extension pack "${packRef.id}" targets family "${packRef.familyId}" but contract target family is "${target.familyId}".`,
132
+ );
133
+ }
134
+
135
+ if (packRef.targetId && packRef.targetId !== target.targetId) {
136
+ throw new Error(
137
+ `extension pack "${packRef.id}" targets "${packRef.targetId}" but contract target is "${target.targetId}".`,
138
+ );
139
+ }
140
+ }
141
+ }
142
+
143
+ function buildContractFromDsl<Definition extends ContractInput>(
144
+ definition: Definition,
145
+ ): SqlContractResult<Definition>;
146
+
147
+ function buildContractFromDsl(
148
+ definition: ContractInput,
149
+ ): ReturnType<typeof buildSqlContractFromDefinition> {
150
+ validateTargetPackRef(definition.family, definition.target);
151
+ validateExtensionPackRefs(definition.target, definition.extensionPacks);
152
+
153
+ return buildSqlContractFromDefinition(
154
+ buildContractDefinition(definition),
155
+ definition.codecLookup,
156
+ );
157
+ }
158
+
671
159
  export function defineContract<
672
160
  const Family extends FamilyPackRef<string>,
673
161
  const Target extends TargetPackRef<'sql', string>,
674
162
  const Types extends Record<string, StorageTypeInstance> = Record<never, never>,
675
- const Models extends Record<string, StagedModelLike> = Record<never, never>,
163
+ const Models extends Record<string, ModelLike> = Record<never, never>,
676
164
  const ExtensionPacks extends
677
165
  | Record<string, ExtensionPackRef<'sql', string>>
678
166
  | undefined = undefined,
679
167
  const Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
680
- const Naming extends StagedContractInput['naming'] | undefined = undefined,
168
+ const Naming extends ContractInput['naming'] | undefined = undefined,
681
169
  const StorageHash extends string | undefined = undefined,
682
170
  const ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined = undefined,
683
171
  >(
684
- definition: StagedContractDefinition<
172
+ definition: ContractDefinition<
685
173
  Family,
686
174
  Target,
687
175
  Types,
@@ -693,7 +181,7 @@ export function defineContract<
693
181
  ForeignKeyDefaults
694
182
  >,
695
183
  ): SqlContractResult<
696
- StagedContractDefinition<
184
+ ContractDefinition<
697
185
  Family,
698
186
  Target,
699
187
  Types,
@@ -709,16 +197,16 @@ export function defineContract<
709
197
  const Family extends FamilyPackRef<string>,
710
198
  const Target extends TargetPackRef<'sql', string>,
711
199
  const Types extends Record<string, StorageTypeInstance> = Record<never, never>,
712
- const Models extends Record<string, StagedModelLike> = Record<never, never>,
200
+ const Models extends Record<string, ModelLike> = Record<never, never>,
713
201
  const ExtensionPacks extends
714
202
  | Record<string, ExtensionPackRef<'sql', string>>
715
203
  | undefined = undefined,
716
204
  const Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
717
- const Naming extends StagedContractInput['naming'] | undefined = undefined,
205
+ const Naming extends ContractInput['naming'] | undefined = undefined,
718
206
  const StorageHash extends string | undefined = undefined,
719
207
  const ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined = undefined,
720
208
  >(
721
- definition: StagedContractScaffold<
209
+ definition: ContractScaffold<
722
210
  Family,
723
211
  Target,
724
212
  ExtensionPacks,
@@ -727,9 +215,9 @@ export function defineContract<
727
215
  StorageHash,
728
216
  ForeignKeyDefaults
729
217
  >,
730
- factory: StagedContractFactory<Family, Target, Types, Models, ExtensionPacks>,
218
+ factory: ContractFactory<Family, Target, Types, Models, ExtensionPacks>,
731
219
  ): SqlContractResult<
732
- StagedContractDefinition<
220
+ ContractDefinition<
733
221
  Family,
734
222
  Target,
735
223
  Types,
@@ -741,41 +229,39 @@ export function defineContract<
741
229
  ForeignKeyDefaults
742
230
  >
743
231
  >;
744
- export function defineContract<
745
- CodecTypes extends Record<string, { output: unknown }> = Record<string, never>,
746
- >(
747
- definition?: StagedContractInput,
748
- factory?: StagedContractFactory<
232
+ export function defineContract(
233
+ definition: ContractInput,
234
+ factory?: ContractFactory<
749
235
  FamilyPackRef<string>,
750
236
  TargetPackRef<'sql', string>,
751
237
  Record<string, StorageTypeInstance>,
752
- Record<string, StagedModelLike>,
238
+ Record<string, ModelLike>,
753
239
  Record<string, ExtensionPackRef<'sql', string>> | undefined
754
240
  >,
755
- ): SqlContractBuilder<CodecTypes> | SqlContractResult<StagedContractInput> {
756
- if (definition && isStagedContractInput(definition)) {
757
- if (factory) {
758
- const builtDefinition = {
759
- ...definition,
760
- ...factory(
761
- createComposedAuthoringHelpers({
762
- family: definition.family,
763
- target: definition.target,
764
- extensionPacks: definition.extensionPacks,
765
- }),
766
- ),
767
- };
768
- return buildStagedContract(builtDefinition);
769
- }
770
- return buildStagedContract(definition);
241
+ ): SqlContractResult<ContractInput> {
242
+ if (!isContractInput(definition)) {
243
+ throw new TypeError(
244
+ 'defineContract expects a contract definition object. Define your contract with defineContract({ family, target, models, ... }).',
245
+ );
246
+ }
247
+
248
+ if (!factory) {
249
+ return buildContractFromDsl(definition);
771
250
  }
772
- return new SqlContractBuilder<CodecTypes>();
251
+
252
+ const builtDefinition = {
253
+ ...definition,
254
+ ...factory(
255
+ createComposedAuthoringHelpers({
256
+ family: definition.family,
257
+ target: definition.target,
258
+ extensionPacks: definition.extensionPacks,
259
+ }),
260
+ ),
261
+ };
262
+
263
+ return buildContractFromDsl(builtDefinition);
773
264
  }
774
265
 
775
266
  export { field, model, rel };
776
- export type {
777
- ComposedAuthoringHelpers,
778
- StagedContractInput,
779
- StagedModelBuilder,
780
- ScalarFieldBuilder,
781
- };
267
+ export type { ComposedAuthoringHelpers, ContractInput, ContractModelBuilder, ScalarFieldBuilder };