@prisma-next/sql-contract-ts 0.14.0-dev.80 → 0.14.0-dev.82

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.80",
3
+ "version": "0.14.0-dev.82",
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.80",
10
- "@prisma-next/contract": "0.14.0-dev.80",
11
- "@prisma-next/contract-authoring": "0.14.0-dev.80",
12
- "@prisma-next/framework-components": "0.14.0-dev.80",
13
- "@prisma-next/sql-contract": "0.14.0-dev.80",
14
- "@prisma-next/utils": "0.14.0-dev.80",
9
+ "@prisma-next/config": "0.14.0-dev.82",
10
+ "@prisma-next/contract": "0.14.0-dev.82",
11
+ "@prisma-next/contract-authoring": "0.14.0-dev.82",
12
+ "@prisma-next/framework-components": "0.14.0-dev.82",
13
+ "@prisma-next/sql-contract": "0.14.0-dev.82",
14
+ "@prisma-next/utils": "0.14.0-dev.82",
15
15
  "arktype": "^2.2.2",
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.80",
21
- "@prisma-next/tsconfig": "0.14.0-dev.80",
20
+ "@prisma-next/test-utils": "0.14.0-dev.82",
21
+ "@prisma-next/tsconfig": "0.14.0-dev.82",
22
22
  "@types/pg": "8.20.0",
23
23
  "pg": "8.22.0",
24
- "@prisma-next/tsdown": "0.14.0-dev.80",
24
+ "@prisma-next/tsdown": "0.14.0-dev.82",
25
25
  "tsdown": "0.22.3",
26
26
  "typescript": "5.9.3",
27
27
  "vitest": "4.1.10"
@@ -281,14 +281,14 @@ function qualifyColumnDescriptor(
281
281
  };
282
282
  }
283
283
 
284
- type CollectedPackEntities = Record<string, Record<string, Record<string, unknown>>>;
284
+ type CollectedColumnEntities = Record<string, Record<string, Record<string, unknown>>>;
285
285
 
286
286
  /**
287
287
  * Records a deferred column's entity-ref into the namespace-scoped collection
288
- * accumulator, keyed the same way author-declared `packEntities` are
289
- * (`namespaceId entityKind → entityName`) folded into the same namespace
290
- * assembly `derivePackEntityValueSets`/`entries.<kind>` step, so a collected
291
- * entity gets its value-set the same way an author-declared one does.
288
+ * accumulator (`namespaceId entityKind entityName`) — folded into the same
289
+ * namespace assembly `deriveEntityValueSets`/`entries.<kind>` step as the
290
+ * entities-channel attachments, so a column-collected entity gets its
291
+ * value-set the same way an entities-channel one does.
292
292
  *
293
293
  * The same handle reused by many columns in one namespace is normal (a native
294
294
  * enum type backs any number of columns) and records the identical entity once.
@@ -297,8 +297,8 @@ type CollectedPackEntities = Record<string, Record<string, Record<string, unknow
297
297
  * of them, silently mismatching the other column's type/cast. PSL hard-errors
298
298
  * on the equivalent (`PSL_DUPLICATE_DECLARATION`); the TS path rejects it too.
299
299
  */
