@aventara/prisma7-adapter 0.1.0-pilot.2 → 0.1.0-pilot.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +22 -22
  2. package/dist/discovery/artifact.loader.d.ts +2 -7
  3. package/dist/discovery/artifact.loader.js +4 -0
  4. package/dist/discovery/capability-surface.interface.d.ts +2 -66
  5. package/dist/discovery/capability.deriver.d.ts +2 -47
  6. package/dist/discovery/discovery-artifact.interface.d.ts +34 -155
  7. package/dist/discovery/discovery-artifact.interface.js +1 -1
  8. package/dist/discovery/enum.mapper.d.ts +0 -24
  9. package/dist/discovery/field.mapper.d.ts +3 -114
  10. package/dist/discovery/field.mapper.js +6 -6
  11. package/dist/discovery/identifier.mapper.d.ts +4 -84
  12. package/dist/discovery/model.discoverer.d.ts +2 -69
  13. package/dist/discovery/operations.deriver.d.ts +0 -36
  14. package/dist/discovery/scalar.mapper.d.ts +1 -32
  15. package/dist/discovery/scalar.mapper.js +2 -2
  16. package/dist/discovery/schema-facts.interface.d.ts +3 -83
  17. package/dist/discovery/schema.reader.d.ts +0 -133
  18. package/dist/discovery/types.reader.d.ts +1 -9
  19. package/dist/discovery/types.reader.js +7 -7
  20. package/dist/discovery/vocabulary.dictionary.d.ts +6 -133
  21. package/dist/discovery/vocabulary.dictionary.js +2 -2
  22. package/dist/errors/error.normalizer.d.ts +5 -168
  23. package/dist/errors/prisma-error.reader.d.ts +1 -93
  24. package/dist/execution/first-variant.emulator.d.ts +5 -28
  25. package/dist/execution/operation.executor.d.ts +1 -62
  26. package/dist/execution/result.shaper.d.ts +0 -56
  27. package/dist/execution/transaction.executor.d.ts +0 -98
  28. package/dist/generate/artifact.emitter.d.ts +1 -35
  29. package/dist/generate/artifact.emitter.js +26 -43
  30. package/dist/generate/declared-support.reader.d.ts +0 -20
  31. package/dist/generate/discovery.cli.d.ts +0 -4
  32. package/dist/generate/existence.gate.d.ts +3 -37
  33. package/dist/generate/index.d.ts +4 -57
  34. package/dist/generate/prisma-cli.resolver.d.ts +0 -22
  35. package/dist/generate/prisma.generate.d.ts +14 -83
  36. package/dist/generate/reader-crosscheck.d.ts +3 -88
  37. package/dist/generate/reader-crosscheck.js +4 -4
  38. package/dist/prisma-client.interface.d.ts +5 -25
  39. package/dist/prisma.adapter.d.ts +21 -22
  40. package/dist/provider/provider-profile.d.ts +6 -14
  41. package/dist/translation/identifier.addressing.d.ts +0 -38
  42. package/dist/translation/mutation.translator.d.ts +5 -51
  43. package/dist/translation/operation.translator.d.ts +1 -102
  44. package/dist/translation/order-pagination.translator.d.ts +1 -47
  45. package/dist/translation/projection.translator.d.ts +1 -46
  46. package/dist/translation/scalar.conversion.d.ts +0 -64
  47. package/dist/translation/where.translator.d.ts +0 -52
  48. package/package.json +3 -2
@@ -1,39 +1,17 @@
1
1
  import type { Adapter, AdapterResource, EnumDefinition, ScalarRegistry, TransactionCapability } from "@aventara/core";
2
2
  import type { PrismaProvider } from "../provider/provider-profile.js";
3
- /**
4
- * A plain `type`, not `interface … extends`: `AdapterModel.resources` is
5
- * self-typed `AdapterResource<this>`, and a nominal `extends` hits TS2430.
6
- */
3
+ /** The adapter model a discovery artifact carries, in Aventara's vocabulary. */
7
4
  export type PrismaAdapterModel = {
5
+ /** The scalar types the schema uses. */
8
6
  readonly scalars: ScalarRegistry;
7
+ /** The schema's enums, by name. */
9
8
  readonly enums: Readonly<Record<string, EnumDefinition>>;
9
+ /** The schema's models, as Resources. */
10
10
  readonly resources: Readonly<Record<string, AdapterResource<PrismaAdapterModel>>>;
11
+ /** Whether the driver supports interactive transactions. */
11
12
  readonly transactions: TransactionCapability;
12
13
  };
