@prisma/orm-mongo 8.0.0-rc.5 → 8.0.0-rc.5-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/package.json +11 -10
  2. package/skills/prisma-8/SKILL.md +84 -0
  3. package/skills/prisma-8/references/build.md +142 -0
  4. package/skills/prisma-8/references/contract.md +417 -0
  5. package/skills/prisma-8/references/debug.md +141 -0
  6. package/skills/prisma-8/references/feedback.md +251 -0
  7. package/skills/prisma-8/references/migration-review.md +224 -0
  8. package/skills/prisma-8/references/migrations.md +519 -0
  9. package/skills/prisma-8/references/queries-mongo.md +236 -0
  10. package/skills/prisma-8/references/queries-postgres.md +415 -0
  11. package/skills/prisma-8/references/queries.md +168 -0
  12. package/skills/prisma-8/references/quickstart.md +326 -0
  13. package/skills/prisma-8/references/runtime.md +344 -0
  14. package/skills/prisma-8/references/supabase.md +244 -0
  15. package/skills/prisma-8/references/upgrade-app.md +101 -0
  16. package/skills/prisma-8/references/upgrade-extension.md +105 -0
  17. package/skills/prisma-8/upgrading/app/upgrades/0.10-to-0.11/instructions.md +56 -0
  18. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/instructions.md +381 -0
  19. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/re-emit-closed-mongo-contracts.ts +202 -0
  20. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/re-emit-domain-namespaced-contracts.ts +201 -0
  21. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/re-emit-postgres-public-default.ts +198 -0
  22. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/strip-migration-labels-hints.ts +340 -0
  23. package/skills/prisma-8/upgrading/app/upgrades/0.12-to-0.13/instructions.md +339 -0
  24. package/skills/prisma-8/upgrading/app/upgrades/0.12-to-0.13/re-emit-mti-variant-link-columns.ts +229 -0
  25. package/skills/prisma-8/upgrading/app/upgrades/0.13-to-0.14/instructions.md +543 -0
  26. package/skills/prisma-8/upgrading/app/upgrades/0.13-to-0.14/migration-op-factories-to-methods.ts +290 -0
  27. package/skills/prisma-8/upgrading/app/upgrades/0.13-to-0.14/uuid-preset-rename.ts +43 -0
  28. package/skills/prisma-8/upgrading/app/upgrades/0.14-to-0.15/instructions.md +359 -0
  29. package/skills/prisma-8/upgrading/app/upgrades/0.15-to-0.16/instructions.md +173 -0
  30. package/skills/prisma-8/upgrading/app/upgrades/0.16-to-0.17/instructions.md +805 -0
  31. package/skills/prisma-8/upgrading/app/upgrades/0.16-to-0.17/strip-sha256-hash-prefixes.ts +382 -0
  32. package/skills/prisma-8/upgrading/app/upgrades/0.17-to-8.0.0-rc.1/instructions.md +72 -0
  33. package/skills/prisma-8/upgrading/app/upgrades/0.7-to-0.8/instructions.md +8 -0
  34. package/skills/prisma-8/upgrading/app/upgrades/0.8-to-0.9/instructions.md +36 -0
  35. package/skills/prisma-8/upgrading/app/upgrades/0.8-to-0.9/strip-inline-contracts.ts +226 -0
  36. package/skills/prisma-8/upgrading/app/upgrades/0.9-to-0.10/instructions.md +86 -0
  37. package/skills/prisma-8/upgrading/app/upgrades/0.9-to-0.10/stamp-storage-types-kind.ts +360 -0
  38. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.1-to-8.0.0-rc.2/instructions.md +588 -0
  39. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.2-to-8.0.0-rc.3/instructions.md +5 -0
  40. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.3-to-8.0.0-rc.4/instructions.md +158 -0
  41. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.4-to-8.0.0-rc.5/instructions.md +42 -0
  42. package/skills/prisma-8/upgrading/extension/upgrades/0.10-to-0.11/instructions.md +276 -0
  43. package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/instructions.md +738 -0
  44. package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/migrate-contract-testing-imports.ts +97 -0
  45. package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/regenerate-extension-public-baseline.ts +223 -0
  46. package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/strip-migration-labels-hints.ts +340 -0
  47. package/skills/prisma-8/upgrading/extension/upgrades/0.12-to-0.13/instructions.md +266 -0
  48. package/skills/prisma-8/upgrading/extension/upgrades/0.13-to-0.14/instructions.md +522 -0
  49. package/skills/prisma-8/upgrading/extension/upgrades/0.13-to-0.14/migration-op-factories-to-methods.ts +290 -0
  50. package/skills/prisma-8/upgrading/extension/upgrades/0.13-to-0.14/uuid-preset-rename.ts +43 -0
  51. package/skills/prisma-8/upgrading/extension/upgrades/0.14-to-0.15/instructions.md +803 -0
  52. package/skills/prisma-8/upgrading/extension/upgrades/0.15-to-0.16/instructions.md +219 -0
  53. package/skills/prisma-8/upgrading/extension/upgrades/0.16-to-0.17/instructions.md +731 -0
  54. package/skills/prisma-8/upgrading/extension/upgrades/0.16-to-0.17/strip-sha256-hash-prefixes.ts +382 -0
  55. package/skills/prisma-8/upgrading/extension/upgrades/0.17-to-8.0.0-rc.1/instructions.md +194 -0
  56. package/skills/prisma-8/upgrading/extension/upgrades/0.7-to-0.8/instructions.md +8 -0
  57. package/skills/prisma-8/upgrading/extension/upgrades/0.8-to-0.9/instructions.md +57 -0
  58. package/skills/prisma-8/upgrading/extension/upgrades/0.8-to-0.9/strip-inline-contracts.ts +226 -0
  59. package/skills/prisma-8/upgrading/extension/upgrades/0.9-to-0.10/instructions.md +150 -0
  60. package/skills/prisma-8/upgrading/extension/upgrades/0.9-to-0.10/stamp-storage-types-kind.ts +360 -0
  61. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.1-to-8.0.0-rc.2/instructions.md +746 -0
  62. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.2-to-8.0.0-rc.3/instructions.md +5 -0
  63. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.3-to-8.0.0-rc.4/instructions.md +137 -0
  64. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.4-to-8.0.0-rc.5/instructions.md +129 -0
