@prisma-next/cli 0.4.0-dev.9 → 0.5.0-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 (116) hide show
  1. package/README.md +26 -18
  2. package/dist/cli-errors-C0JhVj0c.d.mts +4 -0
  3. package/dist/cli-errors-DHq6GQGu.mjs +5 -0
  4. package/dist/cli.mjs +7 -18
  5. package/dist/cli.mjs.map +1 -1
  6. package/dist/{client-CJxHfhze.mjs → client-TG7rbCWT.mjs} +7 -6
  7. package/dist/{client-CJxHfhze.mjs.map → client-TG7rbCWT.mjs.map} +1 -1
  8. package/dist/commands/contract-emit.d.mts.map +1 -1
  9. package/dist/commands/contract-emit.mjs +2 -7
  10. package/dist/commands/contract-infer.mjs +2 -8
  11. package/dist/commands/db-init.mjs +6 -7
  12. package/dist/commands/db-init.mjs.map +1 -1
  13. package/dist/commands/db-schema.mjs +4 -7
  14. package/dist/commands/db-schema.mjs.map +1 -1
  15. package/dist/commands/db-sign.mjs +5 -6
  16. package/dist/commands/db-sign.mjs.map +1 -1
  17. package/dist/commands/db-update.mjs +6 -7
  18. package/dist/commands/db-update.mjs.map +1 -1
  19. package/dist/commands/db-verify.mjs +6 -7
  20. package/dist/commands/db-verify.mjs.map +1 -1
  21. package/dist/commands/migration-apply.d.mts +1 -1
  22. package/dist/commands/migration-apply.d.mts.map +1 -1
  23. package/dist/commands/migration-apply.mjs +33 -25
  24. package/dist/commands/migration-apply.mjs.map +1 -1
  25. package/dist/commands/migration-new.d.mts.map +1 -1
  26. package/dist/commands/migration-new.mjs +47 -22
  27. package/dist/commands/migration-new.mjs.map +1 -1
  28. package/dist/commands/migration-plan.d.mts +6 -1
  29. package/dist/commands/migration-plan.d.mts.map +1 -1
  30. package/dist/commands/migration-plan.mjs +92 -69
  31. package/dist/commands/migration-plan.mjs.map +1 -1
  32. package/dist/commands/migration-ref.d.mts +1 -1
  33. package/dist/commands/migration-ref.mjs +4 -4
  34. package/dist/commands/migration-show.d.mts +2 -2
  35. package/dist/commands/migration-show.d.mts.map +1 -1
  36. package/dist/commands/migration-show.mjs +9 -14
  37. package/dist/commands/migration-show.mjs.map +1 -1
  38. package/dist/commands/migration-status.d.mts +4 -5
  39. package/dist/commands/migration-status.d.mts.map +1 -1
  40. package/dist/commands/migration-status.mjs +2 -7
  41. package/dist/config-loader-_W4T21X1.mjs +90 -0
  42. package/dist/config-loader-_W4T21X1.mjs.map +1 -0
  43. package/dist/config-loader.d.mts.map +1 -1
  44. package/dist/config-loader.mjs +1 -1
  45. package/dist/{contract-emit-gpJNLGs7.mjs → contract-emit-CNYyzJwF.mjs} +18 -14
  46. package/dist/contract-emit-CNYyzJwF.mjs.map +1 -0
  47. package/dist/{contract-emit-CKig_Lra.mjs → contract-emit-CQfj7xJn.mjs} +24 -20
  48. package/dist/contract-emit-CQfj7xJn.mjs.map +1 -0
  49. package/dist/contract-emit-fhNwwhkQ.mjs +4 -0
  50. package/dist/{contract-infer-BDJgg7Xb.mjs → contract-infer-BP3DrGgz.mjs} +3 -3
  51. package/dist/{contract-infer-BDJgg7Xb.mjs.map → contract-infer-BP3DrGgz.mjs.map} +1 -1
  52. package/dist/exports/control-api.d.mts +2 -2
  53. package/dist/exports/control-api.d.mts.map +1 -1
  54. package/dist/exports/control-api.mjs +3 -5
  55. package/dist/exports/index.mjs +2 -7
  56. package/dist/exports/index.mjs.map +1 -1
  57. package/dist/{framework-components-Bsr1GaIj.mjs → framework-components-DfZKQBQ2.mjs} +2 -2
  58. package/dist/{framework-components-Bsr1GaIj.mjs.map → framework-components-DfZKQBQ2.mjs.map} +1 -1
  59. package/dist/{init-DZWvhEP0.mjs → init-CQfo_4Ro.mjs} +2 -2
  60. package/dist/{init-DZWvhEP0.mjs.map → init-CQfo_4Ro.mjs.map} +1 -1
  61. package/dist/{inspect-live-schema-ChqrALmw.mjs → inspect-live-schema-DWzf4Q_m.mjs} +5 -5
  62. package/dist/{inspect-live-schema-ChqrALmw.mjs.map → inspect-live-schema-DWzf4Q_m.mjs.map} +1 -1
  63. package/dist/migration-cli.d.mts +50 -0
  64. package/dist/migration-cli.d.mts.map +1 -0
  65. package/dist/migration-cli.mjs +184 -0
  66. package/dist/migration-cli.mjs.map +1 -0
  67. package/dist/{migration-command-scaffold-B0oH_hyB.mjs → migration-command-scaffold-CLMD302g.mjs} +6 -6
  68. package/dist/{migration-command-scaffold-B0oH_hyB.mjs.map → migration-command-scaffold-CLMD302g.mjs.map} +1 -1
  69. package/dist/{migration-status-CPamfEPj.mjs → migration-status-B0HLF7So.mjs} +18 -34
  70. package/dist/migration-status-B0HLF7So.mjs.map +1 -0
  71. package/dist/{migrations-BIsjFjSV.mjs → migrations-B0dOQlk0.mjs} +4 -15
  72. package/dist/migrations-B0dOQlk0.mjs.map +1 -0
  73. package/dist/{result-handler-AFK4hxyX.mjs → result-handler-CIyu0Pdt.mjs} +22 -11
  74. package/dist/result-handler-CIyu0Pdt.mjs.map +1 -0
  75. package/dist/{validate-contract-deps-DBH6iTAD.mjs → validate-contract-deps-esa-VQ0h.mjs} +1 -1
  76. package/dist/{validate-contract-deps-DBH6iTAD.mjs.map → validate-contract-deps-esa-VQ0h.mjs.map} +1 -1
  77. package/dist/{verify-C56CuQc7.mjs → verify-BxiVp50b.mjs} +2 -2
  78. package/dist/{verify-C56CuQc7.mjs.map → verify-BxiVp50b.mjs.map} +1 -1
  79. package/package.json +19 -19
  80. package/src/cli.ts +1 -5
  81. package/src/commands/contract-emit.ts +9 -10
  82. package/src/commands/migration-apply.ts +34 -23
  83. package/src/commands/migration-new.ts +39 -17
  84. package/src/commands/migration-plan.ts +119 -104
  85. package/src/commands/migration-show.ts +6 -16
  86. package/src/commands/migration-status.ts +14 -34
  87. package/src/config-loader.ts +35 -29
  88. package/src/config-path-validation.ts +75 -0
  89. package/src/control-api/client.ts +2 -1
  90. package/src/control-api/operations/contract-emit.ts +24 -23
  91. package/src/control-api/types.ts +1 -1
  92. package/src/migration-cli.ts +254 -0
  93. package/src/utils/cli-errors.ts +1 -0
  94. package/src/utils/command-helpers.ts +15 -19
  95. package/src/utils/formatters/graph-migration-mapper.ts +5 -14
  96. package/src/utils/formatters/help.ts +0 -1
  97. package/src/utils/formatters/migrations.ts +2 -29
  98. package/dist/cli-errors-BUuJr6py.mjs +0 -5
  99. package/dist/cli-errors-Dic2eADK.d.mts +0 -4
  100. package/dist/commands/migration-emit.d.mts +0 -38
  101. package/dist/commands/migration-emit.d.mts.map +0 -1
  102. package/dist/commands/migration-emit.mjs +0 -81
  103. package/dist/commands/migration-emit.mjs.map +0 -1
  104. package/dist/config-loader-C4VXKl8f.mjs +0 -43
  105. package/dist/config-loader-C4VXKl8f.mjs.map +0 -1
  106. package/dist/contract-emit-CKig_Lra.mjs.map +0 -1
  107. package/dist/contract-emit-CU-SYNe4.mjs +0 -6
  108. package/dist/contract-emit-gpJNLGs7.mjs.map +0 -1
  109. package/dist/migration-emit-Du4DBMqz.mjs +0 -125
  110. package/dist/migration-emit-Du4DBMqz.mjs.map +0 -1
  111. package/dist/migration-status-CPamfEPj.mjs.map +0 -1
  112. package/dist/migrations-BIsjFjSV.mjs.map +0 -1
  113. package/dist/result-handler-AFK4hxyX.mjs.map +0 -1
  114. package/src/commands/migration-emit.ts +0 -134
  115. package/src/lib/migration-emit.ts +0 -125
  116. package/src/lib/migration-strategy.ts +0 -49
