@prisma/orm-mongo 8.0.0-rc.5 → 8.0.0-rc.5-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +11 -10
- package/skills/prisma-8/SKILL.md +84 -0
- package/skills/prisma-8/references/build.md +142 -0
- package/skills/prisma-8/references/contract.md +417 -0
- package/skills/prisma-8/references/debug.md +141 -0
- package/skills/prisma-8/references/feedback.md +251 -0
- package/skills/prisma-8/references/migration-review.md +224 -0
- package/skills/prisma-8/references/migrations.md +519 -0
- package/skills/prisma-8/references/queries-mongo.md +236 -0
- package/skills/prisma-8/references/queries-postgres.md +415 -0
- package/skills/prisma-8/references/queries.md +168 -0
- package/skills/prisma-8/references/quickstart.md +326 -0
- package/skills/prisma-8/references/runtime.md +344 -0
- package/skills/prisma-8/references/supabase.md +244 -0
- package/skills/prisma-8/references/upgrade-app.md +101 -0
- package/skills/prisma-8/references/upgrade-extension.md +105 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.10-to-0.11/instructions.md +56 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/instructions.md +381 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/re-emit-closed-mongo-contracts.ts +202 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/re-emit-domain-namespaced-contracts.ts +201 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/re-emit-postgres-public-default.ts +198 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/strip-migration-labels-hints.ts +340 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.12-to-0.13/instructions.md +339 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.12-to-0.13/re-emit-mti-variant-link-columns.ts +229 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.13-to-0.14/instructions.md +543 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.13-to-0.14/migration-op-factories-to-methods.ts +290 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.13-to-0.14/uuid-preset-rename.ts +43 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.14-to-0.15/instructions.md +359 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.15-to-0.16/instructions.md +173 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.16-to-0.17/instructions.md +805 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.16-to-0.17/strip-sha256-hash-prefixes.ts +382 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.17-to-8.0.0-rc.1/instructions.md +72 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.7-to-0.8/instructions.md +8 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.8-to-0.9/instructions.md +36 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.8-to-0.9/strip-inline-contracts.ts +226 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.9-to-0.10/instructions.md +86 -0
- package/skills/prisma-8/upgrading/app/upgrades/0.9-to-0.10/stamp-storage-types-kind.ts +360 -0
- package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.1-to-8.0.0-rc.2/instructions.md +588 -0
- package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.2-to-8.0.0-rc.3/instructions.md +5 -0
- package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.3-to-8.0.0-rc.4/instructions.md +158 -0
- package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.4-to-8.0.0-rc.5/instructions.md +42 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.10-to-0.11/instructions.md +276 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/instructions.md +738 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/migrate-contract-testing-imports.ts +97 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/regenerate-extension-public-baseline.ts +223 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/strip-migration-labels-hints.ts +340 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.12-to-0.13/instructions.md +266 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.13-to-0.14/instructions.md +522 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.13-to-0.14/migration-op-factories-to-methods.ts +290 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.13-to-0.14/uuid-preset-rename.ts +43 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.14-to-0.15/instructions.md +803 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.15-to-0.16/instructions.md +219 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.16-to-0.17/instructions.md +731 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.16-to-0.17/strip-sha256-hash-prefixes.ts +382 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.17-to-8.0.0-rc.1/instructions.md +194 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.7-to-0.8/instructions.md +8 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.8-to-0.9/instructions.md +57 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.8-to-0.9/strip-inline-contracts.ts +226 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.9-to-0.10/instructions.md +150 -0
- package/skills/prisma-8/upgrading/extension/upgrades/0.9-to-0.10/stamp-storage-types-kind.ts +360 -0
- package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.1-to-8.0.0-rc.2/instructions.md +746 -0
- package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.2-to-8.0.0-rc.3/instructions.md +5 -0
- package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.3-to-8.0.0-rc.4/instructions.md +137 -0
- 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.
|