13
- /**
14
- * One identifier, and the **Prisma addressing key** that reaches it.
15
- *
16
- * `members` is the identifier as core carries it — derived from
17
- * `AdapterResource` rather than restated, so a change to core's identifier type
18
- * is a compile error here. `key` is the same criterion's *Prisma* spelling: the
19
- * key a `WhereUniqueInput` accepts, and the key the generated `AtLeast<…, K>`
20
- * union lists.
21
- *
22
- * The two are different facts, and the whole reason this type exists is that
23
- * they are not derivable from one another. Measured at 7.10.0 (2026-09-29):
24
- *
25
- * - a single-column criterion keys by the field name and does **not** wrap:
26
- * `{ id: "x" }`;
27
- * - a compound keys by its members joined with `_` **in attribute order** and
28
- * does wrap: `@@unique([b, a])` → `{ b_a: { b, a } }`;
29
- * - `name: "X"` **replaces** the positional form on both sides — `}, "id" |
30
- * "altKey">` and `altKey?: Prisma.…CompoundUniqueInput`;
31
- * - `map:` affects neither: it reaches only the 🛑 inline-schema blob.
32
- *
33
- * So `key` is stored at generate time and **matched** at runtime, never
34
- * re-derived: `members.join("_")` is wrong for every named criterion, and
35
- * whether it wraps is `members.length > 1`.
36
- */
14
+ /** One identifier, and the **Prisma addressing key** that reaches it. */
37
15
  export type PrismaIdentifierAddress = {
38
16
  readonly members: AdapterResource<PrismaAdapterModel>["identifiers"][number];
39
17
  readonly key: string;
@@ -42,79 +20,19 @@ export type PrismaIdentifierAddress = {
42
20
  export type PrismaResourceTranslation = {
43
21
  readonly identifierKeys: readonly PrismaIdentifierAddress[];
44
22
  };
45
- /**
46
- * The **translation table**: Prisma addressing for every discovered Resource.
47
- *
48
- * Keyed on `M`'s own resource keys, so a table missing a Resource — or naming
49
- * one the model does not have — is a compile error rather than a runtime
50
- * `undefined` at the first unique read.
51
- *
52
- * It sits **beside** {@link PrismaDiscoveryArtifact.model}, never inside it, and
53
- * that placement is the point: the model is canonicalized, hashed and compiled
54
- * into the Contract, so a Prisma addressing key in it would put a DB-side
55
- * rename into the Contract hash and force every client to be regenerated for a
56
- * change with zero semantic content. This half is adapter-private: the executor
57
- * reads it, core never sees it.
58
- */
23
+ /** The **translation table**: Prisma addressing for every discovered Resource. */
59
24
  export type PrismaTranslationTable<M extends PrismaAdapterModel = PrismaAdapterModel> = {
60
25
  readonly [R in keyof M["resources"]]: PrismaResourceTranslation;
61
26
  };
62
- /**
63
- * A referential action in Aventara's own vocabulary.
64
- *
65
- * Prisma's set — `Cascade | Restrict | NoAction | SetNull | SetDefault` — is the
66
- * SQL-standard set spelled in PascalCase, so a faithful mapping exists and no
67
- * Prisma spelling has to travel with the fact. These words are SQL's own
68
- * (`ON DELETE SET NULL`), which is why the mapping is a rename and not a
69
- * translation: nothing about it is Prisma-shaped, and the next adapter can state
70
- * the same fact without inheriting this one's vocabulary.
71
- *
72
- * It is declared **here**, on the artifact side, rather than beside the PSL
73
- * facts that resolve it: the artifact is what carries the vocabulary off the
74
- * generate step and across the package boundary, and `schema-facts.interface.ts`
75
- * imports it from here so that there is one spelling and the dependency runs
76
- * generate-time → artifact rather than the other way about.
77
- */
27
+ /** A referential action, as `onDelete`/`onUpdate` name it in the schema. */
78
28
  export type PrismaReferentialAction = "cascade" | "restrict" | "no-action" | "set-null" | "set-default";
79
- /**
80
- * One **owning** relation edge's resolved referential actions.
81
- *
82
- * # The direction, which is the whole point of this type
83
- *
84
- * `onDelete` is declared on the **child** — `Kid.parent @relation(…, onDelete:
85
- * Cascade)` — and fires when the **parent** is deleted. PSL enforces that itself:
86
- * `prisma validate` 7.10.0 refuses the action on the other edge, naming the
87
- * opposite field. So an entry under resource `R` reads:
88
- *
89
- * > **deleting a `target` row does `onDelete` to rows of `R`.**
90
- *
91
- * A consumer asking *"what does deleting an `X` do?"* scans every resource's
92
- * {@link PrismaResourceReferentialActions.owningEdges} for `target === "X"` and
93
- * reads the enclosing resource key off the table. It never has to work out which
94
- * side of a pair declared what.
95
- *
96
- * **Reversing that reading is silent.** Nothing in the shape distinguishes
97
- * `resource` from `target`, both are resource names, and a planner built on the
98
- * inverted reading cascades the wrong way with no type error and no runtime
99
- * complaint. That is why the convention is restated here as well as on
100
- * `field.mapper.ts`'s `PrismaRelationEdge`, which is where these values are
101
- * carried out of field projection.
102
- *
103
- * # Both members are resolved, so neither is nullable
104
- *
105
- * An absent `@relation(onDelete:)` is **not** a third state: it is Prisma's
106
- * effective default, measured at 7.10.0 with `prisma migrate diff` and identical
107
- * on `postgresql` and `sqlite` — `SET NULL` when every scalar in `fields:` is
108
- * optional, `RESTRICT` otherwise, and `CASCADE` on update
109
- * (`schema.reader.ts`'s `resolvePrismaReferentialDefaults`). An action the reader
110
- * cannot name is recorded in `unhandled` and fails the generate step, so no
111
- * artifact ever carries an unresolved one.
112
- */
29
+ /** One **owning** relation edge's resolved referential actions. */
113
30
  export type PrismaReferentialEdge = {
114
31
  /** The edge's field name on the enclosing (child) resource. */
115
32
  readonly field: string;
116
33
  /** The resource the edge points AT — the parent, whose deletion fires `onDelete`. */
117
34
  readonly target: string;
35
+ /** Whether the edge holds one related row or many. */
118
36
  readonly cardinality: "one" | "many";
119
37
  /** What deleting a `target` row does to rows of the ENCLOSING resource. */
120
38
  readonly onDelete: PrismaReferentialAction;
@@ -122,30 +40,17 @@ export type PrismaReferentialEdge = {
122
40
  readonly onUpdate: PrismaReferentialAction;
123
41
  };
124
42
  /**
125
- * One Resource's owning edges, in PSL field-declaration order.
126
- *
127
- * Only **owning** edges appear — the ones that declare `@relation(fields: …)`,
128
- * which is what makes an edge the foreign-key side and the only side PSL lets
129
- * carry an action. A back-reference's actions are its partner's, so an entry for
130
- * it would carry two nulls and no fact; a resource with no owning edge carries an
131
- * empty list, which is itself the answer that deleting anything leaves its rows
132
- * alone.
43
+ * One Resource's owning edges, in schema field order: the relation fields that
44
+ * declare `@relation(fields: …)`. An empty list means deleting rows elsewhere
45
+ * leaves this Resource's rows alone.
133
46
  */
134
47
  export type PrismaResourceReferentialActions = {
48
+ /** The Resource's owning edges, in schema order. */
135
49
  readonly owningEdges: readonly PrismaReferentialEdge[];
136
50
  };
137
51
  /**
138
52
  * The **referential-action table**: every discovered Resource's owning edges,
139
53
  * resolved.
140
- *
141
- * Keyed on `M`'s own resource keys for the reason {@link PrismaTranslationTable}
142
- * is — a resource the model carries and the table forgets is a compile error at
143
- * the generate step rather than a runtime `undefined` — and it sits **beside**
144
- * {@link PrismaDiscoveryArtifact.model} and outside `modelHash` for the reason
145
- * that one does: `modelHash` digests the model, and a referential action is not
146
- * part of the model. Putting it inside would push referential-action vocabulary
147
- * into the compiled Contract and the ClientContract, where core has no word for
148
- * it, and would move the Contract identity of every schema that has a relation.
149
54
  */
150
55
  export type PrismaReferentialActionTable<M extends PrismaAdapterModel = PrismaAdapterModel> = {
151
56
  readonly [R in keyof M["resources"]]: PrismaResourceReferentialActions;
@@ -154,18 +59,6 @@ export type PrismaReferentialActionTable<M extends PrismaAdapterModel = PrismaAd
154
59
  * What the generated Prisma client exposed when the artifact was generated: each
155
60
  * model it has a delegate for, keyed by the model's name, and that model's field
156
61
  * references (`prisma.<model>.fields`) in code-unit order.
157
- *
158
- * It is the artifact's record of the client it was read from, and the runtime
159
- * reads the same two facts off the client it is handed — the delegates the client
160
- * carries, and each one's public `fields`. When they disagree, the schema changed
161
- * and the client was regenerated without the artifact, and the adapter refuses to
162
- * start rather than serve a model that no longer matches. Prisma excludes
163
- * `Unsupported(…)` and `@ignore`d fields and `@@ignore`d models from both the
164
- * generated types and the runtime client, so the two readings agree by
165
- * construction on an unchanged schema.
166
- *
167
- * Beside the model and outside `modelHash`, like the translation table: it
168
- * describes the provider client, not the semantic model.
169
62
  */
170
63
  export type PrismaClientShape = Readonly<Record<string, readonly string[]>>;
171
64
  /**
@@ -182,54 +75,40 @@ export type PrismaClientShape = Readonly<Record<string, readonly string[]>>;
182
75
  * model, and the Contract carries no foreign-key detail.
183
76
  */
184
77
  export type PrismaCreateRequirementTable = NonNullable<Adapter["createRequirements"]>;
78
+ /** The current discovery artifact format. */
79
+ export declare const DISCOVERY_ARTIFACT_FORMAT = 1;
185
80
  /**
186
- * One module written `as const satisfies AdapterModel` makes value and type the
187
- * same literal, and makes drift unrepresentable rather than merely detectable.
188
- *
189
- * It is still passive, serializable, introspectable, hashable and free of runtime
190
- * callbacks: a `.ts` module whose only expression is a frozen object literal is
191
- * JSON that carries its own type.
192
- *
193
- * `M` is the reason this type is generic at all. The emitted module's `model` is a
194
- * literal type; if this alias pinned `model` to the general {@link
195
- * PrismaAdapterModel}, every resource key and field key would be erased to
196
- * `string` on the way to `createPrismaAdapter`, `EffectiveFieldKey` would
197
- * degenerate, and core's whole config-typing workstream would buy nothing —
198
- * silently, with no compile error anywhere. `model: M` is a bare property
199
- * position, which is what makes `M` actually infer at the call site;
200
- * `typed-artifact.test-d.ts` is what proves it still does.
201
- *
202
- * The default keeps the unparameterised spelling meaning what it always meant:
203
- * "some Prisma adapter model".
81
+ * The discovery artifact: the module `aventara-prisma7-generate` writes from
82
+ * your schema and generated client. Import its `discovery` export and pass it
83
+ * to `createPrismaAdapter({ discovery })`.
204
84
  */
205
85
  export type PrismaDiscoveryArtifact<M extends PrismaAdapterModel = PrismaAdapterModel> = {
206
- /** e.g. `"7.10.0"`; only the major is fenced. */
86
+ /**
87
+ * The artifact's format. A TypeScript error naming this property means the
88
+ * artifact was written by another version of `@aventara/prisma7-adapter`:
89
+ * regenerate it with `npm run aventara:prepare` (or `aventara-prisma7-generate`).
90
+ */
91
+ readonly regenerate_with_aventara_prepare: typeof DISCOVERY_ARTIFACT_FORMAT;
92
+ /** The Prisma version the artifact was generated with, such as `"7.10.0"`. */
207
93
  readonly prismaVersion: string;
94
+ /** The database provider: `"sqlite"` or `"postgresql"`. */
208
95
  readonly provider: PrismaProvider;
209
96
  /** `sha256:<hex>` of the canonicalized `model` below — and of nothing else. */
210
97
  readonly modelHash: string;
98
+ /** What the schema and the generated client agreed on. */
211
99
  readonly model: M;
212
- /**
213
- * Prisma addressing beside the model, and outside `modelHash` by
214
- * construction: see {@link PrismaTranslationTable}.
215
- */
100
+ /** Prisma addressing per Resource; not part of `modelHash`. */
216
101
  readonly translation: PrismaTranslationTable<M>;
217
102
  /**
218
- * The resolved referential actions, beside the model and outside `modelHash`
219
- * on the same construction: see {@link PrismaReferentialActionTable}.
220
- *
221
- * Direction, because getting it backwards is silent: an entry under resource
222
- * `R` says **deleting a `target` row does `onDelete` to rows of `R`**.
103
+ * The schema's referential actions; not part of `modelHash`. An entry under
104
+ * resource `R` says **deleting a `target` row does `onDelete` to rows of `R`**.
223
105
  */
224
106
  readonly referentialActions: PrismaReferentialActionTable<M>;
225
107
  /**
226
- * The client this artifact was generated against, beside the model and
227
- * outside `modelHash`: see {@link PrismaClientShape}.
108
+ * The models and field references of the client the artifact was generated
109
+ * against; not part of `modelHash`.
228
110
  */
229
111
  readonly client: PrismaClientShape;
230
- /**
231
- * The create requirements, beside the model and outside `modelHash`: see
232
- * {@link PrismaCreateRequirementTable}.
233
- */
112
+ /** What a create of each Resource cannot do without; not part of `modelHash`. */
234
113
  readonly createRequirements: PrismaCreateRequirementTable;
235
114
  };
@@ -1 +1 @@
1
- export {};
1
+ export const DISCOVERY_ARTIFACT_FORMAT = 1;
@@ -1,29 +1,9 @@
1
1
  import type { EnumDefinition } from "@aventara/core";
2
2
  import type { PrismaSchemaEnum } from "./schema-facts.interface.js";
3
3
  import type { PrismaDiscoveryDiagnostic } from "./vocabulary.dictionary.js";
4
- /**
5
- * # Declaration order is semantic, so nothing here sorts
6
- *
7
- * # What a cross-check failure means
8
- *
9
- * `enums.ts` and `schema.prisma` were read in the same instant by the same
10
- * generate step. If they disagree, one of them is stale, and the answer is
11
- * `diverged` — a build stop — rather than a preference for either. The message
12
- * prints both orders because "the enum diverged" without them costs the reader a
13
- * second investigation.
14
- *
15
- * # A member-level `@map` never reaches here, from either side
16
- *
17
- * PSL's reader discards it as bucket 2 (a database name, which Aventara has no
18
- * word for), and the generated `enums.ts` writes the member name on *both* sides
19
- * of a mapped member — `GAMMA: 'GAMMA'`, not `GAMMA: 'g'` **[RUN8 — 2026-09-28,
20
- * prisma 7.10.0]**. So the cross-check compares Aventara identities on both sides,
21
- * and the mapper has nothing to resurrect.
22
- */
23
4
  export type EnumMappingInput = {
24
5
  /** PSL — the source of the values and their order. */
25
6
  readonly declared: PrismaSchemaEnum;
26
- /** TYPE — `enums.ts`'s member list, or `undefined` when the 🟢 types omit the enum entirely. */
27
7
  readonly exposed: readonly string[] | undefined;
28
8
  };
29
9
  export type EnumMappingOutcome = {
@@ -37,10 +17,6 @@ export type EnumMappingOutcome = {
37
17
  readonly outcome: "diverged";
38
18
  readonly diagnostic: PrismaDiscoveryDiagnostic;
39
19
  };
40
- /**
41
- * The `kind` is a literal `"scalar"`, so a third structural kind cannot be
42
- * introduced here without the type changing.
43
- */
44
20
  export type EnumBackedColumn = {
45
21
  readonly kind: "scalar";
46
22
  readonly type: {
@@ -3,93 +3,15 @@ import type { PrismaResourceSurface } from "./capability-surface.interface.js";
3
3
  import type { PrismaAdapterModel, PrismaReferentialAction } from "./discovery-artifact.interface.js";
4
4
  import type { PrismaSchemaField, PrismaSchemaUnknown } from "./schema-facts.interface.js";
5
5
  import { type PrismaDiscoveryDiagnostic, type PrismaEvidence } from "./vocabulary.dictionary.js";
6
- /**
7
- * # Nullability comes from PSL, and the required `Json` column is why
8
- *
9
- * `nullable` is `PrismaSchemaField.optional` — PSL's `?` — and **nothing else**.
10
- * The type surface cannot answer the question, and the damage is not hypothetical:
11
- * `$MetricPayload.scalars.sJson` resolves to `null | string | number | false |
12
- * true | JsonObject | JsonArray` while PSL says `sJson Json`, required, because
13
- * JSON null is a *value*. The reader's own facts point the same wrong way —
14
- * `JsonFilterBase.array_contains` admits `| null` and `equals` admits
15
- * `JsonNullValueFilter` on that same required column — so a plausible "the
16
- * operands mention null, therefore the column is nullable" rule is wrong for
17
- * **every** `Json` field while being right everywhere else. That is the whole
18
- * reason this rule is stated as a rule rather than left to taste.
19
- *
20
- * # The create-optional marker is a cross-check, never a source
21
- *
22
- * {@link crossCheckCreateOptional} is a separate function that *consumes* this
23
- * projection, and the data flows one way only: the marker never reaches {@link
24
- * projectPrismaField}. `<M>UncheckedCreateInput`'s `?` is **one bit over several
25
- * causes** — `@default(uuid())`, `@default(BRONZE)`, `@default(now())`,
26
- * `@updatedAt`, plain nullability, and a scalar list, which needs no value because
27
- * the empty list is one — and nothing on the 🟢 surface tells them apart. Deriving
28
- * a trait *from* the marker would invert the check into the bug it exists to
29
- * catch: it would make the two readers agree by construction and detect nothing.
30
- *
31
- * # `@default` is matched, never parsed
32
- *
33
- * {@link matchPrismaDefault} walks `PRISMA_DEFAULT_TABLE` over the raw argument
34
- * text the PSL reader carried across unchanged.
35
- *
36
- * The matcher adds **one** discriminant the dictionary's table does not state, and
37
- * it is a shape test rather than a parse: an argument that begins with an
38
- * identifier followed by `(` is a *generator form*, and anything else is a *static
39
- * value*. Both are `DEFAULTED`; only an unrecognised generator form records an
40
- * unknown. The test never reads *inside* the argument, so
41
- * `dbgenerated("gen_random_uuid()")` remains a key and `"a, b // not a comment"`
42
- * remains opaque text.
43
- *
44
- * # A relation carries four members, and the FK is not one of them
45
- *
46
- * `target`, `cardinality`, `nullable`, and `capabilities`. The `@relation(fields:
47
- * […], references: […])` scalars are read, used to identify the FK column and
48
- * check it against the edge's own optionality, and then **discarded**.
49
- * `@relation`'s *name* is not an Aventara concept either, and its referential
50
- * actions are not core's yet, so both travel beside the projection as {@link
51
- * PrismaRelationEdge} rather than inside it: pairing is discovery-internal, and it
52
- * is **PSL-only** — the name appears nowhere on the 🟢 surface, so from the types
53
- * alone `Author` has two `Author` edges with nothing to pair them.
54
- *
55
- * # Two failure vocabularies, kept apart
56
- *
57
- * A **diagnostic** is about the schema: PSL declares a column the 🟢 types do not
58
- * expose, or a Prisma type name in no table. A **throw** is about the readers: the
59
- * two sources disagree about a fact they both state, which no schema can cause and
60
- * no diagnostic vocabulary describes. The types reader draws the same line.
61
- */
62
6
  /** A reader-versus-reader disagreement: not a schema problem, and not recoverable. */
63
7
  export declare class PrismaFieldProjectionError extends Error {
64
8
  readonly name = "PrismaFieldProjectionError";
65
9
  }
66
- /**
67
- * `Omit` rather than a restatement, so the composed field is the core type by
68
- * construction.
69
- */
70
10
  export type ProjectedScalarField = Omit<AdapterScalarField<PrismaAdapterModel>, "capabilities">;
71
11
  export type ProjectedRelationField = Omit<AdapterRelationField<PrismaAdapterModel>, "capabilities">;
72
12
  /**
73
13
  * One relation edge as PSL states it — the pairing evidence and the referential
74
14
  * actions, neither of which the projected field carries.
75
- *
76
- * # Why the actions ride here and not on `AdapterRelationField`
77
- *
78
- * Wiring a referential action into the Contract is a core change and belongs to
79
- * the task that owns core's transaction planner, not to discovery. Until then the
80
- * fact lives where discovery can state it truthfully.
81
- *
82
- * # The lookup is inverted, and the edge is shaped so a consumer need not invert
83
- *
84
- * `onDelete` is declared on the CHILD — `Kid.parent @relation(…, onDelete:
85
- * Cascade)` — and fires when the PARENT is deleted. So an edge reads: **deleting a
86
- * `target` does `onDelete` to rows of `resource`.** A consumer asking "what does
87
- * deleting `X` remove?" filters `target === X && onDelete === "cascade"` and reads
88
- * off `resource`; it does not have to re-derive which side of a pair declared
89
- * what.
90
- *
91
- * `null` on both members means this edge is not the owning side (it declares no
92
- * `fields:`), so the actions are on its partner — never that no action applies.
93
15
  */
94
16
  export type PrismaRelationEdge = {
95
17
  /** The model DECLARING the edge — the child, where an owning edge is concerned. */
@@ -100,11 +22,6 @@ export type PrismaRelationEdge = {
100
22
  readonly cardinality: "one" | "many";
101
23
  /** `@relation("Name")`, or `null` where PSL wrote none. PSL-only. */
102
24
  readonly relationName: string | null;
103
- /**
104
- * What deleting a `target` row does to this `resource` row, resolved (an
105
- * absent PSL argument already carries Prisma's measured default). `null` on a
106
- * non-owning edge.
107
- */
108
25
  readonly onDelete: PrismaReferentialAction | null;
109
26
  /** The same for an update of the referenced key. `null` on a non-owning edge. */
110
27
  readonly onUpdate: PrismaReferentialAction | null;
@@ -115,7 +32,7 @@ export type FieldProjectionInput = {
115
32
  readonly field: PrismaSchemaField;
116
33
  /** The model's other fields: the only way to identify an FK scalar by name. */
117
34
  readonly siblings: readonly PrismaSchemaField[];
118
- /** TYPE — what this client exposes. The existence gate. */
35
+ /** TYPE — what this client exposes. */
119
36
  readonly surface: PrismaResourceSurface;
120
37
  /** TYPE — `enums.ts`, which is what makes an enum name an enum name. */
121
38
  readonly enums: Readonly<Record<string, readonly string[]>>;
@@ -126,7 +43,6 @@ export type FieldProjection = {
126
43
  readonly outcome: "scalar";
127
44
  readonly name: string;
128
45
  readonly field: ProjectedScalarField;
129
- /** Recorded unknowns; a non-empty list FAILS the generate step. */
130
46
  readonly unknowns: readonly PrismaSchemaUnknown[];
131
47
  } | {
132
48
  readonly outcome: "relation";
@@ -158,10 +74,6 @@ export type PrismaDefaultOutcome =
158
74
  readonly form: "unrecognised-generator";
159
75
  readonly traits: readonly AdapterLifecycleTrait[];
160
76
  };
161
- /**
162
- * The argument arrives as opaque text precisely so that this function can be a
163
- * lookup.
164
- */
165
77
  export declare function matchPrismaDefault(argument: string): PrismaDefaultOutcome;
166
78
  /** Why a field is legitimately optional in `<M>UncheckedCreateInput`. */
167
79
  export type CreateOptionalCause = AdapterLifecycleTrait | "nullable"
@@ -192,16 +104,7 @@ export type CreateOptionalCrossCheck = {
192
104
  readonly unexplained: readonly string[];
193
105
  readonly messages: readonly string[];
194
106
  };
195
- /**
196
- * TYPE's only contribution to lifecycle: a check, run in one direction.
197
- *
198
- * Every field the 🟢 `<M>UncheckedCreateInput` marks optional must carry a PSL
199
- * cause. A field the types mark optional with no cause means **one of the two
200
- * readers is wrong** — that is the entire signal, and it is why the marker is
201
- * never read as a trait. Names the types mark that this model does not project
202
- * as a scalar (relation edges) are skipped rather than reported: their
203
- * optionality is structural.
204
- */
107
+ /** TYPE's only contribution to lifecycle: a check, run in one direction. */
205
108
  export declare function crossCheckCreateOptional(input: CreateOptionalCrossCheckInput): CreateOptionalCrossCheck;
206
109
  export type PrismaRelationPair = readonly [
207
110
  PrismaRelationEdge,
@@ -212,19 +115,5 @@ export type PrismaRelationPairing = {
212
115
  /** Edges nothing pairs: a back-reference the schema never declared, or an ambiguity. */
213
116
  readonly unpaired: readonly PrismaRelationEdge[];
214
117
  };
215
- /**
216
- * Pairs each edge with its back-reference, which **only PSL can do**.
217
- *
218
- * An explicit `@relation("Name")` is the pairing evidence, and for the two
219
- * `Author` → `Author` edges it is the *only* evidence: the name appears nowhere
220
- * on the 🟢 surface, so from the types alone there are two self-edges and
221
- * nothing to say they are one relation.
222
- *
223
- * Unnamed edges are paired by the unordered model pair, which is unambiguous
224
- * because PSL requires a name as soon as two relations connect the same two
225
- * models. Where an unordered pair still has more than two edges, they are left
226
- * unpaired rather than guessed: the implicit name Prisma would compute lives in
227
- * the 🛑 runtime data model, and re-deriving it here would be this module
228
- * reimplementing the generator.
229
- */
118
+ /** Pairs each edge with its back-reference, which **only PSL can do**. */
230
119
  export declare function pairPrismaRelationEdges(edges: readonly PrismaRelationEdge[]): PrismaRelationPairing;
@@ -44,10 +44,10 @@ function assertTokenAgrees(resource, field, token) {
44
44
  const listed = token.endsWith("[]");
45
45
  const base = listed ? token.slice(0, -2) : token;
46
46
  if (base !== field.type) {
47
- throw new PrismaFieldProjectionError(`${resource}.${field.name} is written \`${field.type}\` in schema.prisma and the 🟢 types carry the FieldRef token \`${token}\`. The two readers describe one instant, so this is a stale generated client or a reader defect, not a schema the adapter can translate.`);
47
+ throw new PrismaFieldProjectionError(`${resource}.${field.name} is written \`${field.type}\` in schema.prisma and the generated client's types carry the FieldRef token \`${token}\`. The two readers describe one instant, so this is a stale generated client or a reader defect, not a schema the adapter can translate.`);
48
48
  }
49
49
  if (listed !== field.list) {
50
- throw new PrismaFieldProjectionError(`${resource}.${field.name} is ${field.list ? "a list" : "not a list"} in schema.prisma and the 🟢 types carry the FieldRef token \`${token}\`, which says the opposite.`);
50
+ throw new PrismaFieldProjectionError(`${resource}.${field.name} is ${field.list ? "a list" : "not a list"} in schema.prisma and the generated client's types carry the FieldRef token \`${token}\`, which says the opposite.`);
51
51
  }
52
52
  }
53
53
  const ADAPTER_TRAIT_ORDER = LIFECYCLE_TRAITS.filter((trait) => trait === "DEFAULTED" ||
@@ -138,20 +138,20 @@ function projectRelationField(input) {
138
138
  outcome: "excluded",
139
139
  diagnostic: {
140
140
  code: "not-exposed",
141
- message: `${column} is declared in schema.prisma as an edge to \`${field.type}\` and absent from the generated 🟢 types, so it is omitted: ${field.ignored ? "it carries `@ignore`" : "no schema attribute explains it — a provider drop or a preview-feature exclusion"}.`,
141
+ message: `${column} is declared in schema.prisma as an edge to \`${field.type}\` and absent from the generated client's types, so it is omitted: ${field.ignored ? "it carries `@ignore`" : "no schema attribute explains it — a provider drop or a preview-feature exclusion"}.`,
142
142
  },
143
143
  };
144
144
  }
145
145
  const cardinality = field.list ? "many" : "one";
146
146
  const nullable = cardinality === "many" ? false : field.optional;
147
147
  if (exposed.many !== field.list) {
148
- throw new PrismaFieldProjectionError(`${column} is ${field.list ? "a list" : "a single edge"} in schema.prisma and the 🟢 payload says the opposite.`);
148
+ throw new PrismaFieldProjectionError(`${column} is ${field.list ? "a list" : "a single edge"} in schema.prisma and the generated client's payload type says the opposite.`);
149
149
  }
150
150
  if (exposed.nullable !== nullable) {
151
- throw new PrismaFieldProjectionError(`${column} is ${nullable ? "optional" : "required"} in schema.prisma and the 🟢 payload ${exposed.nullable ? "admits" : "refuses"} \`null\`.`);
151
+ throw new PrismaFieldProjectionError(`${column} is ${nullable ? "optional" : "required"} in schema.prisma and the generated client's payload type ${exposed.nullable ? "admits" : "refuses"} \`null\`.`);
152
152
  }
153
153
  if (exposed.target !== field.type) {
154
- throw new PrismaFieldProjectionError(`${column} targets \`${field.type}\` in schema.prisma and \`${exposed.target}\` on the 🟢 payload.`);
154
+ throw new PrismaFieldProjectionError(`${column} targets \`${field.type}\` in schema.prisma and \`${exposed.target}\` in the generated client's payload type.`);
155
155
  }
156
156
  assertForeignKeyAgrees(column, field, siblings, nullable);
157
157
  return {
@@ -1,79 +1,18 @@
1
1
  import type { PrismaIdentifierAddress } from "./discovery-artifact.interface.js";
2
2
  import type { PrismaSchemaBlockIdentifier, PrismaSchemaModel } from "./schema-facts.interface.js";
3
- /**
4
- * # Why identity comes from PSL
5
- *
6
- * Because the generated types cannot state it. Measured on 2026-09-28 against
7
- * prisma 7.10.0, on a two-model scratch client generated for this purpose:
8
- *
9
- * ```prisma
10
- * model Delta { code String @unique name String }
11
- * model Epsilon { code String @id name String }
12
- * ```
13
- *
14
- * `models/Delta.ts` and `models/Epsilon.ts` are **byte-identical** — equal md5
15
- * after a case-insensitive `Delta|delta → MODEL|model` substitution and after
16
- * removing one 4-line `StringFieldUpdateOperationsInput` block, which is the
17
- * generator's first-file-wins dedup of a shared input type and lands in whichever
18
- * model file sorts first. Both declare their `AtLeast` key set as `}, "code">` on
19
- * the same line.
20
- *
21
- * So `@id` and `@unique` are the same fact to TYPE, and a compound `@@id` is the
22
- * same fact as a compound `@@unique`. PSL is the only source that distinguishes
23
- * them.
24
- *
25
- * # Why that negative costs the model nothing
26
- *
27
- * `AdapterResource.identifiers` is `readonly AdapterIdentifier<TFields>[]`
28
- * **[CORE]** — an **unmarked set** of non-empty scalar field tuples with no
29
- * primary/secondary distinction. Aventara never asks which identifier is the
30
- * primary key, so a source that cannot tell `@id` from `@unique` withholds nothing
31
- * this mapper needs.
32
- *
33
- * # The types are a cross-check, and a one-sided one
34
- *
35
- * Stored, not re-derived: matching a key computed as `members.join("_")` is what
36
- * used to refuse a schema carrying `@@unique(…, name: "X")`, whose surface key is
37
- * `X`. Measured: `Author` has three keys (`"id" | "email" | "tenantId_handle"`,
38
- * identical on both engines) and two identifiers.
39
- *
40
- * Its key **ORDERING is not used at all**. It appears to list the primary key
41
- * first, but that is an undocumented generator artifact, it is ordering inside a
42
- * union — which TypeScript does not preserve semantically — and it degenerates
43
- * completely when a model has exactly one unique criterion, the common case.
44
- * Nothing here may start depending on it.
45
- *
46
- * # Nothing here sorts
47
- *
48
- * Member order is the attribute's list as written, never the field declaration
49
- * order (`@@unique([y, x])` is `["y", "x"]` even where `x` is declared first), and
50
- * the identifiers themselves come out in PSL's own order: field-level criteria in
51
- * field declaration order, then `@@id`, then `@@unique` as written. Order enters
52
- * the Contract hash, so a deterministic order derived from PSL is the point, not a
53
- * convenience.
54
- */
55
- /** Which PSL spelling a criterion came from. Reported, and never used to rank one. */
3
+ /** Which PSL spelling a criterion came from. */
56
4
  export type PrismaIdentifierSource = "@id" | "@unique" | "@@id" | "@@unique";
57
5
  export type PrismaUniquenessCriterion = {
58
6
  readonly source: PrismaIdentifierSource;
59
7
  /** Member order as written in the attribute's list. Never sorted. */
60
8
  readonly members: readonly string[];
61
9
  /**
62
- * The Prisma addressing key for this criterion — {@link prismaUniqueInputKey} over
63
- * the PSL facts, computed once here.
10
+ * The Prisma addressing key for this criterion — {@link prismaUniqueInputKey}
11
+ * over the PSL facts, computed once here.
64
12
  */
65
13
  readonly key: string;
66
14
  };
67
- /**
68
- * A criterion that is NOT a usable identifier, recorded with its reason.
69
- *
70
- * A discriminated union, because the arms carry different evidence: which members
71
- * are nullable is not the same fact as which members are not scalar columns at
72
- * all.
73
- *
74
- * These are not `PrismaDiscoveryDiagnostic`s. A diagnostic carries prose for an
75
- * engineer; the cross-check needs the member names as data.
76
- */
15
+ /** A criterion that is NOT a usable identifier, recorded with its reason. */
77
16
  export type PrismaIdentifierOmission = PrismaUniquenessCriterion & ({
78
17
  readonly reason: "nullable-participant";
79
18
  readonly nullableMembers: readonly string[];
@@ -118,25 +57,6 @@ export type PrismaIdentifierMapping = {
118
57
  * The Prisma addressing key for a uniqueness criterion: the key a
119
58
  * `WhereUniqueInput` accepts, and the key the generated `AtLeast<…, K>` union
120
59
  * lists.
121
- *
122
- * The rule, measured at 7.10.0 (regenerated 2026-09-29 over five models):
123
- *
124
- * | criterion | key | wraps | | ---------------------------------- | --------- |
125
- * ----- | | `id String @id` / `@unique` | `id` | no | | `@@unique([b, a])` | `b_a`
126
- * | yes | | `@@id([a, b])` | `a_b` | yes | | `@@unique([b, a], name: "altKey")` |
127
- * `altKey` | yes | | `@@id([a, b], name: "pk")` | `pk` | yes | | any of the above,
128
- * `map: "…"` | unchanged | — |
129
- *
130
- * Two of those rows are why this is a function of the PSL facts and not of the
131
- * members alone. A custom `name:` **replaces** the positional alias rather than
132
- * adding to it, so `members.join("_")` is simply wrong for a named criterion —
133
- * which is precisely what made the cross-check refuse a schema Prisma accepts,
134
- * reporting a correctly-discovered identifier as an invented constraint (fixed
135
- * 2026-09-29; `map:` stays invisible and stays discarded).
136
- *
137
- * What this key is **not** is part of the identifier. `AdapterIdentifier` is a
138
- * tuple of field names with nowhere to put a name, and this key lives in the
139
- * artifact's translation table beside the model, never in it.
140
60
  */
141
61
  export declare function prismaUniqueInputKey(uniqueness: PrismaSchemaBlockIdentifier): string;
142
62
  /**