@@ -0,0 +1,50 @@
1
+ import { Migration } from "@prisma-next/migration-tools/migration";
2
+
3
+ //#region src/migration-cli.d.ts
4
+
5
+ /**
6
+ * Constructor shape accepted by `MigrationCLI.run`. `Migration` subclasses
7
+ * accept an optional `ControlStack` in their constructor (each subclass
8
+ * narrows the stack to its own family/target generics); the CLI always
9
+ * passes one assembled from the loaded config. We use a rest-args `any[]`
10
+ * constructor signature so that subclass constructors with narrower
11
+ * parameter types remain assignable - constructor type compatibility in
12
+ * TS is contravariant in the parameter, and a wider `unknown` parameter
13
+ * on the alias side would reject any narrower subclass signature.
14
+ *
15
+ * The CLI only ever passes one argument (`new MigrationClass(stack)`);
16
+ * the rest-arity is purely a type-compatibility concession for subclass
17
+ * constructors that declare narrower parameter types, not an extension
18
+ * point for additional construction arguments.
19
+ */
20
+ type MigrationConstructor = new (...args: any[]) => Migration;
21
+ /**
22
+ * The CLI surface invoked by an authored `migration.ts` file. Exposed as
23
+ * a class with a static `run` method (rather than a free function) to
24
+ * give the concept a stable identity in the ubiquitous language: this is
25
+ * the "migration-file CLI", distinct from the apply-time runner that
26
+ * executes migration JSON ops.
27
+ *
28
+ * Currently a single static method. Future surface (e.g. a programmatic
29
+ * `MigrationCLI.serializeOnly(...)` for tests, or extra subcommands) can
30
+ * land here without changing the import shape used by every authored
31
+ * migration.
32
+ */
33
+ declare class MigrationCLI {
34
+ /**
35
+ * Orchestrates a class-flow `migration.ts` script run. Awaitable:
36
+ * callers may `await MigrationCLI.run(...)` to surface async failures
37
+ * from config loading, but the typical usage pattern (top-level call
38
+ * after the class definition) does not require awaiting because
39
+ * node's module evaluation keeps the promise alive until completion.
40
+ *
41
+ * Any throwable inside this function must surface through the internal
42
+ * try/catch — script callers do not await, so an unhandled rejection
43
+ * would silently exit 0. Treat the try/catch as load-bearing for the
44
+ * no-await usage pattern.
45
+ */
46
+ static run(importMetaUrl: string, MigrationClass: MigrationConstructor): Promise<void>;
47
+ }
48
+ //#endregion
49
+ export { MigrationCLI, MigrationConstructor };
50
+ //# sourceMappingURL=migration-cli.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-cli.d.mts","names":[],"sources":["../src/migration-cli.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;KAqEY,oBAAA,2BAA+C;;;;;;;;;;;;;cAiE9C,YAAA;;;;;;;;;;;;;oDAa6C,uBAAuB"}
@@ -0,0 +1,184 @@
1
+ import { t as loadConfig } from "./config-loader-_W4T21X1.mjs";
2
+ import { readFileSync, writeFileSync } from "node:fs";
3
+ import { CliStructuredError, errorMigrationCliInvalidConfigArg } from "@prisma-next/errors/control";
4
+ import { dirname, join } from "pathe";
5
+ import { createControlStack } from "@prisma-next/framework-components/control";
6
+ import { errorMigrationTargetMismatch } from "@prisma-next/errors/migration";
7
+ import { fileURLToPath } from "node:url";
8
+ import { buildMigrationArtifacts, isDirectEntrypoint, printMigrationHelp } from "@prisma-next/migration-tools/migration";
9
+
10
+ //#region src/migration-cli.ts
11
+ /**
12
+ * The migration-file CLI interface: the actor invoked when the author runs
13
+ * `node migration.ts` directly.
14
+ *
15
+ * Naming: this is *not* a "migration runner" in the apply-time sense. The
16
+ * apply-time runner is the thing `prisma-next migration apply` uses to
17
+ * execute migration JSON ops against a database. `MigrationCLI` is the
18
+ * tiny CLI surface owned by an authored `migration.ts` file: parse the
19
+ * file's argv, load the project's `prisma-next.config.ts`, assemble a
20
+ * `ControlStack`, instantiate the migration class, and serialize.
21
+ *
22
+ * The user authors a migration class, then calls
23
+ * `MigrationCLI.run(import.meta.url, MigrationClass)` at module scope
24
+ * after the class definition. When the file is invoked as a node
25
+ * entrypoint (`node migration.ts`), the CLI:
26
+ *
27
+ * 1. Detects whether the file is the direct entrypoint (no-op when imported).
28
+ * 2. Parses CLI args (`--help`, `--dry-run`, `--config <path>`).
29
+ * 3. Loads the project's `prisma-next.config.ts` via the same `loadConfig`
30
+ * the CLI commands use, walking up from the migration file's directory.
31
+ * 4. Probe-instantiates the migration class without a stack so it can read
32
+ * `targetId` and verify it matches `config.target.targetId`
33
+ * (`PN-MIG-2006` on mismatch) before any stack-driven adapter
34
+ * construction runs.
35
+ * 5. Assembles a `ControlStack` from the loaded config descriptors and
36
+ * constructs the migration with that stack.
37
+ * 6. Reads any previously-scaffolded `migration.json`, then calls
38
+ * `buildMigrationArtifacts` from `@prisma-next/migration-tools` to
39
+ * produce in-memory `ops.json` + `migration.json` content. Persists
40
+ * the result to disk (or prints in dry-run mode).
41
+ *
42
+ * File I/O lives here, in `@prisma-next/cli`: this is the only place
43
+ * that legitimately combines config loading, stack assembly, and
44
+ * on-disk persistence. `@prisma-next/migration-tools` owns the pure
45
+ * conversion from a `Migration` instance to artifact strings; `Migration`
46
+ * stays a pure abstract class.
47
+ */
48
+ /**
49
+ * Parse the subset of `process.argv` that `MigrationCLI.run` cares about.
50
+ * Recognised flags: `--help`, `--dry-run`, `--config <path>` /
51
+ * `--config=<path>`. Unknown flags are ignored to keep the surface
52
+ * forgiving for ad-hoc tooling that wraps a migration file.
53
+ *
54
+ * Throws `errorMigrationCliInvalidConfigArg` (`PN-CLI-4012`) when
55
+ * `--config` is missing its path argument or is followed by another flag
56
+ * (e.g. `--config --dry-run`); silently consuming the next flag would
57
+ * either drop dry-run handling or serialize against the wrong project.
58
+ *
59
+ * NOTE: this hand-rolled parser is a known wart, tracked separately by
60
+ * TML-2318 ("Migration CLI: replace handrolled arg parser with shared
61
+ * CLI library"). Until that lands the surface is intentionally tiny.
62
+ */
63
+ function parseArgs(argv) {
64
+ let help = false;
65
+ let dryRun = false;
66
+ let configPath;
67
+ for (let i = 0; i < argv.length; i++) {
68
+ const arg = argv[i];
69
+ if (arg === "--help" || arg === "-h") help = true;
70
+ else if (arg === "--dry-run") dryRun = true;
71
+ else if (arg === "--config") {
72
+ const next = argv[i + 1];
73
+ if (next === void 0) throw errorMigrationCliInvalidConfigArg();
74
+ if (next.startsWith("-")) throw errorMigrationCliInvalidConfigArg({ nextToken: next });
75
+ configPath = next;
76
+ i++;
77
+ } else if (arg.startsWith("--config=")) configPath = arg.slice(9);
78
+ }
79
+ return {
80
+ help,
81
+ dryRun,
82
+ configPath
83
+ };
84
+ }
85
+ /**
86
+ * The CLI surface invoked by an authored `migration.ts` file. Exposed as
87
+ * a class with a static `run` method (rather than a free function) to
88
+ * give the concept a stable identity in the ubiquitous language: this is
89
+ * the "migration-file CLI", distinct from the apply-time runner that
90
+ * executes migration JSON ops.
91
+ *
92
+ * Currently a single static method. Future surface (e.g. a programmatic
93
+ * `MigrationCLI.serializeOnly(...)` for tests, or extra subcommands) can
94
+ * land here without changing the import shape used by every authored
95
+ * migration.
96
+ */
97
+ var MigrationCLI = class {
98
+ /**
99
+ * Orchestrates a class-flow `migration.ts` script run. Awaitable:
100
+ * callers may `await MigrationCLI.run(...)` to surface async failures
101
+ * from config loading, but the typical usage pattern (top-level call
102
+ * after the class definition) does not require awaiting because
103
+ * node's module evaluation keeps the promise alive until completion.
104
+ *
105
+ * Any throwable inside this function must surface through the internal
106
+ * try/catch — script callers do not await, so an unhandled rejection
107
+ * would silently exit 0. Treat the try/catch as load-bearing for the
108
+ * no-await usage pattern.
109
+ */
110
+ static async run(importMetaUrl, MigrationClass) {
111
+ if (!importMetaUrl) return;
112
+ if (!isDirectEntrypoint(importMetaUrl)) return;
113
+ try {
114
+ const args = parseArgs(process.argv.slice(2));
115
+ if (args.help) {
116
+ printMigrationHelp();
117
+ return;
118
+ }
119
+ const migrationDir = dirname(fileURLToPath(importMetaUrl));
120
+ const config = await loadConfig(args.configPath);
121
+ const probe = new MigrationClass();
122
+ if (probe.targetId !== config.target.targetId) throw errorMigrationTargetMismatch({
123
+ migrationTargetId: probe.targetId,
124
+ configTargetId: config.target.targetId
125
+ });
126
+ serializeMigrationToDisk(new MigrationClass(createControlStack(config)), migrationDir, args.dryRun);
127
+ } catch (err) {
128
+ if (CliStructuredError.is(err)) process.stderr.write(`${err.message}: ${err.why}\n`);
129
+ else process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
130
+ process.exitCode = 1;
131
+ }
132
+ }
133
+ };
134
+ /**
135
+ * Read a previously-scaffolded `migration.json` from disk, returning
136
+ * `null` when the file is missing or unparseable. The CLI feeds this into
137
+ * `buildMigrationArtifacts` so the pure builder can preserve fields owned
138
+ * by `migration plan` (contract bookends, hints, labels, `createdAt`)
139
+ * across re-emits.
140
+ */
141
+ function readExistingManifest(manifestPath) {
142
+ let raw;
143
+ try {
144
+ raw = readFileSync(manifestPath, "utf-8");
145
+ } catch {
146
+ return null;
147
+ }
148
+ try {
149
+ return JSON.parse(raw);
150
+ } catch {
151
+ return null;
152
+ }
153
+ }
154
+ /**
155
+ * Persist a migration instance's artifacts to `migrationDir`. In
156
+ * `dryRun` mode the artifacts are printed to stdout (with the same
157
+ * `--- migration.json --- / --- ops.json ---` framing the legacy
158
+ * `serializeMigration` helper used) and no files are written. Otherwise
159
+ * `ops.json` and `migration.json` are written next to `migration.ts` and
160
+ * a confirmation line is printed.
161
+ *
162
+ * File I/O lives in the CLI rather than `@prisma-next/migration-tools`
163
+ * so the migration-tools package stays focused on the pure
164
+ * `Migration` → in-memory artifact conversion. The CLI is the only
165
+ * legitimate site for combining config loading, stack assembly, and
166
+ * filesystem persistence.
167
+ */
168
+ function serializeMigrationToDisk(instance, migrationDir, dryRun) {
169
+ const manifestPath = join(migrationDir, "migration.json");
170
+ const { opsJson, manifestJson } = buildMigrationArtifacts(instance, readExistingManifest(manifestPath));
171
+ if (dryRun) {
172
+ process.stdout.write(`--- migration.json ---\n${manifestJson}\n`);
173
+ process.stdout.write("--- ops.json ---\n");
174
+ process.stdout.write(`${opsJson}\n`);
175
+ return;
176
+ }
177
+ writeFileSync(join(migrationDir, "ops.json"), opsJson);
178
+ writeFileSync(manifestPath, manifestJson);
179
+ process.stdout.write(`Wrote ops.json + migration.json to ${migrationDir}\n`);
180
+ }
181
+
182
+ //#endregion
183
+ export { MigrationCLI };
184
+ //# sourceMappingURL=migration-cli.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-cli.mjs","names":["configPath: string | undefined","raw: string"],"sources":["../src/migration-cli.ts"],"sourcesContent":["/**\n * The migration-file CLI interface: the actor invoked when the author runs\n * `node migration.ts` directly.\n *\n * Naming: this is *not* a \"migration runner\" in the apply-time sense. The\n * apply-time runner is the thing `prisma-next migration apply` uses to\n * execute migration JSON ops against a database. `MigrationCLI` is the\n * tiny CLI surface owned by an authored `migration.ts` file: parse the\n * file's argv, load the project's `prisma-next.config.ts`, assemble a\n * `ControlStack`, instantiate the migration class, and serialize.\n *\n * The user authors a migration class, then calls\n * `MigrationCLI.run(import.meta.url, MigrationClass)` at module scope\n * after the class definition. When the file is invoked as a node\n * entrypoint (`node migration.ts`), the CLI:\n *\n * 1. Detects whether the file is the direct entrypoint (no-op when imported).\n * 2. Parses CLI args (`--help`, `--dry-run`, `--config <path>`).\n * 3. Loads the project's `prisma-next.config.ts` via the same `loadConfig`\n * the CLI commands use, walking up from the migration file's directory.\n * 4. Probe-instantiates the migration class without a stack so it can read\n * `targetId` and verify it matches `config.target.targetId`\n * (`PN-MIG-2006` on mismatch) before any stack-driven adapter\n * construction runs.\n * 5. Assembles a `ControlStack` from the loaded config descriptors and\n * constructs the migration with that stack.\n * 6. Reads any previously-scaffolded `migration.json`, then calls\n * `buildMigrationArtifacts` from `@prisma-next/migration-tools` to\n * produce in-memory `ops.json` + `migration.json` content. Persists\n * the result to disk (or prints in dry-run mode).\n *\n * File I/O lives here, in `@prisma-next/cli`: this is the only place\n * that legitimately combines config loading, stack assembly, and\n * on-disk persistence. `@prisma-next/migration-tools` owns the pure\n * conversion from a `Migration` instance to artifact strings; `Migration`\n * stays a pure abstract class.\n */\n\nimport { readFileSync, writeFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { CliStructuredError, errorMigrationCliInvalidConfigArg } from '@prisma-next/errors/control';\nimport { errorMigrationTargetMismatch } from '@prisma-next/errors/migration';\nimport { createControlStack } from '@prisma-next/framework-components/control';\nimport {\n buildMigrationArtifacts,\n isDirectEntrypoint,\n type Migration,\n printMigrationHelp,\n} from '@prisma-next/migration-tools/migration';\nimport type { MigrationManifest } from '@prisma-next/migration-tools/types';\nimport { dirname, join } from 'pathe';\nimport { loadConfig } from './config-loader';\n\n/**\n * Constructor shape accepted by `MigrationCLI.run`. `Migration` subclasses\n * accept an optional `ControlStack` in their constructor (each subclass\n * narrows the stack to its own family/target generics); the CLI always\n * passes one assembled from the loaded config. We use a rest-args `any[]`\n * constructor signature so that subclass constructors with narrower\n * parameter types remain assignable - constructor type compatibility in\n * TS is contravariant in the parameter, and a wider `unknown` parameter\n * on the alias side would reject any narrower subclass signature.\n *\n * The CLI only ever passes one argument (`new MigrationClass(stack)`);\n * the rest-arity is purely a type-compatibility concession for subclass\n * constructors that declare narrower parameter types, not an extension\n * point for additional construction arguments.\n */\n// biome-ignore lint/suspicious/noExplicitAny: see JSDoc - rest args with any are the idiomatic TS pattern for accepting arbitrary subclass constructor signatures\nexport type MigrationConstructor = new (...args: any[]) => Migration;\n\ninterface ParsedArgs {\n readonly help: boolean;\n readonly dryRun: boolean;\n readonly configPath: string | undefined;\n}\n\n/**\n * Parse the subset of `process.argv` that `MigrationCLI.run` cares about.\n * Recognised flags: `--help`, `--dry-run`, `--config <path>` /\n * `--config=<path>`. Unknown flags are ignored to keep the surface\n * forgiving for ad-hoc tooling that wraps a migration file.\n *\n * Throws `errorMigrationCliInvalidConfigArg` (`PN-CLI-4012`) when\n * `--config` is missing its path argument or is followed by another flag\n * (e.g. `--config --dry-run`); silently consuming the next flag would\n * either drop dry-run handling or serialize against the wrong project.\n *\n * NOTE: this hand-rolled parser is a known wart, tracked separately by\n * TML-2318 (\"Migration CLI: replace handrolled arg parser with shared\n * CLI library\"). Until that lands the surface is intentionally tiny.\n */\nfunction parseArgs(argv: readonly string[]): ParsedArgs {\n let help = false;\n let dryRun = false;\n let configPath: string | undefined;\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i]!;\n if (arg === '--help' || arg === '-h') {\n help = true;\n } else if (arg === '--dry-run') {\n dryRun = true;\n } else if (arg === '--config') {\n const next = argv[i + 1];\n if (next === undefined) {\n throw errorMigrationCliInvalidConfigArg();\n }\n if (next.startsWith('-')) {\n throw errorMigrationCliInvalidConfigArg({ nextToken: next });\n }\n configPath = next;\n i++;\n } else if (arg.startsWith('--config=')) {\n configPath = arg.slice('--config='.length);\n }\n }\n\n return { help, dryRun, configPath };\n}\n\n/**\n * The CLI surface invoked by an authored `migration.ts` file. Exposed as\n * a class with a static `run` method (rather than a free function) to\n * give the concept a stable identity in the ubiquitous language: this is\n * the \"migration-file CLI\", distinct from the apply-time runner that\n * executes migration JSON ops.\n *\n * Currently a single static method. Future surface (e.g. a programmatic\n * `MigrationCLI.serializeOnly(...)` for tests, or extra subcommands) can\n * land here without changing the import shape used by every authored\n * migration.\n */\n// biome-ignore lint/complexity/noStaticOnlyClass: see JSDoc - intentional class facade for the migration-file CLI surface; future methods will share state derived from argv/config.\nexport class MigrationCLI {\n /**\n * Orchestrates a class-flow `migration.ts` script run. Awaitable:\n * callers may `await MigrationCLI.run(...)` to surface async failures\n * from config loading, but the typical usage pattern (top-level call\n * after the class definition) does not require awaiting because\n * node's module evaluation keeps the promise alive until completion.\n *\n * Any throwable inside this function must surface through the internal\n * try/catch — script callers do not await, so an unhandled rejection\n * would silently exit 0. Treat the try/catch as load-bearing for the\n * no-await usage pattern.\n */\n static async run(importMetaUrl: string, MigrationClass: MigrationConstructor): Promise<void> {\n if (!importMetaUrl) return;\n if (!isDirectEntrypoint(importMetaUrl)) return;\n\n try {\n const args = parseArgs(process.argv.slice(2));\n\n if (args.help) {\n printMigrationHelp();\n return;\n }\n\n const migrationFile = fileURLToPath(importMetaUrl);\n const migrationDir = dirname(migrationFile);\n\n const config = await loadConfig(args.configPath);\n\n // Probe-instantiate without a stack so we can read `targetId` before\n // any target-specific constructor side effects (e.g.\n // `PostgresMigration`'s `stack.adapter.create(stack)`) run. Concrete\n // subclasses are required to accept the no-arg form; the abstract\n // `Migration` constructor declares `stack?` and target subclasses\n // (Postgres, Mongo) propagate that optionality. This makes the\n // target-mismatch guard fail fast with `PN-MIG-2006` before any\n // stack-driven adapter construction begins, even if the wrong-target\n // adapter's `create` would otherwise succeed and silently misshapen\n // the stored adapter cast.\n const probe = new MigrationClass();\n\n if (probe.targetId !== config.target.targetId) {\n throw errorMigrationTargetMismatch({\n migrationTargetId: probe.targetId,\n configTargetId: config.target.targetId,\n });\n }\n\n const stack = createControlStack(config);\n const instance = new MigrationClass(stack);\n\n serializeMigrationToDisk(instance, migrationDir, args.dryRun);\n } catch (err) {\n if (CliStructuredError.is(err)) {\n process.stderr.write(`${err.message}: ${err.why}\\n`);\n } else {\n process.stderr.write(`${err instanceof Error ? err.message : String(err)}\\n`);\n }\n process.exitCode = 1;\n }\n }\n}\n\n/**\n * Read a previously-scaffolded `migration.json` from disk, returning\n * `null` when the file is missing or unparseable. The CLI feeds this into\n * `buildMigrationArtifacts` so the pure builder can preserve fields owned\n * by `migration plan` (contract bookends, hints, labels, `createdAt`)\n * across re-emits.\n */\nfunction readExistingManifest(manifestPath: string): Partial<MigrationManifest> | null {\n let raw: string;\n try {\n raw = readFileSync(manifestPath, 'utf-8');\n } catch {\n return null;\n }\n try {\n return JSON.parse(raw) as Partial<MigrationManifest>;\n } catch {\n return null;\n }\n}\n\n/**\n * Persist a migration instance's artifacts to `migrationDir`. In\n * `dryRun` mode the artifacts are printed to stdout (with the same\n * `--- migration.json --- / --- ops.json ---` framing the legacy\n * `serializeMigration` helper used) and no files are written. Otherwise\n * `ops.json` and `migration.json` are written next to `migration.ts` and\n * a confirmation line is printed.\n *\n * File I/O lives in the CLI rather than `@prisma-next/migration-tools`\n * so the migration-tools package stays focused on the pure\n * `Migration` → in-memory artifact conversion. The CLI is the only\n * legitimate site for combining config loading, stack assembly, and\n * filesystem persistence.\n */\nfunction serializeMigrationToDisk(\n instance: Migration,\n migrationDir: string,\n dryRun: boolean,\n): void {\n const manifestPath = join(migrationDir, 'migration.json');\n const existing = readExistingManifest(manifestPath);\n const { opsJson, manifestJson } = buildMigrationArtifacts(instance, existing);\n\n if (dryRun) {\n process.stdout.write(`--- migration.json ---\\n${manifestJson}\\n`);\n process.stdout.write('--- ops.json ---\\n');\n process.stdout.write(`${opsJson}\\n`);\n return;\n }\n\n writeFileSync(join(migrationDir, 'ops.json'), opsJson);\n writeFileSync(manifestPath, manifestJson);\n\n process.stdout.write(`Wrote ops.json + migration.json to ${migrationDir}\\n`);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4FA,SAAS,UAAU,MAAqC;CACtD,IAAI,OAAO;CACX,IAAI,SAAS;CACb,IAAIA;AAEJ,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,MAAM,KAAK;AACjB,MAAI,QAAQ,YAAY,QAAQ,KAC9B,QAAO;WACE,QAAQ,YACjB,UAAS;WACA,QAAQ,YAAY;GAC7B,MAAM,OAAO,KAAK,IAAI;AACtB,OAAI,SAAS,OACX,OAAM,mCAAmC;AAE3C,OAAI,KAAK,WAAW,IAAI,CACtB,OAAM,kCAAkC,EAAE,WAAW,MAAM,CAAC;AAE9D,gBAAa;AACb;aACS,IAAI,WAAW,YAAY,CACpC,cAAa,IAAI,MAAM,EAAmB;;AAI9C,QAAO;EAAE;EAAM;EAAQ;EAAY;;;;;;;;;;;;;;AAgBrC,IAAa,eAAb,MAA0B;;;;;;;;;;;;;CAaxB,aAAa,IAAI,eAAuB,gBAAqD;AAC3F,MAAI,CAAC,cAAe;AACpB,MAAI,CAAC,mBAAmB,cAAc,CAAE;AAExC,MAAI;GACF,MAAM,OAAO,UAAU,QAAQ,KAAK,MAAM,EAAE,CAAC;AAE7C,OAAI,KAAK,MAAM;AACb,wBAAoB;AACpB;;GAIF,MAAM,eAAe,QADC,cAAc,cAAc,CACP;GAE3C,MAAM,SAAS,MAAM,WAAW,KAAK,WAAW;GAYhD,MAAM,QAAQ,IAAI,gBAAgB;AAElC,OAAI,MAAM,aAAa,OAAO,OAAO,SACnC,OAAM,6BAA6B;IACjC,mBAAmB,MAAM;IACzB,gBAAgB,OAAO,OAAO;IAC/B,CAAC;AAMJ,4BAFiB,IAAI,eADP,mBAAmB,OAAO,CACE,EAEP,cAAc,KAAK,OAAO;WACtD,KAAK;AACZ,OAAI,mBAAmB,GAAG,IAAI,CAC5B,SAAQ,OAAO,MAAM,GAAG,IAAI,QAAQ,IAAI,IAAI,IAAI,IAAI;OAEpD,SAAQ,OAAO,MAAM,GAAG,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CAAC,IAAI;AAE/E,WAAQ,WAAW;;;;;;;;;;;AAYzB,SAAS,qBAAqB,cAAyD;CACrF,IAAIC;AACJ,KAAI;AACF,QAAM,aAAa,cAAc,QAAQ;SACnC;AACN,SAAO;;AAET,KAAI;AACF,SAAO,KAAK,MAAM,IAAI;SAChB;AACN,SAAO;;;;;;;;;;;;;;;;;AAkBX,SAAS,yBACP,UACA,cACA,QACM;CACN,MAAM,eAAe,KAAK,cAAc,iBAAiB;CAEzD,MAAM,EAAE,SAAS,iBAAiB,wBAAwB,UADzC,qBAAqB,aAAa,CAC0B;AAE7E,KAAI,QAAQ;AACV,UAAQ,OAAO,MAAM,2BAA2B,aAAa,IAAI;AACjE,UAAQ,OAAO,MAAM,qBAAqB;AAC1C,UAAQ,OAAO,MAAM,GAAG,QAAQ,IAAI;AACpC;;AAGF,eAAc,KAAK,cAAc,WAAW,EAAE,QAAQ;AACtD,eAAc,cAAc,aAAa;AAEzC,SAAQ,OAAO,MAAM,sCAAsC,aAAa,IAAI"}
@@ -1,12 +1,12 @@
1
- import { t as loadConfig } from "./config-loader-C4VXKl8f.mjs";
2
- import { a as errorContractValidationFailed, c as errorDriverRequired, g as errorTargetMigrationNotSupported, l as errorFileNotFound, o as errorDatabaseConnectionRequired, v as errorUnexpected } from "./cli-errors-BUuJr6py.mjs";
3
- import { t as createControlClient } from "./client-CJxHfhze.mjs";
4
- import { _ as formatStyledHeader, a as maskConnectionUrl, n as addGlobalOptions, s as resolveContractPath } from "./result-handler-AFK4hxyX.mjs";
1
+ import { t as loadConfig } from "./config-loader-_W4T21X1.mjs";
2
+ import { _ as errorUnexpected, a as errorContractValidationFailed, c as errorDriverRequired, h as errorTargetMigrationNotSupported, l as errorFileNotFound, o as errorDatabaseConnectionRequired } from "./cli-errors-DHq6GQGu.mjs";
3
+ import { t as createControlClient } from "./client-TG7rbCWT.mjs";
4
+ import { _ as formatStyledHeader, a as maskConnectionUrl, n as addGlobalOptions, s as resolveContractPath } from "./result-handler-CIyu0Pdt.mjs";
5
5
  import { t as createProgressAdapter } from "./progress-adapter-B-YvmcDu.mjs";
