@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,340 @@
1
+ /**
2
+ * Brings on-disk `migration.json` manifests into the slimmed 0.12 metadata
3
+ * model: drops the now-removed `labels` and `hints` keys and recomputes
4
+ * `migrationHash` over the surviving metadata envelope + sibling `ops.json`.
5
+ *
6
+ * Background: starting at the 0.12 release the migration manifest schema is
7
+ * closed (`'+': 'reject'`) — `labels` and `hints` are no longer part of the
8
+ * model, so any manifest still carrying either key fails to load with
9
+ * `INVALID_MANIFEST` naming the offending key. The two fields also no longer
10
+ * participate in the content-addressed migration identity: `migrationHash` is
11
+ * now computed over `{ from, to, providedInvariants, createdAt }` plus the
12
+ * sibling operations, so every migrated manifest gets a freshly recomputed
13
+ * hash over the slimmed envelope.
14
+ *
15
+ * Before 0.12 the on-disk shape was:
16
+ *
17
+ * {
18
+ * "from": null,
19
+ * "to": "sha256:…",
20
+ * "labels": [],
21
+ * "providedInvariants": ["…"],
22
+ * "createdAt": "2026-…",
23
+ * "hints": { "used": [], "applied": [], "plannerVersion": "2.0.0" },
24
+ * "migrationHash": "sha256:…"
25
+ * }
26
+ *
27
+ * Starting at 0.12 the same manifest is:
28
+ *
29
+ * {
30
+ * "from": null,
31
+ * "to": "sha256:…",
32
+ * "providedInvariants": ["…"],
33
+ * "createdAt": "2026-…",
34
+ * "migrationHash": "sha256:…" // recomputed over the slimmed envelope
35
+ * }
36
+ *
37
+ * Format-preserving edit: rather than reparse-and-reserialise (which would
38
+ * reflow every value to a single canonical style and bloat the diff), this
39
+ * codemod performs a surgical text edit — it removes only the `labels` and
40
+ * `hints` top-level key lines and swaps the `migrationHash` value in place.
41
+ * Every other byte (key order, indentation, and whether arrays like
42
+ * `providedInvariants` are written inline or expanded) is left exactly as the
43
+ * authoring tool wrote it, so the diff is limited to the two removed keys and
44
+ * the new hash value.
45
+ *
46
+ * Confinement: an on-disk migration package is a `migration.json` paired with
47
+ * a sibling `ops.json` (the operations the hash is computed over). The walk
48
+ * keys off that pair rather than off a `migrations/` directory name, because
49
+ * migration packages live under several roots in practice (`migrations/`,
50
+ * `migration-fixtures/`, …); a `migration.json` with no sibling `ops.json` is
51
+ * not a complete package and is left untouched.
52
+ *
53
+ * The hash algorithm is replicated inline (canonicalisation rules from
54
+ * `@internal/framework-components` `canonicalizeJson` + the migration-tools
55
+ * `computeMigrationHash`) so this script stays self-contained — consumers run
56
+ * it via `pnpm exec tsx` from their project root with no dependency on any
57
+ * `@internal/*` package being resolvable from that root.
58
+ *
59
+ * The codemod is idempotent: an already-slimmed manifest carries no
60
+ * `labels`/`hints` and already has its recomputed hash, so the edit is a no-op
61
+ * and the file is left untouched.
62
+ *
63
+ * Flags:
64
+ * --check dry-run; lists manifests that still need fixing and exits 1 if
65
+ * any remain.
66
+ */
67
+ import { createHash } from 'node:crypto';
68
+ import { readdir, readFile, writeFile } from 'node:fs/promises';
69
+ import { dirname, join } from 'node:path';
70
+
71
+ const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build']);
72
+
73
+ const dryRun = process.argv.includes('--check');
74
+ const projectRoot = process.cwd();
75
+
76
+ // --- Inline canonicalisation + hash --------------------------------------
77
+ // Replicated from `@internal/framework-components` `canonicalizeJson`
78
+ // (sortKeys + JSON.stringify) and the migration-tools `computeMigrationHash`.
79
+ // Kept inline so the script has no `@internal/*` import — pnpm's strict
80
+ // node_modules layout won't resolve transitive framework deps from a
81
+ // consumer's project root.
82
+
83
+ function sortKeys(value: unknown): unknown {
84
+ if (value === null || typeof value !== 'object') {
85
+ return value;
86
+ }
87
+ if (Array.isArray(value)) {
88
+ return value.map(sortKeys);
89
+ }
90
+ const sorted: Record<string, unknown> = Object.create(null);
91
+ for (const [key, entry] of Object.entries(value).sort(([a], [b]) =>
92
+ a < b ? -1 : a > b ? 1 : 0,
93
+ )) {
94
+ sorted[key] = sortKeys(entry);
95
+ }
96
+ return sorted;
97
+ }
98
+
99
+ function canonicalizeJson(value: unknown): string {
100
+ return JSON.stringify(sortKeys(value));
101
+ }
102
+
103
+ function sha256Hex(input: string): string {
104
+ return createHash('sha256').update(input).digest('hex');
105
+ }
106
+
107
+ /**
108
+ * Content-addressed migration hash over (metadata envelope, ops). The
109
+ * `migrationHash` field is stripped before hashing so the same function works
110
+ * at write time (no hash yet) and at recompute time (rehashing an
111
+ * already-attested record over the slimmed envelope).
112
+ */
113
+ function computeMigrationHash(metadata: Record<string, unknown>, ops: unknown): string {
114
+ const { migrationHash: _migrationHash, ...strippedMeta } = metadata;
115
+
116
+ const partHashes = [canonicalizeJson(strippedMeta), canonicalizeJson(ops)].map(sha256Hex);
117
+ return `sha256:${sha256Hex(canonicalizeJson(partHashes))}`;
118
+ }
119
+
120
+ // --- Format-preserving text surgery --------------------------------------
121
+
122
+ /**
123
+ * Returns the index just past the end of the JSON value that starts at
124
+ * `start` (which must point at the value's first character). Handles strings
125
+ * (with escapes), nested objects/arrays, and primitives. Used to locate the
126
+ * full span of a top-level key's value when removing the key from the raw
127
+ * text without reparsing the whole document.
128
+ */
129
+ function scanValueEnd(text: string, start: number): number {
130
+ const c = text[start];
131
+
132
+ if (c === '"') {
133
+ let i = start + 1;
134
+ while (i < text.length) {
135
+ if (text[i] === '\\') {
136
+ i += 2;
137
+ continue;
138
+ }
139
+ if (text[i] === '"') return i + 1;
140
+ i += 1;
141
+ }
142
+ throw new Error('unterminated string while scanning JSON value');
143
+ }
144
+
145
+ if (c === '{' || c === '[') {
146
+ const open = c;
147
+ const close = c === '{' ? '}' : ']';
148
+ let depth = 0;
149
+ let i = start;
150
+ while (i < text.length) {
151
+ const ch = text[i];
152
+ if (ch === '"') {
153
+ i = scanValueEnd(text, i);
154
+ continue;
155
+ }
156
+ if (ch === open) depth += 1;
157
+ else if (ch === close) {
158
+ depth -= 1;
159
+ if (depth === 0) return i + 1;
160
+ }
161
+ i += 1;
162
+ }
163
+ throw new Error('unterminated container while scanning JSON value');
164
+ }
165
+
166
+ // Primitive (number / true / false / null) — run to the next structural
167
+ // terminator.
168
+ let i = start;
169
+ while (i < text.length && !',}]\r\n \t'.includes(text[i]!)) i += 1;
170
+ return i;
171
+ }
172
+
173
+ /**
174
+ * Removes a top-level object key (and its value) from `text`, preserving the
175
+ * surrounding bytes exactly. No-op (returns `text`) if the key is absent.
176
+ * Only the top-level `labels` / `hints` keys are ever passed here; both always
177
+ * precede the trailing `migrationHash` key, so a removed key always carries a
178
+ * trailing comma that is consumed along with the line.
179
+ */
180
+ function removeTopLevelKey(text: string, key: string): string {
181
+ // A top-level key is the only occurrence of `"key":` preceded by a newline
182
+ // (line 1 is the opening `{`). Tolerant of any indentation width.
183
+ const re = new RegExp(`\\n([ \\t]*)"${key}"[ \\t]*:[ \\t]*`);
184
+ const match = re.exec(text);
185
+ if (match === null) return text;
186
+
187
+ const lineStart = match.index + 1; // position just after the leading newline
188
+ const valueStart = match.index + match[0].length;
189
+ let after = scanValueEnd(text, valueStart);
190
+
191
+ while (text[after] === ' ' || text[after] === '\t') after += 1;
192
+ if (text[after] === ',') after += 1;
193
+ if (text[after] === '\r') after += 1;
194
+ if (text[after] === '\n') after += 1;
195
+
196
+ return text.slice(0, lineStart) + text.slice(after);
197
+ }
198
+
199
+ function replaceMigrationHash(text: string, oldHash: string, newHash: string): string {
200
+ if (oldHash === newHash) return text;
201
+ // Tolerate any whitespace around the colon (`"migrationHash":"…"`,
202
+ // `"migrationHash" : "…"`), matching the leniency of `removeTopLevelKey`.
203
+ const escapedOld = oldHash.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
204
+ const re = new RegExp(`("migrationHash"[ \\t]*:[ \\t]*)"${escapedOld}"`);
205
+ const match = re.exec(text);
206
+ if (match === null) {
207
+ throw new Error('could not locate the migrationHash value to replace');
208
+ }
209
+ return text.replace(re, (_full, prefix: string) => `${prefix}"${newHash}"`);
210
+ }
211
+
212
+ // --- Filesystem walk ------------------------------------------------------
213
+
214
+ async function findMigrationManifests(root: string): Promise<string[]> {
215
+ const out: string[] = [];
216
+
217
+ async function walk(dir: string): Promise<void> {
218
+ let entries: Awaited<ReturnType<typeof readdir>>;
219
+ try {
220
+ entries = await readdir(dir, { withFileTypes: true });
221
+ } catch {
222
+ // Unreadable directory — skip silently. The consumer's project root may
223
+ // legitimately contain restricted directories.
224
+ return;
225
+ }
226
+ for (const entry of entries) {
227
+ if (entry.isDirectory()) {
228
+ if (SKIP_DIRS.has(entry.name)) continue;
229
+ await walk(join(dir, entry.name));
230
+ } else if (entry.isFile() && entry.name === 'migration.json') {
231
+ out.push(join(dir, entry.name));
232
+ }
233
+ }
234
+ }
235
+
236
+ await walk(root);
237
+ return out.sort();
238
+ }
239
+
240
+ // --- Per-file transform ---------------------------------------------------
241
+
242
+ /** Narrows an arbitrary JSON-parsed value to a plain object (manifest shape). */
243
+ function isJsonObject(value: unknown): value is Record<string, unknown> {
244
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
245
+ }
246
+
247
+ type Status = 'already-clean' | 'needs-fix' | 'fixed' | 'skipped-no-ops';
248
+
249
+ interface Result {
250
+ readonly path: string;
251
+ readonly status: Status;
252
+ }
253
+
254
+ async function processFile(path: string): Promise<Result> {
255
+ const raw = await readFile(path, 'utf-8');
256
+
257
+ let parsed: unknown;
258
+ try {
259
+ parsed = JSON.parse(raw);
260
+ } catch (error) {
261
+ throw new Error(
262
+ `${path}: not valid JSON (${error instanceof Error ? error.message : String(error)})`,
263
+ );
264
+ }
265
+ if (!isJsonObject(parsed)) {
266
+ return { path, status: 'already-clean' }; // not a manifest object
267
+ }
268
+ const metadata = parsed;
269
+
270
+ // A complete on-disk migration package pairs `migration.json` with a sibling
271
+ // `ops.json` (the operations the hash is computed over); without it we cannot
272
+ // recompute the hash, so this is not a package we should touch.
273
+ const opsPath = join(dirname(path), 'ops.json');
274
+ let ops: unknown;
275
+ try {
276
+ ops = JSON.parse(await readFile(opsPath, 'utf-8'));
277
+ } catch {
278
+ return { path, status: 'skipped-no-ops' };
279
+ }
280
+
281
+ // Recompute over the slimmed envelope (canonicalisation is order/whitespace
282
+ // independent, so the parsed object is the right input regardless of on-disk
283
+ // formatting). `computeMigrationHash` strips `migrationHash` internally.
284
+ const slimmed = { ...metadata };
285
+ delete slimmed['labels'];
286
+ delete slimmed['hints'];
287
+ const newHash = computeMigrationHash(slimmed, ops);
288
+
289
+ let out = raw;
290
+ out = removeTopLevelKey(out, 'labels');
291
+ out = removeTopLevelKey(out, 'hints');
292
+
293
+ const oldHash = metadata['migrationHash'];
294
+ if (typeof oldHash === 'string') {
295
+ out = replaceMigrationHash(out, oldHash, newHash);
296
+ } else if (out !== raw) {
297
+ // labels/hints were present but there is no string migrationHash to update
298
+ // — a malformed manifest we refuse to guess at.
299
+ throw new Error(`${path}: manifest is missing a string \`migrationHash\` field`);
300
+ }
301
+
302
+ if (out === raw) {
303
+ return { path, status: 'already-clean' };
304
+ }
305
+ if (!dryRun) await writeFile(path, out, 'utf-8');
306
+ return { path, status: dryRun ? 'needs-fix' : 'fixed' };
307
+ }
308
+
309
+ // --- Driver ---------------------------------------------------------------
310
+
311
+ const manifests = await findMigrationManifests(projectRoot);
312
+ if (manifests.length === 0) {
313
+ console.error(`No migration.json files found under ${projectRoot}.`);
314
+ process.exit(1);
315
+ }
316
+
317
+ let changed = 0;
318
+ let alreadyClean = 0;
319
+ let skipped = 0;
320
+ for (const path of manifests) {
321
+ const result = await processFile(path);
322
+ const rel = path.slice(projectRoot.length + 1);
323
+ if (result.status === 'already-clean') {
324
+ alreadyClean += 1;
325
+ } else if (result.status === 'skipped-no-ops') {
326
+ skipped += 1;
327
+ console.log(`SKIP ${rel} (no sibling ops.json — not a migration package)`);
328
+ } else {
329
+ changed += 1;
330
+ const verb = dryRun ? 'WOULD FIX' : 'FIXED';
331
+ console.log(`${verb} ${rel}`);
332
+ }
333
+ }
334
+
335
+ console.log();
336
+ console.log(
337
+ `${manifests.length} manifest(s) scanned: ${changed} ${dryRun ? 'needing fix' : 'fixed'}, ${alreadyClean} already clean${skipped > 0 ? `, ${skipped} skipped (no ops.json)` : ''}.`,
338
+ );
339
+
340
+ if (dryRun && changed > 0) process.exit(1);
@@ -0,0 +1,339 @@
1
+ ---
2
+ from: "0.12"
3
+ to: "0.13"
4
+ changes:
5
+ - id: sqlite-create-table-method
6
+ summary: |
7
+ SQLite migrations: `createTable` is no longer a free function exported from `@internal/sqlite/migration`. It is now a protected method on the `Migration` base class. Replace every free `createTable(...)` call in your SQLite migration files with `this.createTable({ table: ..., columns: [...], constraints: [...] })`. The `col()`, `lit()`, `fn()`, `primaryKey()`, `foreignKey()`, and `unique()` builder helpers are now exported from `@internal/sqlite/migration` directly, so your import line stays a single entry point.
8
+ detection:
9
+ glob: "**/migration.ts"
10
+ contains:
11
+ - "createTable"
12
+ - "@internal/sqlite/migration"
13
+ anyMatch: false
14
+ - id: re-emit-mti-variant-link-columns
15
+ summary: |
16
+ MTI variant models — PSL `@@base(Parent, "tag")` models that carry their own `@@map` and are therefore stored in their own table — now materialise base-PK link columns in storage. On re-emit, each such variant table gains a copy of the base table's full primary-key column set (same names and types), a primary key over those columns, and a cascading foreign key referencing the base table's primary key; the contract's `storageHash` changes accordingly. Re-emit your contract artefacts (`pnpm emit`), then advance your database with the corresponding migration (`prisma-next migration plan` → `prisma-next migrate`) so the variant tables gain the link column, PK, and cascading FK. Contracts whose variants share the base table (single-table inheritance, no own `@@map`) are unaffected.
17
+ detection:
18
+ glob: "**/contract.json"
19
+ contains:
20
+ - '"base":'
21
+ anyMatch: true
22
+ script: ./re-emit-mti-variant-link-columns.ts
23
+ - id: cross-space-fk-psl-pattern
24
+ summary: |
25
+ New opt-in PSL authoring pattern: reference a model from an extension contract space
26
+ (e.g. `supabase:auth.AuthUser`) in a relation field and declare a named-type alias
27
+ (`types { Uuid = String @db.Uuid }`) for database-native types. No action required
28
+ for consumers who do not use cross-space foreign keys; this entry documents the
29
+ pattern for new adopters.
30
+ - id: storage-namespace-envelope-re-emit
31
+ summary: |
32
+ The storage IR in `contract.json` moved to a namespace envelope
33
+ (`storage.namespaces.<ns>.entries.<kind>`). This changes `storageHash` for every
34
+ SQL and Mongo contract. Re-emit your contract artefacts (`prisma-next contract
35
+ emit`), then plan and apply the corresponding migration (`prisma-next migration
36
+ plan` → `prisma-next migrate`) so your database schema is reconciled with the new
37
+ contract shape. No source change is required — re-emitting is sufficient.
38
+ detection:
39
+ glob: "**/contract.json"
40
+ anyMatch: true
41
+ - id: telemetry-now-opt-out
42
+ summary: |
43
+ Telemetry is now opt-out by default. If you previously relied on the opt-in
44
+ default to keep telemetry off, set `PRISMA_NEXT_DISABLE_TELEMETRY=1` or
45
+ `DO_NOT_TRACK=1` in your environment to restore that behaviour. No code change
46
+ is required.
47
+ ---
48
+
49
+ <!--
50
+ TML-2500(M3b): advances the `examples/supabase` walking skeleton to wire a
51
+ cross-space FK from `public.Profile.userId` to `supabase:auth.AuthUser.id` with
52
+ a cascading delete. The diff is new sample code that exercises a capability
53
+ shipped in M2/M3a — no existing consumer has cross-space FKs to migrate. This
54
+ entry serves as the canonical first-use reference for the PSL authoring pattern.
55
+
56
+ dependabot/runtime-deps: bumped pg 8.20→8.21, pg-cursor 2.19→2.20, vitest 4.1.6→4.1.7,
57
+ vite 8.0.13→8.0.15, tsdown 0.22.0→0.22.1, tsx 4.22.3→4.22.4, next 16.2.4→16.2.6,
58
+ postcss 8.5.14→8.5.15, evlog 2.16.0→2.18.1, @prisma/dev 0.24.7→0.24.8,
59
+ @types/node 25.6.0→25.9.1 — all incidental to examples; no user-side action required.
60
+
61
+ TML-2808: the SQL/Mongo contract storage IR moved to a namespace
62
+ envelope (`namespaces.<ns>.entries.<kind>`) and lifted cross-references
63
+ from bare strings to `{ namespace, model }` objects in `domain`.
64
+ Consumer impact is incidental: re-emitting `contract.json` /
65
+ `contract.d.ts` via the existing `prisma-next contract emit` produces
66
+ the new shape with no source change. No codemod is required.
67
+
68
+ TML-2834: scaffolds the new `@internal/extension-supabase` package
69
+ and adds `examples/supabase` as the Supabase walking-skeleton app. Two
70
+ enabling framework changes ride along: (a) the emitter now emits
71
+ multi-namespace contracts (single-namespace output is byte-identical),
72
+ and (b) `db init` / `db verify` introspect all declared namespaces
73
+ across a composed contract aggregate instead of only `public`. Both
74
+ are forward-compatible — single-namespace contracts emit byte-identical
75
+ output and introspect through the same path as before. The new
76
+ extension package is purely additive (consumers opt in by adding
77
+ `extensionPacks: [supabasePack]`). No codemod or user-side action
78
+ required.
79
+
80
+ TML-2754: points stale migration tests at the post-#751
81
+ `SqlControlAdapter` API (`createPlanner(controlAdapter)` and the
82
+ `adapter` option on `executeDbInit`/`executeDbUpdate`). Touches
83
+ `examples/multi-extension-monorepo/test/` only — a test-only diff with
84
+ no runtime, contract, or public-API change; incidental to examples, no
85
+ user-side action required.
86
+
87
+ dependabot/runtime-deps (PR #761): bumps react 19.2.6→19.2.7, vitest
88
+ 4.1.7→4.1.8, next 16.2.6→16.2.7, react-router 7.15.1→7.16.0, vite
89
+ 8.0.15→8.0.16, lucide-react 1.16.0→1.17.0, @prisma/dev 0.24.8→0.24.9,
90
+ mongodb-memory-server 11.1.0→11.2.0. Touches examples/ only via
91
+ package.json version fields; no runtime, contract, or public-API change.
92
+
93
+ TML-2838: regenerates example-app migration snapshots via pnpm
94
+ fixtures:emit. The prisma-8-demo initial migration was updated from
95
+ the removed standalone createTable function to this.createTable({...})
96
+ (the base-class method introduced by the planner-create-table-adopts-ddl-ast
97
+ refactor). The ops.json snapshots are regenerated accordingly. No
98
+ user-side action required.
99
+
100
+ TML-2843: `@internal/sqlite` gained an additive facade transaction
101
+ API (`db.transaction(async (tx) => …)`) demonstrated in
102
+ `examples/prisma-8-demo-sqlite`. No user action required; incidental
103
+ substrate diff.
104
+
105
+ Release bump 0.13.0 (#789): version-number changes across all workspace
106
+ `package.json` files and `pnpm-lock.yaml` specifiers; the
107
+ `examples/supabase/src/contract.json` and `contract.d.ts` `version`
108
+ field updated to `0.13.0`. Incidental substrate diff — no user-side
109
+ action required.
110
+ -->
111
+
112
+ # 0.12 → 0.13 — User upgrade instructions
113
+
114
+ ## `sqlite-create-table-method`
115
+
116
+ Starting at this release, `createTable` is no longer a free function exported from `@internal/sqlite/migration`. It is now a protected method on the `Migration` base class — call it as `this.createTable({...})` inside `get operations()`.
117
+
118
+ The column builder helpers `col()`, `lit()`, `fn()`, `primaryKey()`, `foreignKey()`, and `unique()` are now exported from `@internal/sqlite/migration` directly, so you do not need an additional import.
119
+
120
+ ### Before 0.13
121
+
122
+ ```ts
123
+ import { Migration, MigrationCLI, createTable, col, primaryKey } from '@internal/sqlite/migration';
124
+
125
+ export default class M extends Migration {
126
+ override describe() { return { from: null, to: '...' }; }
127
+
128
+ override get operations() {
129
+ return [
130
+ createTable('user', [
131
+ col('id', 'INTEGER', { primaryKey: true }),
132
+ col('email', 'TEXT', { notNull: true }),
133
+ ]),
134
+ ];
135
+ }
136
+ }
137
+
138
+ MigrationCLI.run(import.meta.url, M);
139
+ ```
140
+
141
+ ### Starting at 0.13
142
+
143
+ ```ts
144
+ import { Migration, MigrationCLI, col, primaryKey } from '@internal/sqlite/migration';
145
+
146
+ export default class M extends Migration {
147
+ override describe() { return { from: null, to: '...' }; }
148
+
149
+ override get operations() {
150
+ return [
151
+ this.createTable({
152
+ table: 'user',
153
+ columns: [
154
+ col('id', 'INTEGER', { primaryKey: true }),
155
+ col('email', 'TEXT', { notNull: true }),
156
+ ],
157
+ }),
158
+ ];
159
+ }
160
+ }
161
+
162
+ MigrationCLI.run(import.meta.url, M);
163
+ ```
164
+
165
+ ### Migration steps
166
+
167
+ 1. Remove `createTable` from the import list for `@internal/sqlite/migration`.
168
+ 2. In `get operations()`, replace each `createTable(tableName, columns, constraints?)` call with `this.createTable({ table: tableName, columns, constraints? })`.
169
+ 3. Run `pnpm typecheck && pnpm test` to confirm the migration compiled and all tests pass.
170
+
171
+ TypeScript flags the removed `createTable` import as an error after the bump, so every affected call site is pinpointed at compile time. No contract re-emit is required — this is an authoring-surface change only.
172
+
173
+ ## `re-emit-mti-variant-link-columns`
174
+
175
+ Starting at this release, a Multi-Table Inheritance (MTI) variant model stores an explicit link to its base row. An MTI variant is a PSL model that declares `@@base(Parent, "tag")` **and** carries its own `@@map`, so it lives in a dedicated table rather than sharing the base table:
176
+
177
+ ```prisma
178
+ model Task {
179
+ id String @id @default(uuid())
180
+ type String
181
+ // …
182
+ @@discriminator(type)
183
+ @@map("task")
184
+ }
185
+
186
+ model Bug {
187
+ severity String
188
+ @@base(Task, "bug")
189
+ @@map("bug")
190
+ }
191
+ ```
192
+
193
+ Before this release, the `bug` table held only the variant-specific columns (`severity`, …) with **no primary key** and no relationship to `task`. From this release on, re-emitting the contract materialises the base-PK link in the variant's storage table:
194
+
195
+ - a copy of the base table's full primary-key column set — the same column names and types (one column for a single-column PK like `id`, or every component for a composite PK),
196
+ - a primary key over those link columns,
197
+ - a cascading foreign key (`ON DELETE CASCADE`) from those columns to the base table's matching primary-key columns.
198
+
199
+ The variant row's link columns mirror its parent base row's primary key — the same identity links a `task` row to its `bug`/`feature` detail row. This is the storage shape the runtime already assumed when writing base + variant rows together; the change makes it explicit and enforced at the database level.
200
+
201
+ Single-table inheritance variants — `@@base(...)` models **without** their own `@@map`, which share the base table — are unaffected: there is no separate table to link.
202
+
203
+ ### Re-emit your contracts
204
+
205
+ Run the colocated script from your project root:
206
+
207
+ ```bash
208
+ pnpm exec tsx ./re-emit-mti-variant-link-columns.ts
209
+ ```
210
+
211
+ It walks the project for `prisma.config.ts` directories, resolves each space's committed `contract.json`, and re-emits any contract whose MTI variant table still lacks its link column (an MTI variant model whose storage table has no `primaryKey`). It prefers a package's `emit` script when present, otherwise runs `prisma-next contract emit --config <path>`.
212
+
213
+ Use `--check` for a dry-run that lists the contract-spaces still needing re-emit and exits non-zero if any remain:
214
+
215
+ ```bash
216
+ pnpm exec tsx ./re-emit-mti-variant-link-columns.ts --check
217
+ ```
218
+
219
+ The regenerated `contract.json` gains the variant's link columns (the base PK's column set), their primary key, and the cascading foreign key under `storage.namespaces.<ns>.tables.<variant>`, and the contract's `storageHash` changes. `contract.d.ts` picks up the new columns on the variant's row type.
220
+
221
+ ### Migrate your database
222
+
223
+ Re-emitting changes `storageHash`, so your live database needs the matching schema change. Plan and apply it:
224
+
225
+ ```bash
226
+ prisma-next migration plan --name mti-variant-link-columns
227
+ prisma-next migrate
228
+ ```
229
+
230
+ The plan adds the variant's link columns, sets them `NOT NULL`, adds the primary key over them, and adds the cascading foreign key to the base table.
231
+
232
+ A variant row's link columns **must equal its parent base row's primary key** — that shared identity is what links a `task` row to its `bug`/`feature` detail row, and the cascading foreign key to the base table enforces it. There is therefore no correct backfill, and you must **never fabricate** the link values (for example with `gen_random_uuid()`): fabricated values have no matching base row, so the validating foreign key in this same migration would immediately reject them.
233
+
234
+ The runtime always wrote each variant row together with its base row, sharing the same primary-key values. On a database provisioned that way there are no rows missing the link columns, so the `SET NOT NULL` step is a no-op and the migration applies cleanly with no backfill. Author the migration with no `dataTransform` — just `addColumn` (nullable) → `setNotNull` → primary key → foreign key — then run `node <migration>.ts` (or `pnpm exec tsx <migration>.ts`) to self-emit `ops.json` and attest the package before `prisma-next migrate`.
235
+
236
+ If your database does hold variant rows that predate the link columns, they are unlinkable orphans — nothing in those rows maps them back to their base row. The `SET NOT NULL` precheck ("ensure no NULL values") halts the migration before any destructive step. Resolve those rows by hand — map each to the correct base primary key, or delete it — and re-run. Do not paper over the halt with fabricated link values.
237
+
238
+ ### Validation
239
+
240
+ After re-emitting and migrating, run `pnpm typecheck && pnpm test` (or your application's equivalent), then `prisma-next migration check` to confirm the on-disk chain is consistent. Inspect the `contract.json` diff: each MTI variant table should carry the base PK's link columns, a `primaryKey` over them, and a cascading `foreignKey` to its base table.
241
+
242
+ ## `cross-space-fk-psl-pattern`
243
+
244
+ This release ships PSL support for referencing a model from an extension contract space (e.g. `supabase:auth.AuthUser`) in a relation field, together with named-type aliases for database-native column types.
245
+
246
+ **This entry is informational.** No existing consumer has cross-space foreign keys to change — this is a new opt-in capability. Adopt it when you want a field in your model to reference a row owned by an extension (such as Supabase's `auth.users` table).
247
+
248
+ ### Named-type aliases
249
+
250
+ Declare a `types` block at the top of your `contract.prisma` to give a database-native type a reusable name:
251
+
252
+ ```prisma
253
+ types {
254
+ Uuid = String @db.Uuid
255
+ }
256
+ ```
257
+
258
+ You can then use `Uuid` as a field type anywhere in the same contract. On emit the column receives `nativeType: "uuid"` in `contract.json`.
259
+
260
+ ### Cross-space relation field
261
+
262
+ Reference another contract space's model using the `<space>:<namespace>.<Model>` syntax in a relation field. The relation requires `extensionPacks` to declare the dependency on the space:
263
+
264
+ ```prisma
265
+ // Before (no cross-space FK)
266
+ namespace public {
267
+ model Profile {
268
+ id String @id @default(uuid())
269
+ username String
270
+ @@map("profile")
271
+ }
272
+ }
273
+
274
+ // After (cross-space FK to supabase:auth.AuthUser)
275
+ types {
276
+ Uuid = String @db.Uuid
277
+ }
278
+
279
+ namespace public {
280
+ model Profile {
281
+ id String @id @default(uuid())
282
+ username String
283
+ userId Uuid @unique
284
+ user supabase:auth.AuthUser @relation(fields: [userId], references: [id], onDelete: Cascade)
285
+ @@map("profile")
286
+ }
287
+ }
288
+ ```
289
+
290
+ On emit, `contract.json` gains:
291
+ - A `types.Uuid` entry under `storage` for the named-type alias.
292
+ - The `userId` column with `typeRef: "Uuid"` on the storage table.
293
+ - A cross-space `foreignKey` entry on the storage table pointing at the extension space's table.
294
+
295
+ Run `prisma-next contract emit` after updating `contract.prisma`, then plan and apply the migration (`prisma-next migration plan --name add-user-fk && prisma-next migrate`) to add the column and foreign key to your database.
296
+
297
+ ## `storage-namespace-envelope-re-emit`
298
+
299
+ The storage IR inside `contract.json` moved to a namespace envelope in 0.13. Every
300
+ table and type entry that was previously at the top level of `storage` now lives under
301
+ `storage.namespaces.<ns>.entries.<kind>`. Cross-references that were bare strings are
302
+ now `{ namespace, model }` objects in `domain`. The emitter handles this automatically
303
+ — no schema source change is needed.
304
+
305
+ Because the shape change affects `storageHash`, every SQL and Mongo contract must be
306
+ re-emitted, and the database must be migrated to match.
307
+
308
+ ### Re-emit your contract
309
+
310
+ ```bash
311
+ prisma-next contract emit
312
+ ```
313
+
314
+ ### Migrate your database
315
+
316
+ ```bash
317
+ prisma-next migration plan --name storage-namespace-envelope
318
+ prisma-next migrate
319
+ ```
320
+
321
+ The migration records the hash transition; no column or table is added or removed — this
322
+ is a metadata-only change. Confirm with `prisma-next migration check` once done.
323
+
324
+ ## `telemetry-now-opt-out`
325
+
326
+ **Informational — no code change required.**
327
+
328
+ Starting at 0.13, the CLI collects anonymised usage telemetry by default (previously
329
+ opt-in). If you want to disable it, set either of the following environment variables:
330
+
331
+ ```bash
332
+ PRISMA_NEXT_DISABLE_TELEMETRY=1
333
+ # or
334
+ DO_NOT_TRACK=1
335
+ ```
336
+
337
+ Either variable takes effect immediately — no config file change needed. See
338
+ [Telemetry](https://github.com/prisma/prisma/blob/main/docs/Telemetry.md) for
339
+ what is collected and how to opt out permanently.