@prisma-next/sql-contract-ts 0.14.0-dev.65 → 0.14.0-dev.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,27 +1,27 @@
1
1
  {
2
2
  "name": "@prisma-next/sql-contract-ts",
3
- "version": "0.14.0-dev.65",
3
+ "version": "0.14.0-dev.67",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "SQL-specific TypeScript contract authoring surface for Prisma Next",
8
8
  "dependencies": {
9
- "@prisma-next/config": "0.14.0-dev.65",
10
- "@prisma-next/contract": "0.14.0-dev.65",
11
- "@prisma-next/contract-authoring": "0.14.0-dev.65",
12
- "@prisma-next/framework-components": "0.14.0-dev.65",
13
- "@prisma-next/sql-contract": "0.14.0-dev.65",
14
- "@prisma-next/utils": "0.14.0-dev.65",
9
+ "@prisma-next/config": "0.14.0-dev.67",
10
+ "@prisma-next/contract": "0.14.0-dev.67",
11
+ "@prisma-next/contract-authoring": "0.14.0-dev.67",
12
+ "@prisma-next/framework-components": "0.14.0-dev.67",
13
+ "@prisma-next/sql-contract": "0.14.0-dev.67",
14
+ "@prisma-next/utils": "0.14.0-dev.67",
15
15
  "arktype": "^2.2.0",
16
16
  "pathe": "^2.0.3",
17
17
  "ts-toolbelt": "^9.6.0"
18
18
  },
19
19
  "devDependencies": {
20
- "@prisma-next/test-utils": "0.14.0-dev.65",
21
- "@prisma-next/tsconfig": "0.14.0-dev.65",
20
+ "@prisma-next/test-utils": "0.14.0-dev.67",
21
+ "@prisma-next/tsconfig": "0.14.0-dev.67",
22
22
  "@types/pg": "8.20.0",
23
23
  "pg": "8.21.0",
24
- "@prisma-next/tsdown": "0.14.0-dev.65",
24
+ "@prisma-next/tsdown": "0.14.0-dev.67",
25
25
  "tsdown": "0.22.1",
26
26
  "typescript": "5.9.3",
27
27
  "vitest": "4.1.8"
@@ -2,6 +2,7 @@ import type {
2
2
  AuthoringArgumentDescriptor,
3
3
  AuthoringFieldPresetDescriptor,
4
4
  } from '@prisma-next/framework-components/authoring';
5
+ import type { ColumnTypeDescriptor } from '@prisma-next/framework-components/codec';
5
6
  import type { ScalarFieldBuilder, ScalarFieldState } from './contract-dsl';
6
7
 
7
8
  export type UnionToIntersection<U> = (U extends unknown ? (value: U) => void : never) extends (
@@ -114,9 +115,11 @@ export type FieldBuilderFromPresetDescriptor<
114
115
  ConstraintName extends string | undefined = undefined,
115
116
  > = ScalarFieldBuilder<
116
117
  ScalarFieldState<
117
- ResolveTemplateValue<Descriptor['output']['codecId'], Args> extends string
118
- ? ResolveTemplateValue<Descriptor['output']['codecId'], Args>
119
- : string,
118
+ ColumnTypeDescriptor<
119
+ ResolveTemplateValue<Descriptor['output']['codecId'], Args> extends string
120
+ ? ResolveTemplateValue<Descriptor['output']['codecId'], Args>
121
+ : string
122
+ >,
120
123
  undefined,
121
124
  ResolveTemplateValue<Descriptor['output']['nullable'], Args> extends true ? true : false,
122
125
  undefined,
@@ -40,7 +40,7 @@ type NamedConstraintNameSpec<Name extends string = string> = {
40
40
  };
41
41
 
42
42
  export type ScalarFieldState<
43
- CodecId extends string = string,
43
+ Descriptor extends ColumnTypeDescriptor = ColumnTypeDescriptor,
44
44
  TypeRef extends NamedStorageTypeRef | undefined = undefined,
45
45
  Nullable extends boolean = boolean,
46
46
  ColumnName extends string | undefined = string | undefined,
@@ -49,7 +49,7 @@ export type ScalarFieldState<
49
49
  Many extends boolean = false,
50
50
  > = {
51
51
  readonly kind: 'scalar';
52
- readonly descriptor?: (ColumnTypeDescriptor & { readonly codecId: CodecId }) | undefined;
52
+ readonly descriptor?: Descriptor | undefined;
53
53
  readonly typeRef?: TypeRef | undefined;
54
54
  readonly nullable: Nullable;
55
55
  readonly columnName?: ColumnName | undefined;
@@ -63,7 +63,7 @@ export type ScalarFieldState<
63
63
 
64
64
  type AnyScalarFieldState = {
65
65
  readonly kind: 'scalar';
66
- readonly descriptor?: (ColumnTypeDescriptor & { readonly codecId: string }) | undefined;
66
+ readonly descriptor?: ColumnTypeDescriptor | undefined;
67
67
  readonly typeRef?: NamedStorageTypeRef | undefined;
68
68
  readonly nullable: boolean;
69
69
  readonly columnName?: string | undefined;
@@ -76,7 +76,7 @@ type AnyScalarFieldState = {
76
76
 
77
77
  type HasNamedConstraintId<State extends AnyScalarFieldState> =
78
78
  State extends ScalarFieldState<
79
- string,
79
+ ColumnTypeDescriptor,
80
80
  NamedStorageTypeRef | undefined,
81
81
  boolean,
82
82
  string | undefined,
@@ -91,7 +91,7 @@ type HasNamedConstraintId<State extends AnyScalarFieldState> =
91
91
 
92
92
  type HasNamedConstraintUnique<State extends AnyScalarFieldState> =
93
93
  State extends ScalarFieldState<
94
- string,
94
+ ColumnTypeDescriptor,
95
95
  NamedStorageTypeRef | undefined,
96
96
  boolean,
97
97
  string | undefined,
@@ -118,7 +118,7 @@ type ApplyFieldSqlSpec<
118
118
  Spec extends FieldSqlSpecForState<State>,
119
119
  > =
120
120
  State extends ScalarFieldState<
121
- infer CodecId,
121
+ infer Descriptor,
122
122
  infer TypeRef,
123
123
  infer Nullable,
124
124
  infer ColumnName,
@@ -127,7 +127,7 @@ type ApplyFieldSqlSpec<
127
127
  infer Many
128
128
  >
129
129
  ? ScalarFieldState<
130
- CodecId,
130
+ Descriptor,
131
131
  TypeRef,
132
132
  Nullable,
133
133
  Spec extends { readonly column: infer NextColumn extends string } ? NextColumn : ColumnName,
@@ -158,7 +158,6 @@ function toColumnDefault(value: ColumnDefaultLiteralInputValue | ColumnDefault):
158
158
  return { kind: 'literal', value };
159
159
  }
160
160
 
161
- // Chaining methods use `as unknown as <ConditionalType>` because TypeScript cannot narrow generic conditional return types through object spread. The runtime values are correct — the casts bridge the gap between the spread result and the compile-time conditional type that encodes the state transition.
162
161
  export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFieldState> {
163
162
  declare readonly __state: State;
164
163
 
@@ -176,7 +175,7 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
176
175
 
177
176
  optional(): ScalarFieldBuilder<
178
177
  State extends ScalarFieldState<
179
- infer CodecId,
178
+ infer Descriptor,
180
179
  infer TypeRef,
181
180
  boolean,
182
181
  infer ColumnName,
@@ -184,30 +183,35 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
184
183
  infer UniqueSpec,
185
184
  infer Many
186
185
  >
187
- ? ScalarFieldState<CodecId, TypeRef, true, ColumnName, IdSpec, UniqueSpec, Many>
186
+ ? ScalarFieldState<Descriptor, TypeRef, true, ColumnName, IdSpec, UniqueSpec, Many>
188
187
  : AnyScalarFieldState
189
188
  > {
190
- return new ScalarFieldBuilder({
191
- ...this.state,
192
- nullable: true,
193
- } as unknown as State extends ScalarFieldState<
194
- infer CodecId,
195
- infer TypeRef,
196
- boolean,
197
- infer ColumnName,
198
- infer IdSpec,
199
- infer UniqueSpec,
200
- infer Many
201
- >
202
- ? ScalarFieldState<CodecId, TypeRef, true, ColumnName, IdSpec, UniqueSpec, Many>
203
- : AnyScalarFieldState);
189
+ return new ScalarFieldBuilder(
190
+ blindCast<
191
+ State extends ScalarFieldState<
192
+ infer Descriptor,
193
+ infer TypeRef,
194
+ boolean,
195
+ infer ColumnName,
196
+ infer IdSpec,
197
+ infer UniqueSpec,
198
+ infer Many
199
+ >
200
+ ? ScalarFieldState<Descriptor, TypeRef, true, ColumnName, IdSpec, UniqueSpec, Many>
201
+ : AnyScalarFieldState,
202
+ 'object spread does not narrow the generic State conditional; runtime shape is correct'
203
+ >({
204
+ ...this.state,
205
+ nullable: true,
206
+ }),
207
+ );
204
208
  }
205
209
 
206
210
  column<ColumnName extends string>(
207
211
  name: ColumnName,
208
212
  ): ScalarFieldBuilder<
209
213
  State extends ScalarFieldState<
210
- infer CodecId,
214
+ infer Descriptor,
211
215
  infer TypeRef,
212
216
  infer Nullable,
213
217
  string | undefined,
@@ -215,28 +219,33 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
215
219
  infer UniqueSpec,
216
220
  infer Many
217
221
  >
218
- ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, Many>
222
+ ? ScalarFieldState<Descriptor, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, Many>
219
223
  : AnyScalarFieldState
220
224
  > {
221
- return new ScalarFieldBuilder({
222
- ...this.state,
223
- columnName: name,
224
- } as unknown as State extends ScalarFieldState<
225
- infer CodecId,
226
- infer TypeRef,
227
- infer Nullable,
228
- string | undefined,
229
- infer IdSpec,
230
- infer UniqueSpec,
231
- infer Many
232
- >
233
- ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, Many>
234
- : AnyScalarFieldState);
225
+ return new ScalarFieldBuilder(
226
+ blindCast<
227
+ State extends ScalarFieldState<
228
+ infer Descriptor,
229
+ infer TypeRef,
230
+ infer Nullable,
231
+ string | undefined,
232
+ infer IdSpec,
233
+ infer UniqueSpec,
234
+ infer Many
235
+ >
236
+ ? ScalarFieldState<Descriptor, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, Many>
237
+ : AnyScalarFieldState,
238
+ 'object spread does not narrow the generic State conditional; runtime shape is correct'
239
+ >({
240
+ ...this.state,
241
+ columnName: name,
242
+ }),
243
+ );
235
244
  }
236
245
 
237
246
  many(): ScalarFieldBuilder<
238
247
  State extends ScalarFieldState<
239
- infer CodecId,
248
+ infer Descriptor,
240
249
  infer TypeRef,
241
250
  infer Nullable,
242
251
  infer ColumnName,
@@ -244,13 +253,13 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
244
253
  infer UniqueSpec,
245
254
  boolean
246
255
  >
247
- ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, true>
256
+ ? ScalarFieldState<Descriptor, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, true>
248
257
  : AnyScalarFieldState
249
258
  > {
250
259
  return new ScalarFieldBuilder(
251
260
  blindCast<
252
261
  State extends ScalarFieldState<
253
- infer CodecId,
262
+ infer Descriptor,
254
263
  infer TypeRef,
255
264
  infer Nullable,
256
265
  infer ColumnName,
@@ -258,7 +267,7 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
258
267
  infer UniqueSpec,
259
268
  boolean
260
269
  >
261
- ? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, true>
270
+ ? ScalarFieldState<Descriptor, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, true>
262
271
  : AnyScalarFieldState,
263
272
  'object spread does not narrow the generic State conditional; runtime shape is correct'
264
273
  >({
@@ -286,7 +295,7 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
286
295
  options?: NamedConstraintSpec<Name>,
287
296
  ): ScalarFieldBuilder<
288
297
  State extends ScalarFieldState<
289
- infer CodecId,
298
+ infer Descriptor,
290
299
  infer TypeRef,
291
300
  infer Nullable,
292
301
  infer ColumnName,
@@ -295,7 +304,7 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
295
304
  infer Many
296
305
  >
297
306
  ? ScalarFieldState<
298
- CodecId,
307
+ Descriptor,
299
308
  TypeRef,
300
309
  Nullable,
301
310
  ColumnName,
@@ -305,35 +314,40 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
305
314
  >
306
315
  : AnyScalarFieldState
307
316
  > {
308
- return new ScalarFieldBuilder({
309
- ...this.state,
310
- id: options?.name ? { name: options.name } : {},
311
- } as unknown as State extends ScalarFieldState<
312
- infer CodecId,
313
- infer TypeRef,
314
- infer Nullable,
315
- infer ColumnName,
316
- NamedConstraintSpec | undefined,
317
- infer UniqueSpec,
318
- infer Many
319
- >
320
- ? ScalarFieldState<
321
- CodecId,
322
- TypeRef,
323
- Nullable,
324
- ColumnName,
325
- NamedConstraintSpec<Name>,
326
- UniqueSpec,
327
- Many
317
+ return new ScalarFieldBuilder(
318
+ blindCast<
319
+ State extends ScalarFieldState<
320
+ infer Descriptor,
321
+ infer TypeRef,
322
+ infer Nullable,
323
+ infer ColumnName,
324
+ NamedConstraintSpec | undefined,
325
+ infer UniqueSpec,
326
+ infer Many
328
327
  >
329
- : AnyScalarFieldState);
328
+ ? ScalarFieldState<
329
+ Descriptor,
330
+ TypeRef,
331
+ Nullable,
332
+ ColumnName,
333
+ NamedConstraintSpec<Name>,
334
+ UniqueSpec,
335
+ Many
336
+ >
337
+ : AnyScalarFieldState,
338
+ 'object spread does not narrow the generic State conditional; runtime shape is correct'
339
+ >({
340
+ ...this.state,
341
+ id: options?.name ? { name: options.name } : {},
342
+ }),
343
+ );
330
344
  }
331
345
 
332
346
  unique<const Name extends string | undefined = undefined>(
333
347
  options?: NamedConstraintSpec<Name>,
334
348
  ): ScalarFieldBuilder<
335
349
  State extends ScalarFieldState<
336
- infer CodecId,
350
+ infer Descriptor,
337
351
  infer TypeRef,
338
352
  infer Nullable,
339
353
  infer ColumnName,
@@ -342,7 +356,7 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
342
356
  infer Many
343
357
  >
344
358
  ? ScalarFieldState<
345
- CodecId,
359
+ Descriptor,
346
360
  TypeRef,
347
361
  Nullable,
348
362
  ColumnName,
@@ -352,28 +366,33 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
352
366
  >
353
367
  : AnyScalarFieldState
354
368
  > {
355
- return new ScalarFieldBuilder({
356
- ...this.state,
357
- unique: options?.name ? { name: options.name } : {},
358
- } as unknown as State extends ScalarFieldState<
359
- infer CodecId,
360
- infer TypeRef,
361
- infer Nullable,
362
- infer ColumnName,
363
- infer IdSpec,
364
- NamedConstraintSpec | undefined,
365
- infer Many
366
- >
367
- ? ScalarFieldState<
368
- CodecId,
369
- TypeRef,
370
- Nullable,
371
- ColumnName,
372
- IdSpec,
373
- NamedConstraintSpec<Name>,
374
- Many
369
+ return new ScalarFieldBuilder(
370
+ blindCast<
371
+ State extends ScalarFieldState<
372
+ infer Descriptor,
373
+ infer TypeRef,
374
+ infer Nullable,
375
+ infer ColumnName,
376
+ infer IdSpec,
377
+ NamedConstraintSpec | undefined,
378
+ infer Many
375
379
  >
376
- : AnyScalarFieldState);
380
+ ? ScalarFieldState<
381
+ Descriptor,
382
+ TypeRef,
383
+ Nullable,
384
+ ColumnName,
385
+ IdSpec,
386
+ NamedConstraintSpec<Name>,
387
+ Many
388
+ >
389
+ : AnyScalarFieldState,
390
+ 'object spread does not narrow the generic State conditional; runtime shape is correct'
391
+ >({
392
+ ...this.state,
393
+ unique: options?.name ? { name: options.name } : {},
394
+ }),
395
+ );
377
396
  }
378
397
 
379
398
  sql<const Spec extends FieldSqlSpecForState<State>>(
@@ -391,12 +410,17 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
391
410
  );
392
411
  }
393
412
 
394
- return new ScalarFieldBuilder({
395
- ...this.state,
396
- ...(spec.column ? { columnName: spec.column } : {}),
397
- ...(idSpec ? { id: { name: idSpec.name } } : {}),
398
- ...(uniqueSpec ? { unique: { name: uniqueSpec.name } } : {}),
399
- } as unknown as ApplyFieldSqlSpec<State, Spec>);
413
+ return new ScalarFieldBuilder(
414
+ blindCast<
415
+ ApplyFieldSqlSpec<State, Spec>,
416
+ 'conditional object spread does not narrow ApplyFieldSqlSpec; runtime shape is correct'
417
+ >({
418
+ ...this.state,
419
+ ...(spec.column ? { columnName: spec.column } : {}),
420
+ ...(idSpec ? { id: { name: idSpec.name } } : {}),
421
+ ...(uniqueSpec ? { unique: { name: uniqueSpec.name } } : {}),
422
+ }),
423
+ );
400
424
  }
401
425
 
402
426
  build(): State {
@@ -406,7 +430,12 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
406
430
 
407
431
  export class EnumScalarFieldBuilder<
408
432
  Handle extends EnumTypeHandle,
409
- State extends AnyScalarFieldState = ScalarFieldState<Handle['codecId'], Handle, false, undefined>,
433
+ State extends AnyScalarFieldState = ScalarFieldState<
434
+ ColumnTypeDescriptor,
435
+ Handle,
436
+ false,
437
+ undefined
438
+ >,
410
439
  > extends ScalarFieldBuilder<State> {
411
440
  readonly #handle: Handle;
412
441
 
@@ -436,7 +465,7 @@ export class EnumScalarFieldBuilder<
436
465
 
437
466
  function columnField<Descriptor extends ColumnTypeDescriptor>(
438
467
  descriptor: Descriptor,
439
- ): ScalarFieldBuilder<ScalarFieldState<Descriptor['codecId'], undefined, false, undefined>> {
468
+ ): ScalarFieldBuilder<ScalarFieldState<Descriptor, undefined, false, undefined>> {
440
469
  return new ScalarFieldBuilder({
441
470
  kind: 'scalar',
442
471
  descriptor,
@@ -446,7 +475,7 @@ function columnField<Descriptor extends ColumnTypeDescriptor>(
446
475
 
447
476
  function generatedField<Descriptor extends ColumnTypeDescriptor>(
448
477
  spec: GeneratedFieldSpec & { readonly type: Descriptor },
449
- ): ScalarFieldBuilder<ScalarFieldState<Descriptor['codecId'], undefined, false, undefined>> {
478
+ ): ScalarFieldBuilder<ScalarFieldState<Descriptor, undefined, false, undefined>> {
450
479
  return new ScalarFieldBuilder({
451
480
  kind: 'scalar',
452
481
  descriptor: {
@@ -460,10 +489,12 @@ function generatedField<Descriptor extends ColumnTypeDescriptor>(
460
489
 
461
490
  function namedTypeField<TypeRef extends string>(
462
491
  typeRef: TypeRef,
463
- ): ScalarFieldBuilder<ScalarFieldState<string, TypeRef, false, undefined>>;
492
+ ): ScalarFieldBuilder<ScalarFieldState<ColumnTypeDescriptor, TypeRef, false, undefined>>;
464
493
  function namedTypeField<TypeRef extends StorageTypeInstance>(
465
494
  typeRef: TypeRef,
466
- ): ScalarFieldBuilder<ScalarFieldState<TypeRef['codecId'], TypeRef, false, undefined>>;
495
+ ): ScalarFieldBuilder<
496
+ ScalarFieldState<ColumnTypeDescriptor<TypeRef['codecId']>, TypeRef, false, undefined>
497
+ >;
467
498
  function namedTypeField<Handle extends EnumTypeHandle>(
468
499
  typeRef: Handle,
469
500
  ): EnumScalarFieldBuilder<Handle>;
@@ -471,7 +502,7 @@ function namedTypeField(typeRef: NamedStorageTypeRef): ScalarFieldBuilder {
471
502
  if (isEnumTypeHandle(typeRef)) {
472
503
  return new EnumScalarFieldBuilder(
473
504
  blindCast<
474
- ScalarFieldState<string, typeof typeRef, false, undefined>,
505
+ ScalarFieldState<ColumnTypeDescriptor, typeof typeRef, false, undefined>,
475
506
  'literal object lacks explicit many; cast to the full ScalarFieldState so optional() conditional resolves Many = false'
476
507
  >({
477
508
  kind: 'scalar',
@@ -695,6 +695,31 @@ type EnumValueUnion<FieldState> = [FieldTypeRefOf<FieldState>] extends [
695
695
  : Values[number]
696
696
  : never;
697
697
 
698
+ // The member-value literal tuple carried on a descriptor's `entityRef.entity`
699
+ // (e.g. a target's native-enum entity), or `never` when the descriptor has no
700
+ // entityRef, its entity has no `members`, or `members` is widened to
701
+ // `readonly string[]` — this is checked with non-optional property shapes so
702
+ // a descriptor genuinely lacking `entityRef` fails the structural match
703
+ // instead of matching vacuously through the framework type's optional slot.
704
+ type DescriptorEntityMembers<Descriptor> = Descriptor extends {
705
+ readonly entityRef: {
706
+ readonly entity: { readonly members: infer Members extends readonly string[] };
707
+ };
708
+ }
709
+ ? Members
710
+ : never;
711
+
712
+ // The value-set member union for a descriptor-carried entity (the type-level
713
+ // mirror of the runtime's generic `deriveValueSetFromEntity` fold), or
714
+ // `never` for a field with no descriptor, a descriptor with no entityRef.entity,
715
+ // or a widened (non-literal) members tuple — mirroring `EnumValueUnion`'s
716
+ // erasure guard.
717
+ type DescriptorValueSetUnion<FieldState> = [FieldDescriptorOf<FieldState>] extends [never]
718
+ ? never
719
+ : readonly string[] extends DescriptorEntityMembers<FieldDescriptorOf<FieldState>>
720
+ ? never
721
+ : DescriptorEntityMembers<FieldDescriptorOf<FieldState>>[number];
722
+
698
723
  // The codec's `output` / `input` JS type for a field's column, before
699
724
  // nullability. `unknown` when the codec is not in the definition's codec map.
700
725
  type CodecChannelType<
@@ -711,19 +736,27 @@ type CodecChannelType<
711
736
  : unknown
712
737
  : unknown;
713
738
 
714
- // A field's read/write JS type: the enum value union when the field is
715
- // enum-typed, otherwise the codec channel type, with column nullability applied.
739
+ // The literal value union for a field: the enum-typed union takes precedence
740
+ // (matching today's behavior), falling back to the descriptor-carried
741
+ // value-set union; `never` when neither applies.
742
+ type FieldValueUnion<FieldState> = [EnumValueUnion<FieldState>] extends [never]
743
+ ? DescriptorValueSetUnion<FieldState>
744
+ : EnumValueUnion<FieldState>;
745
+
746
+ // A field's read/write JS type: the value union (enum or descriptor value-set)
747
+ // when the field carries one, otherwise the codec channel type, with column
748
+ // nullability applied.
716
749
  type FieldChannelType<
717
750
  Definition,
718
751
  ModelName extends ModelNames<Definition>,
719
752
  FieldName extends ModelFieldNames<Definition, ModelName>,
720
753
  Channel extends 'output' | 'input',
721
754
  > =
722
- | ([EnumValueUnion<ModelFieldState<Definition, ModelName, FieldName>>] extends [never]
755
+ | ([FieldValueUnion<ModelFieldState<Definition, ModelName, FieldName>>] extends [never]
723
756
  ? CodecChannelType<Definition, ModelName, FieldName, Channel>
724
757
  : StorageColumnManyOf<ModelStorageColumn<Definition, ModelName, FieldName>> extends true
725
- ? ReadonlyArray<EnumValueUnion<ModelFieldState<Definition, ModelName, FieldName>>>
726
- : EnumValueUnion<ModelFieldState<Definition, ModelName, FieldName>>)
758
+ ? ReadonlyArray<FieldValueUnion<ModelFieldState<Definition, ModelName, FieldName>>>
759
+ : FieldValueUnion<ModelFieldState<Definition, ModelName, FieldName>>)
727
760
  | (FieldNullableOf<ModelFieldState<Definition, ModelName, FieldName>> extends true
728
761
  ? null
729
762
  : never);