6
6
  import { notOk, ok } from "@prisma-next/utils/result";
7
- import { relative, resolve } from "node:path";
8
7
  import { hasMigrations } from "@prisma-next/framework-components/control";
9
8
  import { readFile } from "node:fs/promises";
9
+ import { relative, resolve } from "node:path";
10
10
 
11
11
  //#region src/utils/migration-command-scaffold.ts
12
12
  /**
@@ -102,4 +102,4 @@ function addMigrationCommandOptions(command) {
102
102
 
103
103
  //#endregion
104
104
  export { prepareMigrationContext as n, addMigrationCommandOptions as t };
105
- //# sourceMappingURL=migration-command-scaffold-B0oH_hyB.mjs.map
105
+ //# sourceMappingURL=migration-command-scaffold-CLMD302g.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"migration-command-scaffold-B0oH_hyB.mjs","names":["details: Array<{ label: string; value: string }>","contractJsonContent: string","contractJson: Record<string, unknown>"],"sources":["../src/utils/migration-command-scaffold.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { relative, resolve } from 'node:path';\nimport { hasMigrations } from '@prisma-next/framework-components/control';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport type { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type { ControlClient } from '../control-api/types';\nimport {\n type CliStructuredError,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n} from './cli-errors';\nimport { addGlobalOptions, maskConnectionUrl, resolveContractPath } from './command-helpers';\nimport { formatStyledHeader } from './formatters/styled';\nimport type { GlobalFlags } from './global-flags';\nimport { createProgressAdapter } from './progress-adapter';\nimport type { TerminalUI } from './terminal-ui';\n\n/**\n * Resolved context for a migration command.\n * Contains everything needed to invoke a control-api operation.\n */\nexport interface MigrationContext {\n readonly client: ControlClient;\n readonly contractJson: Record<string, unknown>;\n readonly dbConnection: unknown;\n readonly onProgress: ReturnType<typeof createProgressAdapter>;\n readonly configPath: string;\n readonly contractPath: string;\n readonly contractPathAbsolute: string;\n readonly config: Awaited<ReturnType<typeof loadConfig>>;\n}\n\n/**\n * Command-specific configuration for the shared scaffold.\n */\nexport interface MigrationCommandDescriptor {\n readonly commandName: string;\n readonly description: string;\n readonly url: string;\n}\n\n/**\n * Prepares the shared context for migration commands (db init, db update).\n *\n * Handles: config loading, contract file reading, JSON parsing, connection resolution,\n * driver/migration-support validation, client creation, and header output.\n *\n * Returns a Result with either the resolved context or a structured error.\n */\nexport async function prepareMigrationContext(\n options: { readonly db?: string; readonly config?: string; readonly dryRun?: boolean },\n flags: GlobalFlags,\n ui: TerminalUI,\n descriptor: MigrationCommandDescriptor,\n): Promise<Result<MigrationContext, CliStructuredError>> {\n // Load config\n const config = await loadConfig(options.config);\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n const contractPathAbsolute = resolveContractPath(config);\n const contractPath = relative(process.cwd(), contractPathAbsolute);\n\n // Output header to stderr (decoration)\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n ];\n if (options.db) {\n details.push({ label: 'database', value: maskConnectionUrl(options.db) });\n }\n if (options.dryRun) {\n details.push({ label: 'mode', value: 'dry run' });\n }\n const header = formatStyledHeader({\n command: descriptor.commandName,\n description: descriptor.description,\n url: descriptor.url,\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n // Load contract file\n let contractJsonContent: string;\n try {\n contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: `Run \\`prisma-next contract emit\\` to generate ${contractPath}, or update \\`config.contract.output\\` in ${configPath}`,\n }),\n );\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n // Parse contract JSON\n let contractJson: Record<string, unknown>;\n try {\n contractJson = JSON.parse(contractJsonContent) as Record<string, unknown>;\n } catch (error) {\n return notOk(\n errorContractValidationFailed(\n `Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\n\n // Resolve database connection (--db flag or config.db.connection)\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for ${descriptor.commandName} (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: descriptor.commandName,\n }),\n );\n }\n\n // Check for driver\n if (!config.driver) {\n return notOk(\n errorDriverRequired({ why: `Config.driver is required for ${descriptor.commandName}` }),\n );\n }\n\n if (!hasMigrations(config.target)) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n // Create control client\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n // Create progress adapter\n const onProgress = createProgressAdapter({ ui, flags });\n\n return ok({\n client,\n contractJson,\n dbConnection,\n onProgress,\n configPath,\n contractPath,\n contractPathAbsolute,\n config,\n });\n}\n\n/**\n * Registers the shared CLI options for migration commands (db init, db update).\n */\nexport function addMigrationCommandOptions(command: Command): Command {\n addGlobalOptions(command);\n return command\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--dry-run', 'Preview planned operations without applying', false);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAuDA,eAAsB,wBACpB,SACA,OACA,IACA,YACuD;CAEvD,MAAM,SAAS,MAAM,WAAW,QAAQ,OAAO;CAC/C,MAAM,aAAa,QAAQ,SACvB,SAAS,QAAQ,KAAK,EAAE,QAAQ,QAAQ,OAAO,CAAC,GAChD;CACJ,MAAM,uBAAuB,oBAAoB,OAAO;CACxD,MAAM,eAAe,SAAS,QAAQ,KAAK,EAAE,qBAAqB;AAGlE,KAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EAC/B,MAAMA,UAAmD,CACvD;GAAE,OAAO;GAAU,OAAO;GAAY,EACtC;GAAE,OAAO;GAAY,OAAO;GAAc,CAC3C;AACD,MAAI,QAAQ,GACV,SAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,QAAQ,GAAG;GAAE,CAAC;AAE3E,MAAI,QAAQ,OACV,SAAQ,KAAK;GAAE,OAAO;GAAQ,OAAO;GAAW,CAAC;EAEnD,MAAM,SAAS,mBAAmB;GAChC,SAAS,WAAW;GACpB,aAAa,WAAW;GACxB,KAAK,WAAW;GAChB;GACA;GACD,CAAC;AACF,KAAG,OAAO,OAAO;;CAInB,IAAIC;AACJ,KAAI;AACF,wBAAsB,MAAM,SAAS,sBAAsB,QAAQ;UAC5D,OAAO;AACd,MAAI,iBAAiB,SAAU,MAA4B,SAAS,SAClE,QAAO,MACL,kBAAkB,sBAAsB;GACtC,KAAK,8BAA8B;GACnC,KAAK,iDAAiD,aAAa,4CAA4C;GAChH,CAAC,CACH;AAEH,SAAO,MACL,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACtE,KAAK,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IAC7F,CAAC,CACH;;CAIH,IAAIC;AACJ,KAAI;AACF,iBAAe,KAAK,MAAM,oBAAoB;UACvC,OAAO;AACd,SAAO,MACL,8BACE,6BAA6B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IACnF,EAAE,OAAO,EAAE,MAAM,sBAAsB,EAAE,CAC1C,CACF;;CAIH,MAAM,eAAe,QAAQ,MAAM,OAAO,IAAI;AAC9C,KAAI,CAAC,aACH,QAAO,MACL,gCAAgC;EAC9B,KAAK,uCAAuC,WAAW,YAAY,yBAAyB,WAAW;EACvG,aAAa,WAAW;EACzB,CAAC,CACH;AAIH,KAAI,CAAC,OAAO,OACV,QAAO,MACL,oBAAoB,EAAE,KAAK,iCAAiC,WAAW,eAAe,CAAC,CACxF;AAGH,KAAI,CAAC,cAAc,OAAO,OAAO,CAC/B,QAAO,MACL,iCAAiC,EAC/B,KAAK,WAAW,OAAO,OAAO,GAAG,gCAClC,CAAC,CACH;CAIH,MAAM,SAAS,oBAAoB;EACjC,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,QAAQ,OAAO;EACf,gBAAgB,OAAO,kBAAkB,EAAE;EAC5C,CAAC;CAGF,MAAM,aAAa,sBAAsB;EAAE;EAAI;EAAO,CAAC;AAEvD,QAAO,GAAG;EACR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;;;;;AAMJ,SAAgB,2BAA2B,SAA2B;AACpE,kBAAiB,QAAQ;AACzB,QAAO,QACJ,OAAO,cAAc,6BAA6B,CAClD,OAAO,mBAAmB,gCAAgC,CAC1D,OAAO,aAAa,+CAA+C,MAAM"}
1
+ {"version":3,"file":"migration-command-scaffold-CLMD302g.mjs","names":["details: Array<{ label: string; value: string }>","contractJsonContent: string","contractJson: Record<string, unknown>"],"sources":["../src/utils/migration-command-scaffold.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { relative, resolve } from 'node:path';\nimport { hasMigrations } from '@prisma-next/framework-components/control';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport type { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type { ControlClient } from '../control-api/types';\nimport {\n type CliStructuredError,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n} from './cli-errors';\nimport { addGlobalOptions, maskConnectionUrl, resolveContractPath } from './command-helpers';\nimport { formatStyledHeader } from './formatters/styled';\nimport type { GlobalFlags } from './global-flags';\nimport { createProgressAdapter } from './progress-adapter';\nimport type { TerminalUI } from './terminal-ui';\n\n/**\n * Resolved context for a migration command.\n * Contains everything needed to invoke a control-api operation.\n */\nexport interface MigrationContext {\n readonly client: ControlClient;\n readonly contractJson: Record<string, unknown>;\n readonly dbConnection: unknown;\n readonly onProgress: ReturnType<typeof createProgressAdapter>;\n readonly configPath: string;\n readonly contractPath: string;\n readonly contractPathAbsolute: string;\n readonly config: Awaited<ReturnType<typeof loadConfig>>;\n}\n\n/**\n * Command-specific configuration for the shared scaffold.\n */\nexport interface MigrationCommandDescriptor {\n readonly commandName: string;\n readonly description: string;\n readonly url: string;\n}\n\n/**\n * Prepares the shared context for migration commands (db init, db update).\n *\n * Handles: config loading, contract file reading, JSON parsing, connection resolution,\n * driver/migration-support validation, client creation, and header output.\n *\n * Returns a Result with either the resolved context or a structured error.\n */\nexport async function prepareMigrationContext(\n options: { readonly db?: string; readonly config?: string; readonly dryRun?: boolean },\n flags: GlobalFlags,\n ui: TerminalUI,\n descriptor: MigrationCommandDescriptor,\n): Promise<Result<MigrationContext, CliStructuredError>> {\n // Load config\n const config = await loadConfig(options.config);\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n const contractPathAbsolute = resolveContractPath(config);\n const contractPath = relative(process.cwd(), contractPathAbsolute);\n\n // Output header to stderr (decoration)\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n ];\n if (options.db) {\n details.push({ label: 'database', value: maskConnectionUrl(options.db) });\n }\n if (options.dryRun) {\n details.push({ label: 'mode', value: 'dry run' });\n }\n const header = formatStyledHeader({\n command: descriptor.commandName,\n description: descriptor.description,\n url: descriptor.url,\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n // Load contract file\n let contractJsonContent: string;\n try {\n contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: `Run \\`prisma-next contract emit\\` to generate ${contractPath}, or update \\`config.contract.output\\` in ${configPath}`,\n }),\n );\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n // Parse contract JSON\n let contractJson: Record<string, unknown>;\n try {\n contractJson = JSON.parse(contractJsonContent) as Record<string, unknown>;\n } catch (error) {\n return notOk(\n errorContractValidationFailed(\n `Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\n\n // Resolve database connection (--db flag or config.db.connection)\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for ${descriptor.commandName} (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: descriptor.commandName,\n }),\n );\n }\n\n // Check for driver\n if (!config.driver) {\n return notOk(\n errorDriverRequired({ why: `Config.driver is required for ${descriptor.commandName}` }),\n );\n }\n\n if (!hasMigrations(config.target)) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n // Create control client\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n // Create progress adapter\n const onProgress = createProgressAdapter({ ui, flags });\n\n return ok({\n client,\n contractJson,\n dbConnection,\n onProgress,\n configPath,\n contractPath,\n contractPathAbsolute,\n config,\n });\n}\n\n/**\n * Registers the shared CLI options for migration commands (db init, db update).\n */\nexport function addMigrationCommandOptions(command: Command): Command {\n addGlobalOptions(command);\n return command\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--dry-run', 'Preview planned operations without applying', false);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAuDA,eAAsB,wBACpB,SACA,OACA,IACA,YACuD;CAEvD,MAAM,SAAS,MAAM,WAAW,QAAQ,OAAO;CAC/C,MAAM,aAAa,QAAQ,SACvB,SAAS,QAAQ,KAAK,EAAE,QAAQ,QAAQ,OAAO,CAAC,GAChD;CACJ,MAAM,uBAAuB,oBAAoB,OAAO;CACxD,MAAM,eAAe,SAAS,QAAQ,KAAK,EAAE,qBAAqB;AAGlE,KAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EAC/B,MAAMA,UAAmD,CACvD;GAAE,OAAO;GAAU,OAAO;GAAY,EACtC;GAAE,OAAO;GAAY,OAAO;GAAc,CAC3C;AACD,MAAI,QAAQ,GACV,SAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,QAAQ,GAAG;GAAE,CAAC;AAE3E,MAAI,QAAQ,OACV,SAAQ,KAAK;GAAE,OAAO;GAAQ,OAAO;GAAW,CAAC;EAEnD,MAAM,SAAS,mBAAmB;GAChC,SAAS,WAAW;GACpB,aAAa,WAAW;GACxB,KAAK,WAAW;GAChB;GACA;GACD,CAAC;AACF,KAAG,OAAO,OAAO;;CAInB,IAAIC;AACJ,KAAI;AACF,wBAAsB,MAAM,SAAS,sBAAsB,QAAQ;UAC5D,OAAO;AACd,MAAI,iBAAiB,SAAU,MAA4B,SAAS,SAClE,QAAO,MACL,kBAAkB,sBAAsB;GACtC,KAAK,8BAA8B;GACnC,KAAK,iDAAiD,aAAa,4CAA4C;GAChH,CAAC,CACH;AAEH,SAAO,MACL,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACtE,KAAK,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IAC7F,CAAC,CACH;;CAIH,IAAIC;AACJ,KAAI;AACF,iBAAe,KAAK,MAAM,oBAAoB;UACvC,OAAO;AACd,SAAO,MACL,8BACE,6BAA6B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IACnF,EAAE,OAAO,EAAE,MAAM,sBAAsB,EAAE,CAC1C,CACF;;CAIH,MAAM,eAAe,QAAQ,MAAM,OAAO,IAAI;AAC9C,KAAI,CAAC,aACH,QAAO,MACL,gCAAgC;EAC9B,KAAK,uCAAuC,WAAW,YAAY,yBAAyB,WAAW;EACvG,aAAa,WAAW;EACzB,CAAC,CACH;AAIH,KAAI,CAAC,OAAO,OACV,QAAO,MACL,oBAAoB,EAAE,KAAK,iCAAiC,WAAW,eAAe,CAAC,CACxF;AAGH,KAAI,CAAC,cAAc,OAAO,OAAO,CAC/B,QAAO,MACL,iCAAiC,EAC/B,KAAK,WAAW,OAAO,OAAO,GAAG,gCAClC,CAAC,CACH;CAIH,MAAM,SAAS,oBAAoB;EACjC,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,QAAQ,OAAO;EACf,gBAAgB,OAAO,kBAAkB,EAAE;EAC5C,CAAC;CAGF,MAAM,aAAa,sBAAsB;EAAE;EAAI;EAAO,CAAC;AAEvD,QAAO,GAAG;EACR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;;;;;AAMJ,SAAgB,2BAA2B,SAA2B;AACpE,kBAAiB,QAAQ;AACzB,QAAO,QACJ,OAAO,cAAc,6BAA6B,CAClD,OAAO,mBAAmB,gCAAgC,CAC1D,OAAO,aAAa,+CAA+C,MAAM"}
@@ -1,16 +1,16 @@
1
- import { t as loadConfig } from "./config-loader-C4VXKl8f.mjs";
2
- import { h as errorRuntime, v as errorUnexpected } from "./cli-errors-BUuJr6py.mjs";
3
- import { t as createControlClient } from "./client-CJxHfhze.mjs";
4
- import { _ as formatStyledHeader, a as maskConnectionUrl, c as resolveMigrationPaths, d as setCommandExamples, i as loadAllBundles, m as parseGlobalFlags, n as addGlobalOptions, o as readContractEnvelope, p as toPathDecisionResult, t as handleResult, u as setCommandDescriptions } from "./result-handler-AFK4hxyX.mjs";
1
+ import { t as loadConfig } from "./config-loader-_W4T21X1.mjs";
2
+ import { _ as errorUnexpected, m as errorRuntime } from "./cli-errors-DHq6GQGu.mjs";
3
+ import { t as createControlClient } from "./client-TG7rbCWT.mjs";
4
+ import { _ as formatStyledHeader, a as maskConnectionUrl, c as resolveMigrationPaths, d as setCommandExamples, i as loadAllBundles, m as parseGlobalFlags, n as addGlobalOptions, o as readContractEnvelope, p as toPathDecisionResult, t as handleResult, u as setCommandDescriptions } from "./result-handler-CIyu0Pdt.mjs";
5
5
  import { t as TerminalUI } from "./terminal-ui-C5k88MmW.mjs";
6
6
  import { Command } from "commander";
7
7
  import { notOk, ok } from "@prisma-next/utils/result";
8
8
  import { ifDefined } from "@prisma-next/utils/defined";
9
9
  import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
10
10
  import { findPath, findPathWithDecision, findReachableLeaves } from "@prisma-next/migration-tools/dag";
11
- import { MigrationToolsError } from "@prisma-next/migration-tools/types";
12
11
  import { bold, cyan, dim, magenta, yellow } from "colorette";
13
12
  import { readRefs, resolveRef } from "@prisma-next/migration-tools/refs";
13
+ import { MigrationToolsError } from "@prisma-next/migration-tools/types";
14
14
  import dagre from "@dagrejs/dagre";
15
15
 
16
16
  //#region src/utils/formatters/graph-types.ts
@@ -155,12 +155,9 @@ function migrationGraphToRenderInput(input) {
155
155
  id: shortHash(contractHash),
156
156
  markers: contractMarkers
157
157
  });
158
- const matchingDraft = input.draftEdges?.find((d) => d.to === contractHash);
159
- const fromHash = matchingDraft?.from ?? spineTargetHash;
160
- if (graph.nodes.has(fromHash) || fromHash === spineTargetHash) edgeList.push({
161
- from: toShortId(fromHash),
158
+ if (graph.nodes.has(spineTargetHash) || spineTargetHash === EMPTY_CONTRACT_HASH) edgeList.push({
159
+ from: toShortId(spineTargetHash),
162
160
  to: shortHash(contractHash),
163
- ...ifDefined("label", matchingDraft ? `${matchingDraft.dirName} [draft]` : void 0),
164
161
  style: "dashed"
165
162
  });
166
163
  }
@@ -1316,11 +1313,10 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1316
1313
  hints: ["Run 'prisma-next contract emit' to generate a valid contract"]
1317
1314
  });
