@prisma/orm-mongo 8.0.0-rc.4-dev.17 → 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.
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,360 @@
1
+ /**
2
+ * Stamps the `kind` discriminator on every entry in `storage.types`
3
+ * inside every on-disk contract snapshot reachable from the project
4
+ * root (`start-contract.json` / `end-contract.json` under any
5
+ * `migrations/` directory).
6
+ *
7
+ * Background: starting at the 0.10 release, the SQL family's
8
+ * `SqlStorage.types` polymorphic slot is strictly typed via an
9
+ * enumerable `kind` discriminator (`'codec-instance'` for codec
10
+ * triples; `'postgres-enum'` for Postgres enums). The family
11
+ * `ContractSerializer` rejects untagged entries with a diagnostic
12
+ * naming the offending entry — the previous silent fallthrough in
13
+ * `normaliseTypeEntry` is gone. See TML-2536.
14
+ *
15
+ * Before 0.10, the on-disk shape was:
16
+ *
17
+ * "storage": {
18
+ * "types": {
19
+ * "Embedding1536": {
20
+ * "codecId": "pg/vector@1",
21
+ * "nativeType": "vector",
22
+ * "typeParams": { "length": 1536 }
23
+ * },
24
+ * "user_type": {
25
+ * "codecId": "pg/enum@1",
26
+ * "nativeType": "user_type",
27
+ * "typeParams": { "values": ["admin", "user"] }
28
+ * }
29
+ * }
30
+ * }
31
+ *
32
+ * Starting at 0.10 the same entries are:
33
+ *
34
+ * "storage": {
35
+ * "types": {
36
+ * "Embedding1536": {
37
+ * "kind": "codec-instance",
38
+ * "codecId": "pg/vector@1",
39
+ * "nativeType": "vector",
40
+ * "typeParams": { "length": 1536 }
41
+ * },
42
+ * "user_type": {
43
+ * "kind": "postgres-enum",
44
+ * "name": "user_type",
45
+ * "nativeType": "user_type",
46
+ * "values": ["admin", "user"],
47
+ * "codecId": "pg/enum@1"
48
+ * }
49
+ * }
50
+ * }
51
+ *
52
+ * Dispatch rules (per entry):
53
+ *
54
+ * - Already-stamped entry (carries a `kind` field) → left untouched.
55
+ * - `codecId === "pg/enum@1"` → rewritten as the `postgres-enum`
56
+ * shape: `kind`, `name` (lifted from the entry key), `nativeType`,
57
+ * `values` (lifted out of `typeParams.values`), `codecId`.
58
+ * `typeParams` is dropped (its only meaningful content was `values`).
59
+ * - Any other `codecId` → rewritten as the `codec-instance` shape:
60
+ * `kind` prepended; `codecId`, `nativeType`, `typeParams` preserved.
61
+ * This is the safe default for unknown codec IDs (including any
62
+ * future extension-contributed codecs).
63
+ *
64
+ * The transformation re-serialises each affected file via
65
+ * `JSON.stringify(value, null, 2) + '\n'` — the same formatting the
66
+ * CLI uses when authoring snapshots originally, so the diff outside
67
+ * `storage.types` is zero on files the CLI generated. Hand-edited
68
+ * contract snapshots may experience cosmetic whitespace shifts; this
69
+ * is acceptable because on-disk contract snapshots are CLI-authored
70
+ * artefacts, not user-edited source.
71
+ *
72
+ * The codemod is idempotent: running it on already-stamped snapshots
73
+ * is a no-op (every entry passes the `kind`-already-present check).
74
+ *
75
+ * Flags:
76
+ * --check dry-run; lists affected files and exits 1 if any still
77
+ * need fixing.
78
+ */
79
+ import { readdir, readFile, writeFile } from 'node:fs/promises';
80
+ import { join } from 'node:path';
81
+
82
+ const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build']);
83
+ const CONTRACT_FILES = new Set(['start-contract.json', 'end-contract.json']);
84
+
85
+ const POSTGRES_ENUM_CODEC_ID = 'pg/enum@1';
86
+
87
+ const dryRun = process.argv.includes('--check');
88
+ const projectRoot = process.cwd();
89
+
90
+ interface Result {
91
+ readonly path: string;
92
+ readonly status: 'already-clean' | 'needs-fix' | 'fixed';
93
+ readonly stamped: number;
94
+ }
95
+
96
+ async function findContractSnapshots(root: string): Promise<string[]> {
97
+ const out: string[] = [];
98
+
99
+ // The `inMigrations` flag confines snapshot rewrites to the
100
+ // `migrations/` subtree the doc promises. Without the flag the walk
101
+ // would happily stamp any `start-contract.json` / `end-contract.json`
102
+ // found anywhere under the project root, including non-migration
103
+ // fixtures (e.g. inline contract test snapshots).
104
+ async function walk(dir: string, inMigrations: boolean): Promise<void> {
105
+ let entries: Awaited<ReturnType<typeof readdir>>;
106
+ try {
107
+ entries = await readdir(dir, { withFileTypes: true });
108
+ } catch {
109
+ // Unreadable directory — skip silently. Mirrors the predecessor
110
+ // 0.8→0.9 codemod's failure-tolerant walk; the user's project
111
+ // root may legitimately contain restricted directories.
112
+ return;
113
+ }
114
+ for (const entry of entries) {
115
+ if (entry.isDirectory()) {
116
+ if (SKIP_DIRS.has(entry.name)) continue;
117
+ await walk(join(dir, entry.name), inMigrations || entry.name === 'migrations');
118
+ } else if (inMigrations && entry.isFile() && CONTRACT_FILES.has(entry.name)) {
119
+ out.push(join(dir, entry.name));
120
+ }
121
+ }
122
+ }
123
+
124
+ await walk(root, false);
125
+ return out.sort();
126
+ }
127
+
128
+ interface UntaggedCodecTriple {
129
+ readonly codecId: string;
130
+ readonly nativeType: string;
131
+ readonly typeParams: Record<string, unknown>;
132
+ }
133
+
134
+ interface StampedCodecInstance {
135
+ readonly kind: 'codec-instance';
136
+ readonly codecId: string;
137
+ readonly nativeType: string;
138
+ readonly typeParams: Record<string, unknown>;
139
+ }
140
+
141
+ interface StampedPostgresEnum {
142
+ readonly kind: 'postgres-enum';
143
+ readonly name: string;
144
+ readonly nativeType: string;
145
+ readonly values: readonly string[];
146
+ readonly codecId: string;
147
+ }
148
+
149
+ type StampedEntry = StampedCodecInstance | StampedPostgresEnum;
150
+
151
+ function isAlreadyStamped(value: unknown): boolean {
152
+ if (typeof value !== 'object' || value === null) return false;
153
+ const kind = (value as { kind?: unknown }).kind;
154
+ return kind === 'codec-instance' || kind === 'postgres-enum';
155
+ }
156
+
157
+ function looksLikeUntaggedCodecTriple(value: unknown): value is UntaggedCodecTriple {
158
+ if (typeof value !== 'object' || value === null) return false;
159
+ const obj = value as Record<string, unknown>;
160
+ if (
161
+ typeof obj['codecId'] !== 'string' ||
162
+ typeof obj['nativeType'] !== 'string' ||
163
+ typeof obj['typeParams'] !== 'object' ||
164
+ obj['typeParams'] === null
165
+ ) {
166
+ return false;
167
+ }
168
+ // A `pg/enum@1` triple is only recognisable as an untagged enum if its
169
+ // `typeParams.values` is already a string[]. Without this guard a
170
+ // malformed enum entry would slip through the classifier and surface
171
+ // a different (more specific) diagnostic from `stampEntry` than the
172
+ // outer "neither stamped nor untagged-triple — hand-edit required"
173
+ // throw. Folding that case into the predicate gives every malformed
174
+ // entry the same single diagnostic shape.
175
+ if (obj['codecId'] === POSTGRES_ENUM_CODEC_ID) {
176
+ const values = (obj['typeParams'] as { values?: unknown })['values'];
177
+ if (!Array.isArray(values) || !values.every((v) => typeof v === 'string')) {
178
+ return false;
179
+ }
180
+ }
181
+ return true;
182
+ }
183
+
184
+ function stampEntry(name: string, raw: UntaggedCodecTriple): StampedEntry {
185
+ if (raw.codecId === POSTGRES_ENUM_CODEC_ID) {
186
+ const values = (raw.typeParams as { values?: unknown })['values'];
187
+ // Invariant: `looksLikeUntaggedCodecTriple` already gated this — a
188
+ // `pg/enum@1` entry that reaches `stampEntry` has a string[]
189
+ // `typeParams.values`. The runtime check stays as a defensive
190
+ // marker so a future loosening of the predicate doesn't silently
191
+ // produce a malformed StampedPostgresEnum.
192
+ if (!Array.isArray(values) || !values.every((v) => typeof v === 'string')) {
193
+ throw new Error(
194
+ `invariant: storage.types[${JSON.stringify(name)}] reached stampEntry with codecId="${POSTGRES_ENUM_CODEC_ID}" but typeParams.values is not a string[]; the classifier should have rejected this entry`,
195
+ );
196
+ }
197
+ return {
198
+ kind: 'postgres-enum',
199
+ name,
200
+ nativeType: raw.nativeType,
201
+ values,
202
+ codecId: raw.codecId,
203
+ };
204
+ }
205
+ return {
206
+ kind: 'codec-instance',
207
+ codecId: raw.codecId,
208
+ nativeType: raw.nativeType,
209
+ typeParams: raw.typeParams,
210
+ };
211
+ }
212
+
213
+ interface ProcessOutcome {
214
+ readonly transformed: Record<string, unknown> | null;
215
+ readonly stamped: number;
216
+ }
217
+
218
+ function processContract(parsed: unknown, filePath: string): ProcessOutcome {
219
+ if (typeof parsed !== 'object' || parsed === null) {
220
+ return { transformed: null, stamped: 0 };
221
+ }
222
+ const root = parsed as Record<string, unknown>;
223
+ const storage = root['storage'];
224
+ if (typeof storage !== 'object' || storage === null) {
225
+ return { transformed: null, stamped: 0 };
226
+ }
227
+ const storageObj = storage as Record<string, unknown>;
228
+ const types = storageObj['types'];
229
+ if (typeof types !== 'object' || types === null) {
230
+ return { transformed: null, stamped: 0 };
231
+ }
232
+ const typesObj = types as Record<string, unknown>;
233
+
234
+ let stamped = 0;
235
+ const newTypes: Record<string, unknown> = {};
236
+ for (const [name, entry] of Object.entries(typesObj)) {
237
+ if (isAlreadyStamped(entry)) {
238
+ newTypes[name] = entry;
239
+ continue;
240
+ }
241
+ if (!looksLikeUntaggedCodecTriple(entry)) {
242
+ throw new Error(
243
+ `${filePath}: storage.types[${JSON.stringify(name)}] is neither a stamped entry nor an untagged codec triple — refusing to guess. Hand-edit required.`,
244
+ );
245
+ }
246
+ newTypes[name] = stampEntry(name, entry);
247
+ stamped += 1;
248
+ }
249
+
250
+ if (stamped === 0) return { transformed: null, stamped: 0 };
251
+
252
+ return {
253
+ transformed: { ...root, storage: { ...storageObj, types: newTypes } },
254
+ stamped,
255
+ };
256
+ }
257
+
258
+ /**
259
+ * Pretty-print JSON with multi-line objects/arrays (per
260
+ * `JSON.stringify(null, 2)` conventions) but inline arrays of primitives
261
+ * (strings, numbers, booleans, null) whose serialised length fits
262
+ * within `INLINE_ARRAY_THRESHOLD`. This matches the on-disk shape the
263
+ * CLI's contract-snapshot writer produces (e.g. `"columns": ["id"]`,
264
+ * `"values": ["admin", "user"]`) — the alternative (Node's default
265
+ * `JSON.stringify(null, 2)`) reflows every such array onto multiple
266
+ * lines and bloats the diff with hundreds of lines of cosmetic noise.
267
+ *
268
+ * The non-array, non-object surfaces match `JSON.stringify(null, 2)`
269
+ * byte-for-byte (same key ordering — insertion order — and same
270
+ * quoting/escaping). The only divergence is inline-primitive-arrays.
271
+ */
272
+ const INLINE_ARRAY_THRESHOLD = 80;
273
+
274
+ function isPrimitive(value: unknown): boolean {
275
+ return (
276
+ value === null ||
277
+ typeof value === 'string' ||
278
+ typeof value === 'number' ||
279
+ typeof value === 'boolean'
280
+ );
281
+ }
282
+
283
+ function formatJson(value: unknown, indentLevel = 0): string {
284
+ const indent = ' '.repeat(indentLevel);
285
+ const childIndent = ' '.repeat(indentLevel + 1);
286
+
287
+ if (value === null) return 'null';
288
+ if (typeof value === 'string') return JSON.stringify(value);
289
+ if (typeof value === 'number' || typeof value === 'boolean') return JSON.stringify(value);
290
+
291
+ if (Array.isArray(value)) {
292
+ if (value.length === 0) return '[]';
293
+ if (value.every(isPrimitive)) {
294
+ const inline = `[${value.map((v) => JSON.stringify(v)).join(', ')}]`;
295
+ if (inline.length <= INLINE_ARRAY_THRESHOLD) return inline;
296
+ }
297
+ const items = value.map((v) => `${childIndent}${formatJson(v, indentLevel + 1)}`);
298
+ return `[\n${items.join(',\n')}\n${indent}]`;
299
+ }
300
+
301
+ if (typeof value === 'object') {
302
+ const entries = Object.entries(value as Record<string, unknown>);
303
+ if (entries.length === 0) return '{}';
304
+ const lines = entries.map(
305
+ ([k, v]) => `${childIndent}${JSON.stringify(k)}: ${formatJson(v, indentLevel + 1)}`,
306
+ );
307
+ return `{\n${lines.join(',\n')}\n${indent}}`;
308
+ }
309
+
310
+ throw new Error(`Unsupported value: ${typeof value}`);
311
+ }
312
+
313
+ async function processFile(path: string): Promise<Result> {
314
+ const raw = await readFile(path, 'utf-8');
315
+ let parsed: unknown;
316
+ try {
317
+ parsed = JSON.parse(raw);
318
+ } catch (error) {
319
+ throw new Error(
320
+ `${path}: not valid JSON (${error instanceof Error ? error.message : String(error)})`,
321
+ );
322
+ }
323
+ const outcome = processContract(parsed, path);
324
+ if (outcome.transformed === null) {
325
+ return { path, status: 'already-clean', stamped: 0 };
326
+ }
327
+ const serialised = `${formatJson(outcome.transformed)}\n`;
328
+ if (!dryRun) await writeFile(path, serialised, 'utf-8');
329
+ return { path, status: dryRun ? 'needs-fix' : 'fixed', stamped: outcome.stamped };
330
+ }
331
+
332
+ const contracts = await findContractSnapshots(projectRoot);
333
+ if (contracts.length === 0) {
334
+ console.error(`No start-contract.json / end-contract.json files found under ${projectRoot}.`);
335
+ process.exit(1);
336
+ }
337
+
338
+ let changed = 0;
339
+ let alreadyClean = 0;
340
+ let totalStamped = 0;
341
+ for (const path of contracts) {
342
+ const result = await processFile(path);
343
+ const rel = path.slice(projectRoot.length + 1);
344
+ if (result.status === 'already-clean') {
345
+ alreadyClean += 1;
346
+ console.log(`OK ${rel} (already stamped or no storage.types)`);
347
+ } else {
348
+ changed += 1;
349
+ totalStamped += result.stamped;
350
+ const verb = dryRun ? 'WOULD FIX' : 'FIXED';
351
+ console.log(`${verb} ${rel} (stamped ${result.stamped} entry/entries)`);
352
+ }
353
+ }
354
+
355
+ console.log();
356
+ console.log(
357
+ `${contracts.length} snapshot(s) scanned: ${changed} ${dryRun ? 'needing fix' : 'fixed'} (${totalStamped} entries), ${alreadyClean} already clean.`,
358
+ );
359
+
360
+ if (dryRun && changed > 0) process.exit(1);