300
- function collectPackEntityFromColumn(
301
- collected: CollectedPackEntities,
300
+ function collectEntityFromColumn(
301
+ collected: CollectedColumnEntities,
302
302
  namespaceId: string,
303
303
  entityRef: NonNullable<ColumnTypeDescriptor['entityRef']>,
304
304
  ): void {
@@ -316,34 +316,36 @@ function collectPackEntityFromColumn(
316
316
  }
317
317
 
318
318
  /**
319
- * Merges the author-declared `packEntities` for one namespace with the entities
320
- * collected from that namespace's deferred entity-ref columns. A collected
321
- * entity that shadows a *different* declared entity of the same kind+name (or
322
- * vice-versa) is the same name-collision bug `collectPackEntityFromColumn`
323
- * guards against across columns, so it is rejected the same way — by entity
324
- * identity, so the same handle declared and used by a column does not throw.
319
+ * Merges a namespace's entities-channel attachments (lowered from the
320
+ * `entities` handle list, carried on `ContractDefinition.attachedEntities`)
321
+ * with the entities collected from that namespace's deferred entity-ref
322
+ * columns. A column-collected entity that shadows a *different* attached
323
+ * entity of the same kind+name (or vice-versa) is the same name-collision bug
324
+ * `collectEntityFromColumn` guards against across columns, so it is rejected
325
+ * the same way — by entity identity, so the same handle attached and used by
326
+ * a column does not throw.
325
327
  */
326
- function mergeCollectedPackEntities(
328
+ function mergeColumnAndAttachedEntities(
327
329
  namespaceId: string,
328
- declared: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined,
329
- collected: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined,
330
+ attached: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined,
331
+ columnCollected: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined,
330
332
  ): Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined {
331
- if (declared === undefined) return collected;
332
- if (collected === undefined) return declared;
333
- const kinds = new Set([...Object.keys(declared), ...Object.keys(collected)]);
333
+ if (attached === undefined) return columnCollected;
334
+ if (columnCollected === undefined) return attached;
335
+ const kinds = new Set([...Object.keys(attached), ...Object.keys(columnCollected)]);
334
336
  const result: Record<string, Readonly<Record<string, unknown>>> = {};
335
337
  for (const kind of kinds) {
336
- const declaredForKind = declared[kind];
337
- const collectedForKind = collected[kind];
338
- for (const [name, entity] of Object.entries(collectedForKind ?? {})) {
339
- const existing = declaredForKind?.[name];
338
+ const attachedForKind = attached[kind];
339
+ const columnForKind = columnCollected[kind];
340
+ for (const [name, entity] of Object.entries(columnForKind ?? {})) {
341
+ const existing = attachedForKind?.[name];
340
342
  if (existing !== undefined && existing !== entity) {
341
343
  throw new Error(
342
- `buildSqlContractFromDefinition: two different "${kind}" entities named "${name}" in namespace "${namespaceId}" — a collected pack entity conflicts with an author-declared one; pack-entity names must be unique per namespace.`,
344
+ `buildSqlContractFromDefinition: two different "${kind}" entities named "${name}" in namespace "${namespaceId}" — a column-referenced entity conflicts with an attached one; pack-entity names must be unique per namespace.`,
343
345
  );
344
346
  }
345
347
  }
346
- result[kind] = { ...declaredForKind, ...collectedForKind };
348
+ result[kind] = { ...attachedForKind, ...columnForKind };
347
349
  }
348
350
  return result;
349
351
  }
@@ -486,7 +488,7 @@ function collectStorageNamespaceCoordinateIds(definition: ContractDefinition): S
486
488
  ids.add(model.namespaceId);
487
489
  }
488
490
  }
489
- for (const id of Object.keys(definition.packEntities ?? {})) {
491
+ for (const id of Object.keys(definition.attachedEntities ?? {})) {
490
492
  if (id.length > 0) {
491
493
  ids.add(id);
492
494
  }
@@ -496,21 +498,21 @@ function collectStorageNamespaceCoordinateIds(definition: ContractDefinition): S
496
498
 
497
499
  /**
498
500
  * Entry kinds the framework assembler itself manages (`table` from models,
499
- * `valueSet` from `enums` and pack-entity value-set derivation). An
500
- * author-declared pack entity claiming one of these would silently clobber
501
- * or be clobbered by the managed slot, so it is rejected outright.
501
+ * `valueSet` from `enums` and attached-entity value-set derivation). A
502
+ * pack-attached entity claiming one of these would silently clobber or be
503
+ * clobbered by the managed slot, so it is rejected outright.
502
504
  */
503
505
  const MANAGED_ENTRY_KINDS = new Set([tableEntityKind.kind, valueSetEntityKind.kind]);
504
506
 
505
- function assertNoManagedPackEntityKinds(
507
+ function assertNoManagedEntityKinds(
506
508
  namespaceId: string,
507
- packEntitiesForNs: Readonly<Record<string, unknown>> | undefined,
509
+ entitiesForNs: Readonly<Record<string, unknown>> | undefined,
508
510
  ): void {
509
- if (packEntitiesForNs === undefined) return;
510
- for (const kind of Object.keys(packEntitiesForNs)) {
511
+ if (entitiesForNs === undefined) return;
512
+ for (const kind of Object.keys(entitiesForNs)) {
511
513
  if (MANAGED_ENTRY_KINDS.has(kind)) {
512
514
  throw new Error(
513
- `buildSqlContractFromDefinition: packEntities in namespace "${namespaceId}" declares entry kind "${kind}", which is managed by the framework (table/valueSet) and cannot be supplied via packEntities.`,
515
+ `buildSqlContractFromDefinition: attached entity in namespace "${namespaceId}" declares entry kind "${kind}", which is managed by the framework (table/valueSet) and cannot be attached.`,
514
516
  );
515
517
  }
516
518
  }
@@ -557,13 +559,13 @@ function collectEntityTypeDescriptorsByDiscriminator(
557
559
  * registered descriptor, or whose descriptor output doesn't derive a
558
560
  * value-set, contribute nothing.
559
561
  */
560
- function derivePackEntityValueSets(
561
- packEntitiesForNs: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined,
562
+ function deriveEntityValueSets(
563
+ entitiesForNs: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined,
562
564
  entityTypesByDiscriminator: ReadonlyMap<string, AuthoringEntityTypeDescriptor>,
563
565
  ): Record<string, StorageValueSetInput> | undefined {
564
- if (packEntitiesForNs === undefined) return undefined;
566
+ if (entitiesForNs === undefined) return undefined;
565
567
  let result: Record<string, StorageValueSetInput> | undefined;
566
- for (const [kind, entitiesByName] of Object.entries(packEntitiesForNs)) {
568
+ for (const [kind, entitiesByName] of Object.entries(entitiesForNs)) {
567
569
  const descriptor = entityTypesByDiscriminator.get(kind);
568
570
  if (descriptor === undefined) continue;
569
571
  for (const [name, entity] of Object.entries(entitiesByName)) {
@@ -582,7 +584,7 @@ function derivePackEntityValueSets(
582
584
  * which drives value-set → codec typing and the domain-enum CHECK — so a
583
585
  * same-named entry in both would let one silently overwrite the other and
584
586
  * corrupt whichever column resolves against it. The same collision class the
585
- * `mergeCollectedPackEntities` guard rejects; the PSL path already hard-errors
587
+ * `mergeColumnAndAttachedEntities` guard rejects; the PSL path already hard-errors
586
588
  * on the equivalent (`interpretPslDocumentToSqlContract`). Reject it here too.
587
589
  */
588
590
  function mergeNamespaceValueSets(
@@ -645,7 +647,7 @@ export function buildSqlContractFromDefinition(
645
647
  const modelNameToNamespaceId = new Map<string, string>();
646
648
  const executionDefaults: ExecutionMutationDefault[] = [];
647
649
  const modelsByNamespace: Record<string, Record<string, ContractModel>> = {};
648
- const collectedPackEntities: CollectedPackEntities = {};
650
+ const collectedColumnEntities: CollectedColumnEntities = {};
649
651
  const rootEntries: Array<{
650
652
  readonly tableName: string;
651
653
  readonly namespaceId: string;
@@ -720,9 +722,9 @@ export function buildSqlContractFromDefinition(
720
722
 
721
723
  // A field authored through a deferred entity-ref column helper (e.g.
722
724
  // `pg.enum(handle)`) carries `descriptor.entityRef`: the referenced
723
- // entity is collected into `collectedPackEntities` (folded into the
724
- // same `entries.<kind>` + `entries.valueSet` assembly an author-declared
725
- // `packEntities` entry goes through) and the descriptor is resolved
725
+ // entity is collected into `collectedColumnEntities` (folded into the
726
+ // same `entries.<kind>` + `entries.valueSet` assembly an entities-channel
727
+ // attachment goes through) and the descriptor is resolved
726
728
  // against this field's now-known `namespaceId` — the builder call that
727
729
  // produced it ran before the enclosing model associated one. The
728
730
  // descriptor is then handed to the target's `qualifyColumnType` hook,
@@ -738,7 +740,7 @@ export function buildSqlContractFromDefinition(
738
740
  let descriptor = field.descriptor;
739
741
  const entityRef = descriptor.entityRef;
740
742
  if (entityRef !== undefined) {
741
- collectPackEntityFromColumn(collectedPackEntities, namespaceId, entityRef);
743
+ collectEntityFromColumn(collectedColumnEntities, namespaceId, entityRef);
742
744
  descriptor = resolveEntityRefDescriptor(descriptor, namespaceId);
743
745
  }
744
746
  descriptor = qualifyColumnDescriptor(descriptor, namespaceId, qualifyColumnType);
@@ -1072,18 +1074,15 @@ export function buildSqlContractFromDefinition(
1072
1074
  const entityTypesByDiscriminator = collectEntityTypeDescriptorsByDiscriminator(definition);
1073
1075
  const namespaces: SqlStorageInput['namespaces'] = Object.fromEntries(
1074
1076
  [...namespaceCoordinateIds].sort().map((id) => {
1075
- const packEntitiesForNs = mergeCollectedPackEntities(
1077
+ const entitiesForNs = mergeColumnAndAttachedEntities(
1076
1078
  id,
1077
- definition.packEntities?.[id],
1078
- collectedPackEntities[id],
1079
+ definition.attachedEntities?.[id],
1080
+ collectedColumnEntities[id],
1079
1081
  );
1080
- assertNoManagedPackEntityKinds(id, packEntitiesForNs);
1082
+ assertNoManagedEntityKinds(id, entitiesForNs);
1081
1083
 
1082
1084
  const enumValueSetEntries = storageValueSetsByNs[id];
1083
- const packValueSetEntries = derivePackEntityValueSets(
1084
- packEntitiesForNs,
1085
- entityTypesByDiscriminator,
1086
- );
1085
+ const packValueSetEntries = deriveEntityValueSets(entitiesForNs, entityTypesByDiscriminator);
1087
1086
  const valueSetEntries =
1088
1087
  enumValueSetEntries !== undefined || packValueSetEntries !== undefined
1089
1088
  ? mergeNamespaceValueSets(id, enumValueSetEntries, packValueSetEntries)
@@ -1093,7 +1092,7 @@ export function buildSqlContractFromDefinition(
1093
1092
  id,
1094
1093
  entries: {
1095
1094
  table: tablesByNamespace[id] ?? {},
1096
- ...packEntitiesForNs,
1095
+ ...entitiesForNs,
1097
1096
  ...(valueSetEntries !== undefined && Object.keys(valueSetEntries).length > 0
1098
1097
  ? { valueSet: valueSetEntries }
1099
1098
  : {}),
@@ -6,6 +6,7 @@ import type {
6
6
  FamilyPackRef,
7
7
  TargetPackRef,
8
8
  } from '@prisma-next/framework-components/components';
9
+ import type { PackEntityHandle } from '@prisma-next/sql-contract/entity-handle-lowering-hook';
9
10
  import type {
10
11
  SqlNamespaceBase,
11
12
  SqlNamespaceInput,
@@ -18,7 +19,6 @@ import {
18
19
  type ComposedAuthoringHelpers,
19
20
  createComposedAuthoringHelpers,
20
21
  } from './composed-authoring-helpers';
21
- import type { PackEntitiesInput } from './contract-definition';
22
22
  import {
23
23
  type ContractInput,
24
24
  type ContractModelBuilder,
@@ -77,7 +77,7 @@ type ContractDefinition<
77
77
  readonly models?: Models;
78
78
  readonly codecLookup?: CodecLookup;
79
79
  readonly enums?: Enums;
80
- readonly packEntities?: PackEntitiesInput;
80
+ readonly entities?: readonly PackEntityHandle[];
81
81
  };
82
82
 
83
83
  type ContractScaffold<
@@ -103,7 +103,7 @@ type ContractScaffold<
103
103
  readonly models?: never;
104
104
  readonly codecLookup?: CodecLookup;
105
105
  readonly enums?: Enums;
106
- readonly packEntities?: PackEntitiesInput;
106
+ readonly entities?: readonly PackEntityHandle[];
107
107
  };
108
108
 
109
109
  type ContractFactory<
@@ -117,7 +117,7 @@ type ContractFactory<
117
117
  readonly types?: Types;
118
118
  readonly models?: Models;
119
119
  readonly enums?: Enums;
120
- readonly packEntities?: PackEntitiesInput;
120
+ readonly entities?: readonly PackEntityHandle[];
121
121
  };
122
122
 
123
123
  function validateTargetPackRef(
@@ -326,7 +326,7 @@ type BoundDefinitionInput<
326
326
  readonly models?: Models;
327
327
  readonly codecLookup?: CodecLookup;
328
328
  readonly enums?: Record<string, EnumTypeHandle>;
329
- readonly packEntities?: PackEntitiesInput;
329
+ readonly entities?: readonly PackEntityHandle[];
330
330
  };
331
331
 
332
332
  // A bare `Record<string, EnumTypeHandle>` (no literal keys) is the widened
@@ -350,60 +350,6 @@ type WithFamilyTarget<
350
350
  T extends TargetPackRef<'sql', string>,
351
351
  > = Input & { readonly family: F; readonly target: T };
352
352
 
353
- // Deep-merges packEntities authored on the scaffold definition with those
354
- // returned from the factory callback — three levels deep (namespace, kind,
355
- // name), unlike `enums`' flat shallow merge, since a factory-declared
356
- // namespace/kind must not silently drop a scaffold-declared sibling entry
357
- // under the same namespace or kind. A same-name key present on both sides is
358
- // only merged when it is the identical entity instance; two *different*
359
- // entities of the same namespace/kind/name is a collision (the emitted
360
- // entry could reflect only one), rejected here the same way
361
- // `mergeCollectedPackEntities` in `build-contract.ts` rejects it.
362
- function mergePackEntityNames(
363
- namespaceId: string,
364
- kind: string,
365
- a: Readonly<Record<string, unknown>> | undefined,
366
- b: Readonly<Record<string, unknown>> | undefined,
367
- ): Readonly<Record<string, unknown>> {
368
- if (a !== undefined && b !== undefined) {
369
- for (const [name, entity] of Object.entries(b)) {
370
- const existing = a[name];
371
- if (existing !== undefined && existing !== entity) {
372
- throw new Error(
373
- `defineContract: two different "${kind}" entities named "${name}" in namespace "${namespaceId}" — a factory-returned pack entity conflicts with a scaffold-declared one; pack-entity names must be unique per namespace.`,
374
- );
375
- }
376
- }
377
- }
378
- return { ...(a ?? {}), ...(b ?? {}) };
379
- }
380
-
381
- function mergePackEntityKinds(
382
- namespaceId: string,
383
- a: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined,
384
- b: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined,
385
- ): Readonly<Record<string, Readonly<Record<string, unknown>>>> {
386
- const kinds = new Set([...Object.keys(a ?? {}), ...Object.keys(b ?? {})]);
387
- const result: Record<string, Readonly<Record<string, unknown>>> = {};
388
- for (const kind of kinds) {
389
- result[kind] = mergePackEntityNames(namespaceId, kind, a?.[kind], b?.[kind]);
390
- }
391
- return result;
392
- }
393
-
394
- function mergePackEntities(
395
- a: PackEntitiesInput | undefined,
396
- b: PackEntitiesInput | undefined,
397
- ): PackEntitiesInput | undefined {
398
- if (a === undefined && b === undefined) return undefined;
399
- const namespaces = new Set([...Object.keys(a ?? {}), ...Object.keys(b ?? {})]);
400
- const result: Record<string, Readonly<Record<string, Readonly<Record<string, unknown>>>>> = {};
401
- for (const namespaceId of namespaces) {
402
- result[namespaceId] = mergePackEntityKinds(namespaceId, a?.[namespaceId], b?.[namespaceId]);
403
- }
404
- return result;
405
- }
406
-
407
353
  /**
408
354
  * Shared builder that assembles a SqlContract with pre-bound family and target.
409
355
  * Extension wrappers keep their own public overloads and delegate their impl body here;
@@ -449,7 +395,7 @@ export function buildBoundContract<
449
395
  readonly types?: Record<string, StorageTypeInstance>;
450
396
  readonly models?: Record<string, ModelLike>;
451
397
  readonly enums?: Record<string, EnumTypeHandle>;
452
- readonly packEntities?: PackEntitiesInput;
398
+ readonly entities?: readonly PackEntityHandle[];
453
399
  },
454
400
  >(
455
401
  family: F,
@@ -475,7 +421,7 @@ export function buildBoundContract(
475
421
  readonly types?: Record<string, StorageTypeInstance>;
476
422
  readonly models?: Record<string, ModelLike>;
477
423
  readonly enums?: Record<string, EnumTypeHandle>;
478
- readonly packEntities?: PackEntitiesInput;
424
+ readonly entities?: readonly PackEntityHandle[];
479
425
  })
480
426
  | undefined,
481
427
  ) {
@@ -490,13 +436,13 @@ export function buildBoundContract(
490
436
  }),
491
437
  );
492
438
  const mergedEnums = { ...(definition.enums ?? {}), ...built.enums };
493
- const mergedPackEntities = mergePackEntities(definition.packEntities, built.packEntities);
439
+ const mergedEntities = [...(definition.entities ?? []), ...(built.entities ?? [])];
494
440
  return buildContractFromDsl({
495
441
  ...full,
496
442
  ...ifDefined('types', built.types),
497
443
  ...ifDefined('models', built.models),
498
444
  ...ifDefined('enums', Object.keys(mergedEnums).length > 0 ? mergedEnums : undefined),
499
- ...ifDefined('packEntities', mergedPackEntities),
445
+ ...ifDefined('entities', mergedEntities.length > 0 ? mergedEntities : undefined),
500
446
  });
501
447
  }
502
448
 
@@ -17,16 +17,19 @@ import type { EnumTypeHandle } from './enum-type';
17
17
  export type { ExecutionMutationDefaultPhases };
18
18
 
19
19
  /**
20
- * An author-declared, namespace-scoped pack entity attachment: namespace id
21
- * entity kind (the discriminator the target/extension pack registered its
20
+ * Namespace-scoped pack-entity attachments, the internal build IR carrying
21
+ * the lowered `entities` handle list: namespace id entity kind (the
22
+ * discriminator the target/extension pack registered its
22
23
  * `AuthoringContributions.entityTypes` descriptor under, e.g. `native_enum`)
23
24
  * → entity name → the lowered entity instance. Generic on purpose — neither
24
25
  * the framework nor `contract-ts` names a specific entity kind here; the
25
26
  * shape mirrors `SqlNamespaceInput.entries` (`entries.<kind>[name]`), just
26
- * namespace-nested so an author can target any declared namespace (default
27
- * or named), not only the contract's default namespace.
27
+ * namespace-nested so an attachment can target any declared namespace
28
+ * (default or named), not only the contract's default namespace. Produced by
29
+ * the generic entity-handle walk in `buildContractDefinition`; never an
30
+ * author-facing input.
28
31
  */
29
- export type PackEntitiesInput = Readonly<
32
+ export type AttachedEntities = Readonly<
30
33
  Record<string, Readonly<Record<string, Readonly<Record<string, unknown>>>>>
31
34
  >;
32
35
 
@@ -200,12 +203,14 @@ export interface ContractDefinition {
200
203
  */
201
204
  readonly enums?: Record<string, EnumTypeHandle>;
202
205
  /**
203
- * Author-declared pack entities, keyed by namespace then entity kind then
204
- * name. Each entity lowers into `storage.namespaces[ns].entries.<kind>`;
205
- * when the registered entity-type descriptor's factory output implements
206
- * the `SqlValueSetDerivingEntityTypeOutput.deriveValueSet` hook, the
207
- * derived value-set also folds into `entries.valueSet`, mirroring how
208
- * `enums` flows there.
206
+ * Pack-entity attachments lowered from the `entities` handle list, keyed by
207
+ * namespace then entity kind then name. Each entity lands in
208
+ * `storage.namespaces[ns].entries.<kind>`; when the registered entity-type
209
+ * descriptor's factory output implements the
210
+ * `SqlValueSetDerivingEntityTypeOutput.deriveValueSet` hook, the derived
211
+ * value-set also folds into `entries.valueSet`, mirroring how `enums` flows
212
+ * there. Internal build IR — populated by `buildContractDefinition`, not an
213
+ * author input.
209
214
  */
210
- readonly packEntities?: PackEntitiesInput;
215
+ readonly attachedEntities?: AttachedEntities;
211
216
  }
@@ -1615,14 +1615,14 @@ export type ContractInput<
1615
1615
  */
1616
1616
  readonly enums?: Record<string, import('./enum-type').EnumTypeHandle>;
1617
1617
  /**
1618
- * Author-declared pack entities, keyed by namespace id then entity kind
1619
- * then name — e.g. `{ auth: { native_enum: { AalLevel: <entity> } } }`.
1620
- * Each entity lowers into `storage.namespaces[ns].entries.<kind>`; when its
1621
- * registered entity-type descriptor derives a value-set, that also folds
1622
- * into `entries.valueSet`, mirroring how `enums` flows there. Generic on
1623
- * purpose neither this type nor the assembler names a specific kind.
1618
+ * Author-declared pack-entity handles, lowered by the pack that registered
1619
+ * each handle's `entityKind` (through the SQL-family batch lowering hook)
1620
+ * into namespace-scoped entry attachments at build time. Generic on
1621
+ * purpose — neither this type nor the walk names a specific kind; a handle
1622
+ * whose kind no composed pack registers is a build error. This is the only
1623
+ * public channel for attaching pack entities.
1624
1624
  */
1625
- readonly packEntities?: import('./contract-definition').PackEntitiesInput;
1625
+ readonly entities?: readonly import('@prisma-next/sql-contract/entity-handle-lowering-hook').PackEntityHandle[];
1626
1626
  };
1627
1627
 
1628
1628
  export function model<
@@ -1744,7 +1744,7 @@ type CrossSpaceHandle = {
1744
1744
  readonly stageOne: { readonly namespace?: string };
1745
1745
  };
1746
1746
 
1747
- function isCrossSpaceHandle(value: unknown): value is CrossSpaceHandle {
1747
+ export function isCrossSpaceHandle(value: unknown): value is CrossSpaceHandle {
1748
1748
  if (typeof value !== 'object' || value === null) {
1749
1749
  return false;
1750
1750
  }