1318
1315
  }
1319
- let attested;
1320
- let drafts;
1316
+ let bundles;
1321
1317
  let graph;
1322
1318
  try {
1323
- ({attested, drafts, graph} = await loadAllBundles(migrationsDir));
1319
+ ({bundles, graph} = await loadAllBundles(migrationsDir));
1324
1320
  } catch (error) {
1325
1321
  if (MigrationToolsError.is(error)) return notOk(errorRuntime(error.message, {
1326
1322
  why: error.why,
@@ -1329,13 +1325,7 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1329
1325
  }));
1330
1326
  return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read migrations directory: ${error instanceof Error ? error.message : String(error)}` }));
1331
1327
  }
1332
- if (drafts.length > 0) diagnostics.push({
1333
- code: "MIGRATION.DRAFTS",
1334
- severity: "warn",
1335
- message: `${drafts.length} draft migration(s) found: ${drafts.map((d) => d.dirName).join(", ")}`,
1336
- hints: ["Run 'prisma-next migration emit --dir <path>' to attest draft migrations before applying"]
1337
- });
1338
- if (attested.length === 0) {
1328
+ if (bundles.length === 0) {
1339
1329
  if (contractHash !== EMPTY_CONTRACT_HASH) diagnostics.push({
1340
1330
  code: "CONTRACT.AHEAD",
1341
1331
  severity: "warn",
@@ -1401,7 +1391,7 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1401
1391
  migrations: [],
1402
1392
  targetHash: EMPTY_CONTRACT_HASH,
1403
1393
  contractHash,
1404
- summary: `${attested.length} migration(s) on disk`,
1394
+ summary: `${bundles.length} migration(s) on disk`,
1405
1395
  diagnostics,
1406
1396
  markerHash,
1407
1397
  ...statusRefs.length > 0 ? { refs: statusRefs } : {}
@@ -1425,12 +1415,12 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1425
1415
  migrations: [],
1426
1416
  targetHash: EMPTY_CONTRACT_HASH,
1427
1417
  contractHash,
1428
- summary: `${attested.length} migration(s) on disk`,
1418
+ summary: `${bundles.length} migration(s) on disk`,
1429
1419
  diagnostics,
1430
1420
  ...ifDefined("markerHash", markerHash),
1431
1421
  ...statusRefs.length > 0 ? { refs: statusRefs } : {},
1432
1422
  graph,
1433
- bundles: attested,
1423
+ bundles,
1434
1424
  diverged: true
1435
1425
  });
1436
1426
  const chain = resolveDisplayChain(graph, targetHash, markerHash);
@@ -1439,11 +1429,11 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1439
1429
  fix: "The migration history may have gaps. Check the migrations directory for missing or corrupted packages."
1440
1430
  }));
1441
1431
  const edgeStatuses = deriveEdgeStatuses(graph, targetHash, contractHash, markerHash, mode);
1442
- const entries = buildMigrationEntries(chain, attested, mode, markerHash, edgeStatuses);
1432
+ const entries = buildMigrationEntries(chain, bundles, mode, markerHash, edgeStatuses);
1443
1433
  const pendingCount = edgeStatuses.filter((e) => e.status === "pending").length;
1444
1434
  const appliedCount = edgeStatuses.filter((e) => e.status === "applied").length;
1445
1435
  let summary;
1446
- if (mode === "online") if (markerHash !== void 0 && !graph.nodes.has(markerHash) && markerHash === contractHash) summary = `${attested.length} migration(s) on disk`;
1436
+ if (mode === "online") if (markerHash !== void 0 && !graph.nodes.has(markerHash) && markerHash === contractHash) summary = `${bundles.length} migration(s) on disk`;
1447
1437
  else if (activeRefHash && markerHash !== void 0) summary = summarizeRefDistance(graph, markerHash, activeRefHash, activeRefName);
1448
1438
  else if (pendingCount === 0) summary = `Database is up to date (${appliedCount} migration${appliedCount !== 1 ? "s" : ""} applied)`;
1449
1439
  else if (markerHash === void 0) summary = `${pendingCount} pending migration(s) — database has no marker`;
@@ -1484,8 +1474,7 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1484
1474
  ...statusRefs.length > 0 ? { refs: statusRefs } : {},
1485
1475
  ...ifDefined("pathDecision", pathDecision),
1486
1476
  graph,
1487
- bundles: attested,
1488
- ...drafts.length > 0 ? { drafts } : {},
1477
+ bundles,
1489
1478
  edgeStatuses,
1490
1479
  ...ifDefined("activeRefHash", activeRefHash),
1491
1480
  ...ifDefined("activeRefName", activeRefName)
@@ -1517,12 +1506,7 @@ function createMigrationStatusCommand() {
1517
1506
  refs: statusResult.refs,
1518
1507
  activeRefHash: statusResult.activeRefHash,
1519
1508
  activeRefName: statusResult.activeRefName,
1520
- edgeStatuses: statusResult.edgeStatuses,
1521
- draftEdges: statusResult.drafts?.map((d) => ({
1522
- from: d.manifest.from,
1523
- to: d.manifest.to,
1524
- dirName: d.dirName
1525
- }))
1509
+ edgeStatuses: statusResult.edgeStatuses
1526
1510
  });
1527
1511
  const graphToRender = options.graph || statusResult.diverged ? renderInput.graph : extractRelevantSubgraph(renderInput.graph, renderInput.relevantPaths);
1528
1512
  const dagreOptions = !options.graph && isLinearGraph(graphToRender) ? { ranksep: 1 } : void 0;
@@ -1580,4 +1564,4 @@ function summarizeRefDistance(graph, markerHash, refHash, refName) {
1580
1564
 
1581
1565
  //#endregion
1582
1566
  export { deriveEdgeStatuses as n, createMigrationStatusCommand as t };
1583
- //# sourceMappingURL=migration-status-CPamfEPj.mjs.map
1567
+ //# sourceMappingURL=migration-status-B0HLF7So.mjs.map