@@ -0,0 +1,158 @@
1
+ ---
2
+ from: "8.0.0-rc.3"
3
+ to: "8.0.0-rc.4"
4
+ changes:
5
+ - id: prisma-config-hard-cut-and-top-level-commands
6
+ summary: |
7
+ The deprecated fallbacks are gone: the CLI no longer reads
8
+ `prisma-next.config.ts`, no longer accepts the flat (un-nested) config shape, and the
9
+ `prisma-next` command no longer exists. The unified CLI (`@prisma/cli`, installed from
10
+ the `next` dist-tag; its binary is currently `prisma-cli`) runs the ORM commands at the
11
+ top level — `contract emit`, `db init`, `migration plan`, `migrate` — with only `init`
12
+ under the `orm` group (`orm init`), and the only config it reads is `prisma.config.ts`
13
+ in the engine envelope shape.
14
+
15
+ 1. Rename `prisma-next.config.ts` to `prisma.config.ts` if you have not already.
16
+ 2. Rewrite the export to the envelope shape. Old flat shape:
17
+ `import { defineConfig } from '@prisma/orm-postgres/config';`
18
+ `export default defineConfig({ contract: '…', db: { connection: … } });`
19
+ New shape:
20
+ `import { definePrismaConfig } from '@prisma/cli-engine';`
21
+ `import { defineConfig as ormConfig } from '@prisma/orm-postgres/config';`
22
+ `export default definePrismaConfig({ orm: ormConfig({ contract: '…', db: { connection: … } }) });`
23
+ The options object moves into the target helper unchanged. The same pattern applies
24
+ to `@prisma/orm-sqlite/config` and `@prisma/orm-mongo/config`.
25
+ 3. If the config reads `process.env`, keep (or add) `import 'dotenv/config';` as the
26
+ first import — the loader does not read `.env` for you.
27
+ 4. In `package.json`, replace the `prisma-next` devDependency with `@prisma/cli@next`
28
+ plus `@prisma/cli-engine` at the exact version that `@prisma/cli` names in its own
29
+ dependencies, and rewrite scripts: `prisma-next <subcommand>` becomes
30
+ `prisma-cli <subcommand>` (`migration apply` becomes `migrate`; `init` alone moves
31
+ under the orm group as `prisma-cli orm init`).
32
+ 5. Run `prisma-cli contract emit` to confirm the config loads and to regenerate the
33
+ artifacts (their generated-file headers change with this release).
34
+ detection:
35
+ glob: "**/prisma-next.config.ts"
36
+ - id: raw-moves-to-its-own-lane
37
+ summary: |
38
+ Whole-query raw SQL moves address: ``db.sql.raw`SELECT ...` `` becomes
39
+ ``db.raw.sql`SELECT ...` ``. Everything after the template is unchanged.
40
+ `.returnsRow(spec)`, `.affectedCount()`, `.returns(codecId)`, and splicing a
41
+ row-returning statement into another template all behave as they did.
42
+
43
+ The client's `raw` property changes shape in the same move. It was a tagged template you
44
+ could call directly for an expression fragment. It is now the raw lane, an object whose
45
+ `sql` key holds the statement tag.
46
+
47
+ An author who called `db.raw` as a fragment tag has two replacements. Use `fns.raw`
48
+ inside a builder callback, which is where fragments belong. Or terminate the lane's tag
49
+ with `.returns(codecId)` for the same expression, now bound to the contract.
50
+ detection:
51
+ glob: "**/*.{ts,tsx,mts,cts}"
52
+ regex:
53
+ # The old whole-query address, on any receiver.
54
+ - '\.sql\.raw`'
55
+ # The client tag being repurposed. `fns.raw` is a fragment call site and
56
+ # is deliberately excluded: fragments are unchanged by this release.
57
+ - '(?<!(?<![\w$])fns)\.raw`'
58
+ anyMatch: true
59
+ - id: raw-is-no-longer-a-reserved-namespace
60
+ summary: |
61
+ A storage namespace named `raw` is allowed again. 8.0.0-rc.2 and 8.0.0-rc.3 refused such a contract when
62
+ the client was built, with `ORM.NAMESPACE_RESERVED`, because the SQL surface answered
63
+ `db.sql.raw` with the raw tag. The tag has moved to `db.raw.sql`, so nothing a contract
64
+ declares can collide with it.
65
+
66
+ If you renamed a namespace to get past that error, you may rename it back:
67
+ `@@schema("raw")` is an ordinary name, reachable as `db.sql.raw.<table>`. Re-emit the
68
+ contract afterwards, then plan the rename against the database as you would any other
69
+ namespace rename. The physical schema keeps the name it has until a plan moves it.
70
+ Renaming back is optional: a namespace you renamed away stays valid.
71
+ detection:
72
+ glob: "**/*.{prisma,json}"
73
+ contains:
74
+ - "ORM.NAMESPACE_RESERVED"
75
+ - '@@schema("raw")'
76
+ anyMatch: true
77
+ - id: contract-artifacts-restamp
78
+ summary: |
79
+ The emitted `contract.json` / `contract.d.ts` embed the toolchain version, which moves
80
+ to 8.0.0-rc.4. Run `contract emit` once after upgrading so the emitted artifacts match
81
+ the installed toolchain. This applies even to projects whose config needed no
82
+ migration — the restamp is independent of the config changes above.
83
+ detection:
84
+ glob: "**/contract.json"
85
+ contains:
86
+ - '"version": "8.0.0-rc.3"'
87
+ ---
88
+
89
+ # 8.0.0-rc.3 → 8.0.0-rc.4 — User upgrade instructions
90
+
91
+ ## `raw-moves-to-its-own-lane`
92
+
93
+ Whole-query raw SQL has its own front door. The tag that sat inside the namespace map is now a
94
+ lane on the client:
95
+
96
+ ```ts
97
+ // Before
98
+ const plan = db.sql.raw`SELECT id, email FROM users WHERE id = ${1}`
99
+ .returnsRow({ id: users.columns.id, email: users.columns.email })
100
+ .build();
101
+
102
+ // After
103
+ const plan = db.raw.sql`SELECT id, email FROM users WHERE id = ${1}`
104
+ .returnsRow({ id: users.columns.id, email: users.columns.email })
105
+ .build();
106
+ ```
107
+
108
+ Everything after the template is unchanged: the terminators, the row specs they take, the plans
109
+ they build, and splicing a row-returning statement into another template.
110
+
111
+ The client's `raw` property changes shape in the same move. It was the expression tag you could
112
+ call directly; it is now the lane, whose `sql` key holds the statement tag:
113
+
114
+ ```ts
115
+ // Before: `raw` is a tag
116
+ const upper = db.raw`UPPER(${email})`.returns('pg/text@1');
117
+
118
+ // After, inside a builder callback — where fragments belong
119
+ const rows = db.sql.public.users
120
+ .select((f, fns) => ({ upper: fns.raw`UPPER(${f.email})`.returns('pg/text@1') }))
121
+ .build();
122
+
123
+ // After, from the lane, for a fragment you hold on its own
124
+ const upper = db.raw.sql`UPPER(${email})`.returns('pg/text@1');
125
+ ```
126
+
127
+ The detector looks for the old address and for `raw` used as a tag. It skips the receiver `fns`
128
+ exactly, including `x.fns.raw`, because that is a fragment call site and needs no change. A
129
+ receiver that merely ends in those letters, such as `myfns.raw`, still matches. So does a
130
+ builder callback that names its functions object something else. Check whether the receiver is
131
+ a client before you change anything.
132
+
133
+ ## `raw-is-no-longer-a-reserved-namespace`
134
+
135
+ 8.0.0-rc.2 and 8.0.0-rc.3 refused a contract whose storage declared a namespace named `raw`, because that was
136
+ the key the SQL surface answered with the raw tag:
137
+
138
+ ```text
139
+ ORM.NAMESPACE_RESERVED: The SQL surface exposes the raw statement tag as "db.raw", so a storage
140
+ namespace named "raw" cannot be reached through it. Rename the namespace in the schema.
141
+ ```
142
+
143
+ That constraint is gone. `db.sql` is a namespace map and nothing else, and the lane is composed
144
+ by the client rather than derived from your contract, so the two cannot collide.
145
+
146
+ If you renamed a namespace to get past the error, you may rename it back:
147
+
148
+ ```prisma
149
+ model Event {
150
+ id String @id
151
+ @@schema("raw")
152
+ }
153
+ ```
154
+
155
+ Its tables are then reachable as `db.sql.raw.<table>`, like any other namespace. Re-emit the
156
+ contract, and plan the rename against the database as you would any other namespace rename —
157
+ the physical schema carries the old name until a plan moves it. Renaming back is optional; the
158
+ name you moved to stays valid.
@@ -0,0 +1,42 @@
1
+ ---
2
+ from: "8.0.0-rc.4"
3
+ to: "8.0.0-rc.5"
4
+ changes:
5
+ - id: attach-pg-client-error-listener
6
+ summary: |
7
+ Attach an 'error' listener to any pg `Client` or `Pool` your own code constructs outside the Prisma runtime. node-postgres emits 'error' on the pool or client when an idle connection drops (database restart, pooler timeout, network blip); with no listener Node treats it as an uncaught exception and kills the process. Starting at rc.5 every pool and client the Prisma runtime creates or receives — including a pool you pass via the `pg:` binding — gets a listener automatically, so this only applies to pg handles your code uses directly (health checks, side-channel observers, hand-rolled scripts).
8
+ detection:
9
+ glob: "**/*.{ts,tsx}"
10
+ contains:
11
+ - "new Client("
12
+ - "new pg.Client("
13
+ - "new Pool("
14
+ - "new pg.Pool("
15
+ anyMatch: true
16
+ - id: contract-artifacts-restamp
17
+ summary: |
18
+ The emitted `contract.json` / `contract.d.ts` embed the toolchain version, which moves
19
+ to 8.0.0-rc.5. Run `contract emit` once after upgrading so the emitted artifacts match
20
+ the installed toolchain. The restamp is independent of the other changes in this
21
+ release.
22
+ detection:
23
+ glob: "**/contract.json"
24
+ contains:
25
+ - '"version": "8.0.0-rc.4"'
26
+ ---
27
+
28
+ # 8.0.0-rc.4 → 8.0.0-rc.5 — User upgrade instructions
29
+
30
+ ## `attach-pg-client-error-listener`
31
+
32
+ Walk every file matched by `detection.glob`. For each `pg.Client` or `pg.Pool` your code constructs and uses directly (not one handed to `postgres({ pg: ... })` / `supabase({ pg: ... })` — the runtime covers those since rc.5), attach an `'error'` listener right after construction, before `connect()`:
33
+
34
+ ```ts
35
+ const client = new pg.Client({ connectionString });
36
+ client.on('error', () => {});
37
+ await client.connect();
38
+ ```
39
+
40
+ A no-op listener is enough: connect and query failures still reject their own promises, so nothing real is masked — the listener only stops a dropped idle connection from becoming an uncaught exception. If the handle is long-lived and you have a logging channel, log the error instead of discarding it.
41
+
42
+ Note that a surrounding `try/catch` does **not** cover this case — the `'error'` event is emitted on the client object asynchronously, outside any promise chain the `catch` can see.
@@ -0,0 +1,276 @@
1
+ ---
2
+ from: "0.10"
3
+ to: "0.11"
4
+ changes:
5
+ - id: namespace-kind-required-on-handcrafted-contract-literals
6
+ summary: Add the `kind` discriminator (`'sql-namespace'` for SQL namespaces; `'mongo-namespace'` for Mongo namespaces) to every handcrafted `Contract<{ namespaces: { ... } }>` type literal in extension test-d files and inline-typed fixtures. The framework `Namespace` interface tightened `kind` from optional to required; emitted `contract.d.ts` literals carry it automatically, but anything you write by hand will fail typecheck without it.
7
+ detection:
8
+ glob: "**/*.test-d.ts"
9
+ contains:
10
+ - "Contract<"
11
+ - "namespaces"
12
+ anyMatch: true
13
+ - id: facade-add-close-and-async-dispose
14
+ summary: |
15
+ The official Prisma Next facades (`@internal/postgres`, `@internal/sqlite`, `@internal/mongo`) now expose `close()` and `[Symbol.asyncDispose]` so short-lived scripts can release facade-owned resources cleanly and exit instead of hanging on a live connection. Extensions that expose a facade in the same shape should add the same surface for parity, honouring the ownership rule (only close resources the facade itself constructed) and managing a terminal closed state (subsequent operations reject with a clear error). No script — manual code authoring per extension.
16
+ detection:
17
+ glob: "**/src/runtime/*.ts"
18
+ contains:
19
+ - "createRuntimeCore"
20
+ anyMatch: true
21
+ - id: mongo-close-ownership-rule
22
+ summary: |
23
+ The Mongo facade's `db.close()` is **silently breaking**. Before 0.11 it unconditionally called `await runtime.close()`, which closed the underlying `MongoClient` regardless of how the facade was constructed. From 0.11 it honours the ownership rule and closes only facade-constructed clients (from a `{ url }` binding); when the facade was constructed with `{ mongoClient }` the caller-supplied `MongoClient` is left untouched. Extensions that wrap or extend `@internal/mongo` and relied on `db.close()` disposing of a shared `MongoClient` need to either switch to a `{ url }` binding (so the facade owns the client) or close the `MongoClient` themselves.
24
+ detection:
25
+ glob: "**/*.{ts,tsx}"
26
+ contains:
27
+ - "mongoClient"
28
+ - "@internal/mongo"
29
+ anyMatch: true
30
+ - id: insert-single-row-wrap-in-array
31
+ summary: Wrap single-row `.insert({...})` call sites in an array — `.insert([{...}])`. The single-object overload is removed; `.insert()` now exclusively accepts an array of row objects.
32
+ detection:
33
+ glob: "**/*.{ts,tsx}"
34
+ contains:
35
+ - ".insert("
36
+ anyMatch: true
37
+ - id: insert-ast-with-values-to-with-rows
38
+ summary: Replace `InsertAst.withValues(assignments)` with `InsertAst.withRows([assignments])`. The `withValues` method is removed; `withRows` accepts an array of assignment maps.
39
+ detection:
40
+ glob: "**/*.{ts,tsx}"
41
+ contains:
42
+ - ".withValues("
43
+ ---
44
+
45
+ # 0.10 → 0.11 — Extension-author upgrade instructions
46
+
47
+ ## `namespace-kind-required-on-handcrafted-contract-literals`
48
+
49
+ Starting at the 0.11 release, the framework `Namespace` interface tightens `kind` from optional (inherited from `IRNode`) to required. Any **handcrafted** `Contract<{ namespaces: { ... } }>` type literal — typically used in extension test-d files and inline-typed fixtures — must add `kind: 'sql-namespace'` (or `'mongo-namespace'`) to each namespace literal or TypeScript will reject the literal as not structurally assignable to `Namespace`.
50
+
51
+ This **does not** affect:
52
+
53
+ - Real `contract.d.ts` files emitted by `prisma-next contract emit`. The emitter prints `kind` automatically.
54
+ - Real `contract.json` envelopes. The runtime `kind` field is non-enumerable on namespace class instances, so it doesn't surface in the JSON on-disk envelope and the byte hash is unchanged.
55
+ - Plain-literal `Contract` values constructed at runtime (the framework only tightens the **type** declaration of `kind`; the runtime walks tolerate missing values).
56
+
57
+ It **does** affect:
58
+
59
+ - `.test-d.ts` files in extension packages that handcraft `Contract<{ namespaces: { __unbound__: { id, tables, ... } } }>` literals to assert generic-inference shapes. Each namespace literal needs `kind: 'sql-namespace'` (SQL namespaces) or `kind: 'mongo-namespace'` (Mongo namespaces) added alongside `id`.
60
+ - Any inline-typed fixture file (`test/fixtures/*.d.ts`, etc.) that mirrors what the emitter would produce for testing.
61
+
62
+ ### Before 0.11
63
+
64
+ ```ts
65
+ type ContractUnderTest = Contract<
66
+ SqlStorage<string> & {
67
+ readonly namespaces: {
68
+ readonly __unbound__: {
69
+ readonly id: '__unbound__';
70
+ readonly tables: {
71
+ readonly user: {
72
+ // ... columns, primaryKey, etc.
73
+ };
74
+ };
75
+ };
76
+ };
77
+ readonly storageHash: StorageHash;
78
+ },
79
+ // ...
80
+ >;
81
+ ```
82
+
83
+ ### Starting at 0.11
84
+
85
+ ```ts
86
+ type ContractUnderTest = Contract<
87
+ SqlStorage<string> & {
88
+ readonly namespaces: {
89
+ readonly __unbound__: {
90
+ readonly id: '__unbound__';
91
+ readonly kind: 'sql-namespace'; // ← new: required
92
+ readonly tables: {
93
+ readonly user: {
94
+ // ... columns, primaryKey, etc.
95
+ };
96
+ };
97
+ };
98
+ };
99
+ readonly storageHash: StorageHash;
100
+ },
101
+ // ...
102
+ >;
103
+ ```
104
+
105
+ ### Mapping table
106
+
107
+ | Namespace family | Discriminator literal | Where it surfaces in handcrafted types |
108
+ |---|---|---|
109
+ | SQL (`SqlNamespace`, `SqlUnboundNamespace`) | `'sql-namespace'` | Anywhere you write `Contract<{ namespaces: { … } }>` with a SQL-style namespace |
110
+ | Mongo (`MongoNamespace`, `MongoUnboundNamespace`) | `'mongo-namespace'` | Anywhere you write `Contract<{ namespaces: { … } }>` with a Mongo-style namespace |
111
+ | Postgres (`PostgresSchema`, when handcrafted) | `'postgres-schema'` or `'postgres-unbound-schema'` | Rare in extension code; only needed if you handcraft a literal with a Postgres-specific namespace class |
112
+
113
+ ### Detection
114
+
115
+ Run the matcher's grep over your extension's source:
116
+
117
+ ```bash
118
+ rg --files-with-matches -t ts -e 'Contract<' -e 'namespaces' -g '**/*.test-d.ts'
119
+ ```
120
+
121
+ For each match, open the file and add the `kind` literal to every namespace entry under `namespaces:`. If you have many such literals, a regex-driven mechanical pass works (e.g. find every `readonly id: '<ns-id>';` inside a `namespaces:` block and inject `readonly kind: 'sql-namespace';` immediately after).
122
+
123
+ ### Why the change
124
+
125
+ The framework needs every namespace IR node to carry its family discriminator at the type level so that cross-family namespace walks (the new `elementCoordinates(storage)` surface in `@internal/framework-components/ir`) can dispatch on a known-present `kind`, not an optional one.
126
+
127
+ The runtime invariant has always held — every concrete namespace class sets `kind` non-enumerably via `Object.defineProperty(this, 'kind', { value, enumerable: false })` in its constructor. The type tightening makes the invariant honest at the consumer surface.
128
+
129
+ ### What you do **not** need to change
130
+
131
+ - No `.d.ts` regeneration is needed. Run `prisma-next contract emit` only as part of your normal authoring flow; the emitter handles the `kind` field for you.
132
+ - No `contract.json` snapshot changes. The hash inputs are unchanged because `kind` is non-enumerable on namespace class instances.
133
+ - No runtime API changes. Extension factories that construct namespaces via `new SqlStorage(...)`, `new PostgresSchema(...)`, etc. are unchanged — the constructors continue to materialise `kind` non-enumerably.
134
+
135
+ ## `facade-add-close-and-async-dispose`
136
+
137
+ Starting at the 0.11 release the three official facades (`postgres()`, `sqlite()`, `mongo()`) expose two new methods:
138
+
139
+ ```typescript
140
+ interface ClientFacade {
141
+ // ...existing surface...
142
+ close(): Promise<void>;
143
+ [Symbol.asyncDispose](): Promise<void>;
144
+ }
145
+ ```
146
+
147
+ This is the surface that lets a short-lived script (`tsx my-script.ts`) release facade-owned connection resources and exit cleanly. Without it, a `pg.Pool` (or analogous keep-alive in SQLite / Mongo) keeps Node's event loop alive and the script hangs after its last query prints.
148
+
149
+ If your extension exposes a facade in the same shape (e.g. you publish your own `postgresServerless()` or `someDriver()` factory that returns the same client object), add the equivalent surface. Three load-bearing properties:
150
+
151
+ 1. **Ownership rule.** `close()` releases only the resources the facade *itself* constructed. A `{ url }` (or similar opaque-string) binding means the facade opened the connection — facade owns it, `close()` disposes it. A `{ pool }` / `{ client }` / `{ mongoClient }` (caller-supplied opaque-handle) binding means the caller owns it — `close()` leaves it untouched. The facade must capture this ownership decision at construction time and remember it.
152
+
153
+ 2. **Idempotence.** `close()` can be called multiple times in a row without throwing. The second and later calls are no-ops.
154
+
155
+ 3. **Terminal closed state.** After `close()` resolves, the facade is permanently locked. Any subsequent `db.orm.X.<op>(...)`, `db.runtime()`, `db.connect()` call rejects with `Error('<target> client is closed')`. This catches use-after-close bugs cleanly instead of silently re-opening resources.
156
+
157
+ Reference implementations in this repo:
158
+
159
+ - `packages/3-extensions/postgres/src/runtime/postgres.ts` (full pattern; `{ url }` vs `{ pool }` ownership)
160
+ - `packages/3-extensions/sqlite/src/runtime/sqlite.ts` (only-`{ path }` shape; the facade always owns)
161
+ - `packages/3-extensions/mongo/src/runtime/mongo.ts` (`{ url }` vs `{ mongoClient }`)
162
+
163
+ The `[Symbol.asyncDispose]` alias is one line — delegate to `close()` — and enables the TS 5.2+ `await using db = yourFacade(...)` syntax. There is no good reason not to add both methods together.
164
+
165
+ ## `mongo-close-ownership-rule`
166
+
167
+ Before 0.11, `@internal/mongo`'s `db.close()` looked like this:
168
+
169
+ ```typescript
170
+ async close() {
171
+ try {
172
+ await runtimePromise;
173
+ await runtime.close(); // unconditional — closed any MongoClient, owned or not
174
+ } catch { /* swallow */ }
175
+ closed = true;
176
+ }
177
+ ```
178
+
179
+ From 0.11 it captures the ownership decision at construction time and only closes the `MongoClient` if the facade owns it:
180
+
181
+ ```typescript
182
+ let ownedDispose: (() => Promise<void>) | undefined;
183
+ if (resolvedBinding.kind === 'url') {
184
+ ownedDispose = () => driver.close();
185
+ }
186
+ // ...
187
+ async close() {
188
+ try {
189
+ await runtimePromise;
190
+ await ownedDispose?.(); // no-op when the caller supplied the MongoClient
191
+ } catch { /* swallow */ }
192
+ closed = true;
193
+ }
194
+ ```
195
+
196
+ **If your extension uses `mongo({ mongoClient: someClient })`** and previously called `db.close()` expecting `someClient` to be closed, your test suite will now show the `MongoClient` outliving the facade. Two ways to migrate:
197
+
198
+ - **Switch to a `{ url }` binding.** If your extension constructs the `MongoClient` purely to hand it to `mongo()`, drop the manual construction — pass the connection string in `{ url }` and let the facade own the client.
199
+ - **Close the `MongoClient` explicitly.** If your extension genuinely needs to share a `MongoClient` across multiple consumers (e.g. one client backs several `mongo()` facades, or the client is held in a higher-level connection-management seam), keep the `{ mongoClient }` binding and add `await someClient.close()` after your last facade is disposed.
200
+
201
+ No script — the right migration depends on why your extension was sharing the client in the first place. Walk the call sites by hand.
202
+
203
+ ## `insert-single-row-wrap-in-array`
204
+
205
+ Starting at the 0.11 release, the `.insert()` method on the SQL builder accepts **only** an array of row objects. The single-object overload that previously allowed `.insert({ field: value })` is removed.
206
+
207
+ Before 0.11:
208
+
209
+ ```ts
210
+ const ast = InsertAst.into(TableSource.named(tableName))
211
+ .insert({ field: value });
212
+ // or via the query builder:
213
+ db.sql.table.insert({ field: value }).build();
214
+ ```
215
+
216
+ Starting at 0.11:
217
+
218
+ ```ts
219
+ const ast = InsertAst.into(TableSource.named(tableName))
220
+ .insert([{ field: value }]);
221
+ // or via the query builder:
222
+ db.sql.table.insert([{ field: value }]).build();
223
+ ```
224
+
225
+ Walk every `.ts` / `.tsx` file matched by the `detection.glob` above. For each call site that passes a plain object directly to `.insert(...)`, wrap the argument in an array:
226
+
227
+ - `.insert(row)` → `.insert([row])`
228
+ - `.insert({ field: value })` → `.insert([{ field: value }])`
229
+
230
+ Variable references to a row object are safe to wrap directly:
231
+
232
+ ```ts
233
+ // Before
234
+ await runtime.execute(db.sql.table.insert(row).build());
235
+ // After
236
+ await runtime.execute(db.sql.table.insert([row]).build());
237
+ ```
238
+
239
+ If a call site already passes an array (`.insert([row1, row2])`), it is already correct — leave it unchanged.
240
+
241
+ TypeScript will report bare-object call sites as type errors after the bump, which is a reliable compile-time signal for every affected site.
242
+
243
+ ## `insert-ast-with-values-to-with-rows`
244
+
245
+ Starting at the 0.11 release, the `InsertAst.withValues(assignments)` method is removed. Extensions that build `InsertAst` directly via the AST layer must switch to `InsertAst.withRows([assignments])`.
246
+
247
+ Before 0.11:
248
+
249
+ ```ts
250
+ const ast = InsertAst.into(TableSource.named(tableName))
251
+ .withValues(createAssignments.assignments)
252
+ .withOnConflict(onConflict);
253
+ ```
254
+
255
+ Starting at 0.11:
256
+
257
+ ```ts
258
+ const ast = InsertAst.into(TableSource.named(tableName))
259
+ .withRows([createAssignments.assignments])
260
+ .withOnConflict(onConflict);
261
+ ```
262
+
263
+ The change is:
264
+ - Replace `.withValues(expr)` with `.withRows([expr])` — the single-row overload is removed; `withRows` accepts an array of assignment maps.
265
+
266
+ Walk every `.ts` / `.tsx` file matched by the `detection.glob` above. For each call site matching `.withValues(`, apply the replacement. The argument remains a single expression; it just needs to be wrapped in an array.
267
+
268
+ ### Validation
269
+
270
+ After applying the rules above, run `pnpm typecheck && pnpm test` (or your extension's equivalent). `prisma-8-check-pins` should also pass — the pin set is unchanged for this transition; the breaking change is in the `InsertAst` builder method surface, not the dependency contract.
271
+
272
+ ## Validation by execution
273
+
274
+ These entries are prose-only (no scripts). The substrate diff on `packages/3-extensions/` is additive (new methods on the three official facades) plus the Mongo behaviour change documented above; the `namespace-kind-required-on-handcrafted-contract-literals` entry covers a type-only tightening with no runtime substrate transform. There is no codemod to apply against a reverted substrate — the framework changes *are* the new surfaces, and these instructions describe the consumer-side translation, not a substrate transform.
275
+
276
+ The release-pipeline gate (`pnpm check:upgrade-coverage`) is satisfied by this directory existing with at least one entry. The substantive verification of the consumer-facing translation lives in the published skill's per-step bump-install-instructions-validate-commit loop, which runs in extension authors' own CI.