prisma-next 0.5.0-dev.8 → 0.5.0-dev.80
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/dist/cli-errors-B9OBbled.d.mts +3 -0
- package/dist/cli-errors-D3_sMh2K.mjs +33 -0
- package/dist/cli-errors-D3_sMh2K.mjs.map +1 -0
- package/dist/cli.mjs +16 -78
- package/dist/cli.mjs.map +1 -1
- package/dist/client-qVH-rEgd.mjs +1595 -0
- package/dist/client-qVH-rEgd.mjs.map +1 -0
- package/dist/{result-handler-Ba3zWQsI.mjs → command-helpers-BeZHkxV8.mjs} +70 -47
- package/dist/command-helpers-BeZHkxV8.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +2 -4
- package/dist/commands/contract-infer.d.mts.map +1 -1
- package/dist/commands/contract-infer.mjs +2 -4
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +16 -13
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.d.mts.map +1 -1
- package/dist/commands/db-schema.mjs +6 -7
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.d.mts.map +1 -1
- package/dist/commands/db-sign.mjs +9 -9
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +15 -13
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.d.mts.map +1 -1
- package/dist/commands/db-verify.mjs +1 -321
- package/dist/commands/migration-apply.d.mts +28 -13
- package/dist/commands/migration-apply.d.mts.map +1 -1
- package/dist/commands/migration-apply.mjs +55 -151
- package/dist/commands/migration-apply.mjs.map +1 -1
- package/dist/commands/migration-new.d.mts +0 -1
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +34 -40
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +33 -6
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +2 -348
- package/dist/commands/migration-ref.d.mts +1 -1
- package/dist/commands/migration-ref.d.mts.map +1 -1
- package/dist/commands/migration-ref.mjs +8 -12
- package/dist/commands/migration-ref.mjs.map +1 -1
- package/dist/commands/migration-show.d.mts +13 -7
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +35 -36
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +126 -5
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +2 -4
- package/dist/{config-loader-C25b63rJ.mjs → config-loader-B6sJjXTv.mjs} +3 -5
- package/dist/config-loader-B6sJjXTv.mjs.map +1 -0
- package/dist/config-loader.d.mts +0 -1
- package/dist/config-loader.d.mts.map +1 -1
- package/dist/config-loader.mjs +2 -3
- package/dist/contract-emit-9DBda5Ou.mjs +150 -0
- package/dist/contract-emit-9DBda5Ou.mjs.map +1 -0
- package/dist/contract-emit-B77TsJqf.mjs +327 -0
- package/dist/contract-emit-B77TsJqf.mjs.map +1 -0
- package/dist/{contract-enrichment-CAOELa-H.mjs → contract-enrichment-Dani0mMW.mjs} +4 -6
- package/dist/contract-enrichment-Dani0mMW.mjs.map +1 -0
- package/dist/{contract-infer-D9cC3rJm.mjs → contract-infer-BK9YFGEG.mjs} +13 -22
- package/dist/contract-infer-BK9YFGEG.mjs.map +1 -0
- package/dist/db-verify-C0y1PCO2.mjs +404 -0
- package/dist/db-verify-C0y1PCO2.mjs.map +1 -0
- package/dist/exports/config-types.mjs +1 -2
- package/dist/exports/control-api.d.mts +101 -586
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +4 -6
- package/dist/exports/index.d.mts.map +1 -1
- package/dist/exports/index.mjs +28 -30
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.d.mts +2 -4
- package/dist/exports/init-output.d.mts.map +1 -1
- package/dist/exports/init-output.mjs +2 -3
- package/dist/extension-pack-inputs-C7xgE-vv.mjs +74 -0
- package/dist/extension-pack-inputs-C7xgE-vv.mjs.map +1 -0
- package/dist/{framework-components-Cr--XBKy.mjs → framework-components-ChqVUxR-.mjs} +3 -4
- package/dist/{framework-components-Cr--XBKy.mjs.map → framework-components-ChqVUxR-.mjs.map} +1 -1
- package/dist/global-flags-Icqpxk23.d.mts +12 -0
- package/dist/global-flags-Icqpxk23.d.mts.map +1 -0
- package/dist/helpers-eqdN8tH6.mjs +25 -0
- package/dist/helpers-eqdN8tH6.mjs.map +1 -0
- package/dist/{init-C5220SY9.mjs → init-CoDVPvQ4.mjs} +26 -35
- package/dist/init-CoDVPvQ4.mjs.map +1 -0
- package/dist/{inspect-live-schema-yrHAvG71.mjs → inspect-live-schema-CWYxGKlb.mjs} +10 -11
- package/dist/inspect-live-schema-CWYxGKlb.mjs.map +1 -0
- package/dist/migration-cli.d.mts +41 -12
- package/dist/migration-cli.d.mts.map +1 -1
- package/dist/migration-cli.mjs +309 -86
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-B3B09et6.mjs → migration-command-scaffold-B5dORFEv.mjs} +8 -9
- package/dist/migration-command-scaffold-B5dORFEv.mjs.map +1 -0
- package/dist/migration-plan-C6lVaHsO.mjs +554 -0
- package/dist/migration-plan-C6lVaHsO.mjs.map +1 -0
- package/dist/{migration-status-DUMiH8_G.mjs → migration-status-CZ-D5k7k.mjs} +272 -65
- package/dist/migration-status-CZ-D5k7k.mjs.map +1 -0
- package/dist/migrations-D_UJnpuW.mjs +216 -0
- package/dist/migrations-D_UJnpuW.mjs.map +1 -0
- package/dist/{output-BpcQrnnq.mjs → output-B16Kefzx.mjs} +9 -3
- package/dist/output-B16Kefzx.mjs.map +1 -0
- package/dist/{progress-adapter-DvQWB1nK.mjs → progress-adapter-DFfvZcYL.mjs} +2 -2
- package/dist/{progress-adapter-DvQWB1nK.mjs.map → progress-adapter-DFfvZcYL.mjs.map} +1 -1
- package/dist/result-handler-rmPVKIP2.mjs +25 -0
- package/dist/result-handler-rmPVKIP2.mjs.map +1 -0
- package/dist/rolldown-runtime-twds-ZHy.mjs +14 -0
- package/dist/{terminal-ui-C3ZLwQxK.mjs → terminal-ui-C_hFNbAn.mjs} +4 -28
- package/dist/terminal-ui-C_hFNbAn.mjs.map +1 -0
- package/dist/types-D7x-IFLO.d.mts +858 -0
- package/dist/types-D7x-IFLO.d.mts.map +1 -0
- package/dist/{verify-Bkycc-Tf.mjs → verify-CiwNWM9N.mjs} +3 -4
- package/dist/verify-CiwNWM9N.mjs.map +1 -0
- package/package.json +19 -17
- package/dist/cli-errors-BFYgBH3L.d.mts +0 -4
- package/dist/cli-errors-Cd79vmTH.mjs +0 -5
- package/dist/client-CrsnY58k.mjs +0 -997
- package/dist/client-CrsnY58k.mjs.map +0 -1
- package/dist/commands/db-verify.mjs.map +0 -1
- package/dist/commands/migration-plan.mjs.map +0 -1
- package/dist/config-loader-C25b63rJ.mjs.map +0 -1
- package/dist/contract-emit--feXyNd7.mjs +0 -4
- package/dist/contract-emit-NJ01hiiv.mjs +0 -195
- package/dist/contract-emit-NJ01hiiv.mjs.map +0 -1
- package/dist/contract-emit-V5SSitUT.mjs +0 -122
- package/dist/contract-emit-V5SSitUT.mjs.map +0 -1
- package/dist/contract-enrichment-CAOELa-H.mjs.map +0 -1
- package/dist/contract-infer-D9cC3rJm.mjs.map +0 -1
- package/dist/extract-operation-statements-DsFfxXVZ.mjs +0 -13
- package/dist/extract-operation-statements-DsFfxXVZ.mjs.map +0 -1
- package/dist/extract-sql-ddl-D9UbZDyz.mjs +0 -26
- package/dist/extract-sql-ddl-D9UbZDyz.mjs.map +0 -1
- package/dist/init-C5220SY9.mjs.map +0 -1
- package/dist/inspect-live-schema-yrHAvG71.mjs.map +0 -1
- package/dist/migration-command-scaffold-B3B09et6.mjs.map +0 -1
- package/dist/migration-status-DUMiH8_G.mjs.map +0 -1
- package/dist/migrations-Bo5WtTla.mjs +0 -153
- package/dist/migrations-Bo5WtTla.mjs.map +0 -1
- package/dist/output-BpcQrnnq.mjs.map +0 -1
- package/dist/result-handler-Ba3zWQsI.mjs.map +0 -1
- package/dist/terminal-ui-C3ZLwQxK.mjs.map +0 -1
- package/dist/validate-contract-deps-B_Cs29TL.mjs +0 -37
- package/dist/validate-contract-deps-B_Cs29TL.mjs.map +0 -1
- package/dist/verify-Bkycc-Tf.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect-live-schema-CWYxGKlb.mjs","names":[],"sources":["../src/commands/inspect-live-schema.ts"],"sourcesContent":["import type { CoreSchemaView } from '@prisma-next/framework-components/control';\nimport type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { relative, resolve } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport {\n CliStructuredError,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorUnexpected,\n} from '../utils/cli-errors';\nimport { maskConnectionUrl, sanitizeErrorMessage } from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions, GlobalFlags } from '../utils/global-flags';\nimport { createProgressAdapter } from '../utils/progress-adapter';\nimport type { TerminalUI } from '../utils/terminal-ui';\n\nexport interface InspectLiveSchemaOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n}\n\ninterface InspectLiveSchemaContext {\n readonly commandName: string;\n readonly description: string;\n readonly url: string;\n}\n\ntype LoadedCliConfig = Awaited<ReturnType<typeof loadConfig>>;\n\nexport interface InspectLiveSchemaResult {\n readonly config: LoadedCliConfig;\n readonly schema: unknown;\n readonly schemaView: CoreSchemaView | undefined;\n /**\n * PSL AST inferred from the introspected schema, when the configured family\n * implements `PslContractInferCapable`. `undefined` for families that do not\n * support inference (e.g. Mongo today).\n */\n readonly pslContractAst: PslDocumentAst | undefined;\n readonly target: {\n readonly familyId: string;\n readonly id: string;\n };\n readonly meta: {\n readonly configPath?: string;\n readonly dbUrl?: string;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\nexport async function inspectLiveSchema(\n options: InspectLiveSchemaOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n context: InspectLiveSchemaContext,\n): Promise<Result<InspectLiveSchemaResult, CliStructuredError>> {\n let config: LoadedCliConfig;\n try {\n config = await loadConfig(options.config);\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: 'Failed to load config',\n }),\n );\n }\n\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n ];\n\n if (options.db) {\n details.push({ label: 'database', value: maskConnectionUrl(options.db) });\n } else if (config.db?.connection && typeof config.db.connection === 'string') {\n details.push({ label: 'database', value: maskConnectionUrl(config.db.connection) });\n }\n\n ui.stderr(\n formatStyledHeader({\n command: context.commandName,\n description: context.description,\n url: context.url,\n details,\n flags,\n }),\n );\n }\n\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for ${context.commandName} (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: context.commandName,\n }),\n );\n }\n\n if (!config.driver) {\n return notOk(\n errorDriverRequired({\n why: `Config.driver is required for ${context.commandName}`,\n }),\n );\n }\n\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 const onProgress = createProgressAdapter({ ui, flags });\n\n try {\n const schema = await client.introspect({\n connection: dbConnection,\n onProgress,\n });\n const schemaView = client.toSchemaView(schema);\n const pslContractAst = client.inferPslContract(schema);\n\n const dbUrl = typeof dbConnection === 'string' ? maskConnectionUrl(dbConnection) : undefined;\n\n return ok({\n config,\n schema,\n schemaView,\n pslContractAst,\n target: {\n familyId: config.family.familyId,\n id: config.target.targetId,\n },\n meta: {\n configPath,\n ...(dbUrl ? { dbUrl } : {}),\n },\n timings: {\n total: Date.now() - startTime,\n },\n });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n\n const rawMessage = error instanceof Error ? error.message : String(error);\n const safeMessage = sanitizeErrorMessage(\n rawMessage,\n typeof dbConnection === 'string' ? dbConnection : undefined,\n );\n return notOk(\n errorUnexpected(safeMessage, {\n why: `Unexpected error during ${context.commandName}: ${safeMessage}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n"],"mappings":";;;;;;;;AAsDA,eAAsB,kBACpB,SACA,OACA,IACA,WACA,SAC8D;CAC9D,IAAI;CACJ,IAAI;EACF,SAAS,MAAM,WAAW,QAAQ,OAAO;UAClC,OAAO;EACd,IAAI,mBAAmB,GAAG,MAAM,EAC9B,OAAO,MAAM,MAAM;EAGrB,OAAO,MACL,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACtE,KAAK,yBACN,CAAC,CACH;;CAGH,MAAM,aAAa,QAAQ,SACvB,SAAS,QAAQ,KAAK,EAAE,QAAQ,QAAQ,OAAO,CAAC,GAChD;CAEJ,IAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EAC/B,MAAM,UAAmD,CACvD;GAAE,OAAO;GAAU,OAAO;GAAY,CACvC;EAED,IAAI,QAAQ,IACV,QAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,QAAQ,GAAG;GAAE,CAAC;OACpE,IAAI,OAAO,IAAI,cAAc,OAAO,OAAO,GAAG,eAAe,UAClE,QAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,OAAO,GAAG,WAAW;GAAE,CAAC;EAGrF,GAAG,OACD,mBAAmB;GACjB,SAAS,QAAQ;GACjB,aAAa,QAAQ;GACrB,KAAK,QAAQ;GACb;GACA;GACD,CAAC,CACH;;CAGH,MAAM,eAAe,QAAQ,MAAM,OAAO,IAAI;CAC9C,IAAI,CAAC,cACH,OAAO,MACL,gCAAgC;EAC9B,KAAK,uCAAuC,QAAQ,YAAY,yBAAyB,WAAW;EACpG,aAAa,QAAQ;EACtB,CAAC,CACH;CAGH,IAAI,CAAC,OAAO,QACV,OAAO,MACL,oBAAoB,EAClB,KAAK,iCAAiC,QAAQ,eAC/C,CAAC,CACH;CAGH,MAAM,SAAS,oBAAoB;EACjC,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,QAAQ,OAAO;EACf,gBAAgB,OAAO,kBAAkB,EAAE;EAC5C,CAAC;CACF,MAAM,aAAa,sBAAsB;EAAE;EAAI;EAAO,CAAC;CAEvD,IAAI;EACF,MAAM,SAAS,MAAM,OAAO,WAAW;GACrC,YAAY;GACZ;GACD,CAAC;EACF,MAAM,aAAa,OAAO,aAAa,OAAO;EAC9C,MAAM,iBAAiB,OAAO,iBAAiB,OAAO;EAEtD,MAAM,QAAQ,OAAO,iBAAiB,WAAW,kBAAkB,aAAa,GAAG,KAAA;EAEnF,OAAO,GAAG;GACR;GACA;GACA;GACA;GACA,QAAQ;IACN,UAAU,OAAO,OAAO;IACxB,IAAI,OAAO,OAAO;IACnB;GACD,MAAM;IACJ;IACA,GAAI,QAAQ,EAAE,OAAO,GAAG,EAAE;IAC3B;GACD,SAAS,EACP,OAAO,KAAK,KAAK,GAAG,WACrB;GACF,CAAC;UACK,OAAO;EACd,IAAI,mBAAmB,GAAG,MAAM,EAC9B,OAAO,MAAM,MAAM;EAIrB,MAAM,cAAc,qBADD,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAGvE,OAAO,iBAAiB,WAAW,eAAe,KAAA,EACnD;EACD,OAAO,MACL,gBAAgB,aAAa,EAC3B,KAAK,2BAA2B,QAAQ,YAAY,IAAI,eACzD,CAAC,CACH;WACO;EACR,MAAM,OAAO,OAAO"}
|
package/dist/migration-cli.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Migration } from "@prisma-next/migration-tools/migration";
|
|
2
|
+
import { Writable } from "node:stream";
|
|
2
3
|
|
|
3
4
|
//#region src/migration-cli.d.ts
|
|
4
|
-
|
|
5
5
|
/**
|
|
6
6
|
* Constructor shape accepted by `MigrationCLI.run`. `Migration` subclasses
|
|
7
7
|
* accept an optional `ControlStack` in their constructor (each subclass
|
|
@@ -18,6 +18,20 @@ import { Migration } from "@prisma-next/migration-tools/migration";
|
|
|
18
18
|
* point for additional construction arguments.
|
|
19
19
|
*/
|
|
20
20
|
type MigrationConstructor = new (...args: any[]) => Migration;
|
|
21
|
+
/**
|
|
22
|
+
* Stream surface accepted by `MigrationCLI.run`'s `options.stdout` /
|
|
23
|
+
* `options.stderr`. Aliases node's `Writable` because clipanion's
|
|
24
|
+
* `BaseContext.stdout`/`stderr` are typed as `Writable`, and the CLI
|
|
25
|
+
* forwards the injected streams into clipanion's context.
|
|
26
|
+
*
|
|
27
|
+
* `process.stdout` and `process.stderr` are `Writable`-shaped, so the
|
|
28
|
+
* default-fallback path remains a no-op for existing two-argument
|
|
29
|
+
* callers like `MigrationCLI.run(import.meta.url, MyMigration)`.
|
|
30
|
+
*
|
|
31
|
+
* Tests inject a `Writable` subclass that captures chunks for
|
|
32
|
+
* assertions.
|
|
33
|
+
*/
|
|
34
|
+
type MigrationCliWritable = Writable;
|
|
21
35
|
/**
|
|
22
36
|
* The CLI surface invoked by an authored `migration.ts` file. Exposed as
|
|
23
37
|
* a class with a static `run` method (rather than a free function) to
|
|
@@ -32,19 +46,34 @@ type MigrationConstructor = new (...args: any[]) => Migration;
|
|
|
32
46
|
*/
|
|
33
47
|
declare class MigrationCLI {
|
|
34
48
|
/**
|
|
35
|
-
* Orchestrates a class-flow `migration.ts` script run.
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
49
|
+
* Orchestrates a class-flow `migration.ts` script run.
|
|
50
|
+
*
|
|
51
|
+
* The third argument is the in-process testability surface: callers
|
|
52
|
+
* (and tests) may inject `argv`, `stdout`, and `stderr` instead of
|
|
53
|
+
* relying on `process.argv` / `process.stdout` / `process.stderr`.
|
|
54
|
+
* Each option defaults to its `process` global when omitted, so
|
|
55
|
+
* existing two-argument call sites
|
|
56
|
+
* (`MigrationCLI.run(import.meta.url, MyMigration)`) continue to
|
|
57
|
+
* compile and behave identically.
|
|
58
|
+
*
|
|
59
|
+
* Returns the exit code so the caller can branch on it. Also writes
|
|
60
|
+
* the same code to `process.exitCode` so script-style callers that
|
|
61
|
+
* don't await the return value still surface a non-zero exit when
|
|
62
|
+
* something fails.
|
|
40
63
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
64
|
+
* Exit codes:
|
|
65
|
+
* - 0 — success, or `--help`, or imported-not-entrypoint no-op.
|
|
66
|
+
* - 1 — runtime/orchestration error (config not found, target
|
|
67
|
+
* mismatch, etc.).
|
|
68
|
+
* - 2 — usage error (unknown flag, malformed `--config`). Aligns
|
|
69
|
+
* with `docs/CLI Style Guide.md` § Exit Codes.
|
|
45
70
|
*/
|
|
46
|
-
static run(importMetaUrl: string, MigrationClass: MigrationConstructor
|
|
71
|
+
static run(importMetaUrl: string, MigrationClass: MigrationConstructor, options?: {
|
|
72
|
+
readonly argv?: readonly string[];
|
|
73
|
+
readonly stdout?: MigrationCliWritable;
|
|
74
|
+
readonly stderr?: MigrationCliWritable;
|
|
75
|
+
}): Promise<number>;
|
|
47
76
|
}
|
|
48
77
|
//#endregion
|
|
49
|
-
export { MigrationCLI, MigrationConstructor };
|
|
78
|
+
export { MigrationCLI, MigrationCliWritable, MigrationConstructor };
|
|
50
79
|
//# sourceMappingURL=migration-cli.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-cli.d.mts","names":[],"sources":["../src/migration-cli.ts"],"
|
|
1
|
+
{"version":3,"file":"migration-cli.d.mts","names":[],"sources":["../src/migration-cli.ts"],"mappings":";;;;;;;;;;;;;;;;;;;KA6EY,oBAAA,WAA+B,IAAA,YAAgB,SAAA;;;;;;;;;;;;;;KAe/C,oBAAA,GAAuB,QAAA;;;;;;;;;;;;;cAuEtB,YAAA;;;;;;;;;;;;;;;;;;;;;;;;SAwBE,GAAA,CACX,aAAA,UACA,cAAA,EAAgB,oBAAA,EAChB,OAAA;IAAA,SACW,IAAA;IAAA,SACA,MAAA,GAAS,oBAAA;IAAA,SACT,MAAA,GAAS,oBAAA;EAAA,IAEnB,OAAA;AAAA"}
|
package/dist/migration-cli.mjs
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { t as loadConfig } from "./config-loader-
|
|
2
|
-
import {
|
|
3
|
-
import { CliStructuredError, errorMigrationCliInvalidConfigArg } from "@prisma-next/errors/control";
|
|
1
|
+
import { t as loadConfig } from "./config-loader-B6sJjXTv.mjs";
|
|
2
|
+
import { CliStructuredError, errorMigrationCliInvalidConfigArg, errorMigrationCliUnknownFlag } from "@prisma-next/errors/control";
|
|
4
3
|
import { dirname, join } from "pathe";
|
|
5
4
|
import { createControlStack } from "@prisma-next/framework-components/control";
|
|
6
5
|
import { errorMigrationTargetMismatch } from "@prisma-next/errors/migration";
|
|
6
|
+
import { readFileSync, realpathSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { MigrationToolsError, errorInvalidJson } from "@prisma-next/migration-tools/errors";
|
|
7
8
|
import { fileURLToPath } from "node:url";
|
|
8
|
-
import { buildMigrationArtifacts
|
|
9
|
-
|
|
9
|
+
import { buildMigrationArtifacts } from "@prisma-next/migration-tools/migration";
|
|
10
|
+
import { Cli, Command, Option, UsageError } from "clipanion";
|
|
10
11
|
//#region src/migration-cli.ts
|
|
11
12
|
/**
|
|
12
13
|
* The migration-file CLI interface: the actor invoked when the author runs
|
|
@@ -25,7 +26,8 @@ import { buildMigrationArtifacts, isDirectEntrypoint, printMigrationHelp } from
|
|
|
25
26
|
* entrypoint (`node migration.ts`), the CLI:
|
|
26
27
|
*
|
|
27
28
|
* 1. Detects whether the file is the direct entrypoint (no-op when imported).
|
|
28
|
-
* 2. Parses CLI args (`--help`, `--dry-run`, `--config <path>`)
|
|
29
|
+
* 2. Parses CLI args (`--help`, `--dry-run`, `--config <path>`) via
|
|
30
|
+
* [clipanion](https://github.com/arcanis/clipanion).
|
|
29
31
|
* 3. Loads the project's `prisma-next.config.ts` via the same `loadConfig`
|
|
30
32
|
* the CLI commands use, walking up from the migration file's directory.
|
|
31
33
|
* 4. Probe-instantiates the migration class without a stack so it can read
|
|
@@ -44,44 +46,62 @@ import { buildMigrationArtifacts, isDirectEntrypoint, printMigrationHelp } from
|
|
|
44
46
|
* on-disk persistence. `@prisma-next/migration-tools` owns the pure
|
|
45
47
|
* conversion from a `Migration` instance to artifact strings; `Migration`
|
|
46
48
|
* stays a pure abstract class.
|
|
49
|
+
*
|
|
50
|
+
* Parser library: clipanion (chosen over Commander/citty/`node:util.parseArgs`
|
|
51
|
+
* for its in-process testability and runtime-agnostic execution surface; see
|
|
52
|
+
* `docs/architecture docs/research/commander-friction-points.md` for the
|
|
53
|
+
* evaluation rubric and the durable rationale that drove the choice).
|
|
47
54
|
*/
|
|
48
55
|
/**
|
|
49
|
-
*
|
|
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.
|
|
56
|
+
* Flags exposed by the migration-file CLI.
|
|
53
57
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
* Must stay in sync with the `Option` declarations on
|
|
59
|
+
* `MigrationFileCommand` below. This list is rendered in the
|
|
60
|
+
* `errorMigrationCliUnknownFlag` envelope's `fix` text and `meta`,
|
|
61
|
+
* so order matters for user-visible output (declaration order is the
|
|
62
|
+
* order users see when they run `--help`).
|
|
63
|
+
*/
|
|
64
|
+
const KNOWN_FLAGS = [
|
|
65
|
+
"--help",
|
|
66
|
+
"--dry-run",
|
|
67
|
+
"--config"
|
|
68
|
+
];
|
|
69
|
+
/**
|
|
70
|
+
* The clipanion command that owns the migration-file CLI's option
|
|
71
|
+
* declarations. The class is internal — `MigrationCLI.run` is the
|
|
72
|
+
* stable public surface. Adding a flag here automatically updates
|
|
73
|
+
* `--help` rendering and the `KNOWN_FLAGS` list (the latter must be
|
|
74
|
+
* updated in tandem).
|
|
62
75
|
*/
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
var MigrationFileCommand = class extends Command {
|
|
77
|
+
static paths = [Command.Default];
|
|
78
|
+
static usage = Command.Usage({
|
|
79
|
+
description: "Self-emit ops.json and migration.json from a class-flow migration",
|
|
80
|
+
details: `
|
|
81
|
+
Loads the project's prisma-next.config.ts, assembles a ControlStack
|
|
82
|
+
from the configured target/adapter/extensions, and serializes the
|
|
83
|
+
migration's operations + metadata next to this file.
|
|
84
|
+
`,
|
|
85
|
+
examples: [
|
|
86
|
+
["Self-emit ops.json + migration.json next to migration.ts", "$0"],
|
|
87
|
+
["Preview without writing files", "$0 --dry-run"],
|
|
88
|
+
["Use a non-default config path", "$0 --config ./custom.config.ts"]
|
|
89
|
+
]
|
|
90
|
+
});
|
|
91
|
+
dryRun = Option.Boolean("--dry-run", false, { description: "Print operations to stdout without writing files" });
|
|
92
|
+
config = Option.String("--config", { description: "Path to prisma-next.config.ts" });
|
|
93
|
+
/**
|
|
94
|
+
* Unused: orchestration runs inside `MigrationCLI.run` so error
|
|
95
|
+
* routing stays under our control (clipanion's `cli.run` writes
|
|
96
|
+
* error output to `context.stdout`, but our contract requires
|
|
97
|
+
* structured errors on stderr). `cli.process` is used to parse
|
|
98
|
+
* argv into a populated `MigrationFileCommand` instance whose
|
|
99
|
+
* fields drive the orchestration directly.
|
|
100
|
+
*/
|
|
101
|
+
async execute() {
|
|
102
|
+
return 0;
|
|
78
103
|
}
|
|
79
|
-
|
|
80
|
-
help,
|
|
81
|
-
dryRun,
|
|
82
|
-
configPath
|
|
83
|
-
};
|
|
84
|
-
}
|
|
104
|
+
};
|
|
85
105
|
/**
|
|
86
106
|
* The CLI surface invoked by an authored `migration.ts` file. Exposed as
|
|
87
107
|
* a class with a static `run` method (rather than a free function) to
|
|
@@ -96,59 +116,243 @@ function parseArgs(argv) {
|
|
|
96
116
|
*/
|
|
97
117
|
var MigrationCLI = class {
|
|
98
118
|
/**
|
|
99
|
-
* Orchestrates a class-flow `migration.ts` script run.
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
119
|
+
* Orchestrates a class-flow `migration.ts` script run.
|
|
120
|
+
*
|
|
121
|
+
* The third argument is the in-process testability surface: callers
|
|
122
|
+
* (and tests) may inject `argv`, `stdout`, and `stderr` instead of
|
|
123
|
+
* relying on `process.argv` / `process.stdout` / `process.stderr`.
|
|
124
|
+
* Each option defaults to its `process` global when omitted, so
|
|
125
|
+
* existing two-argument call sites
|
|
126
|
+
* (`MigrationCLI.run(import.meta.url, MyMigration)`) continue to
|
|
127
|
+
* compile and behave identically.
|
|
104
128
|
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
129
|
+
* Returns the exit code so the caller can branch on it. Also writes
|
|
130
|
+
* the same code to `process.exitCode` so script-style callers that
|
|
131
|
+
* don't await the return value still surface a non-zero exit when
|
|
132
|
+
* something fails.
|
|
133
|
+
*
|
|
134
|
+
* Exit codes:
|
|
135
|
+
* - 0 — success, or `--help`, or imported-not-entrypoint no-op.
|
|
136
|
+
* - 1 — runtime/orchestration error (config not found, target
|
|
137
|
+
* mismatch, etc.).
|
|
138
|
+
* - 2 — usage error (unknown flag, malformed `--config`). Aligns
|
|
139
|
+
* with `docs/CLI Style Guide.md` § Exit Codes.
|
|
109
140
|
*/
|
|
110
|
-
static async run(importMetaUrl, MigrationClass) {
|
|
111
|
-
if (!importMetaUrl) return;
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
141
|
+
static async run(importMetaUrl, MigrationClass, options = {}) {
|
|
142
|
+
if (!importMetaUrl) return 0;
|
|
143
|
+
const argv = options.argv ?? process.argv;
|
|
144
|
+
const stdout = options.stdout ?? process.stdout;
|
|
145
|
+
const stderr = options.stderr ?? process.stderr;
|
|
146
|
+
if (!isDirectEntrypoint(importMetaUrl, argv)) return 0;
|
|
147
|
+
const exitCode = await orchestrate(importMetaUrl, MigrationClass, {
|
|
148
|
+
argv,
|
|
149
|
+
stdout,
|
|
150
|
+
stderr
|
|
151
|
+
});
|
|
152
|
+
if (exitCode !== 0 || !process.exitCode) process.exitCode = exitCode;
|
|
153
|
+
return exitCode;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Argv-aware variant of the entrypoint guard. The shared
|
|
158
|
+
* `@prisma-next/migration-tools` helper of the same name reads
|
|
159
|
+
* `process.argv[1]` directly, which doesn't compose with the new
|
|
160
|
+
* in-process testability surface (tests inject `argv` without mutating
|
|
161
|
+
* the process global). Inlined here so the migration-file CLI's check
|
|
162
|
+
* follows the injected `argv[1]` consistently.
|
|
163
|
+
*/
|
|
164
|
+
function isDirectEntrypoint(importMetaUrl, argv) {
|
|
165
|
+
const argv1 = argv[1];
|
|
166
|
+
if (!argv1) return false;
|
|
167
|
+
try {
|
|
168
|
+
return realpathSync(fileURLToPath(importMetaUrl)) === realpathSync(argv1);
|
|
169
|
+
} catch {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Argv-and-stream-driven orchestration body. Pulled out of the static
|
|
175
|
+
* method so the entrypoint guard / process-default plumbing stays
|
|
176
|
+
* separate from the parse + load + serialize steps.
|
|
177
|
+
*/
|
|
178
|
+
async function orchestrate(importMetaUrl, MigrationClass, ctx) {
|
|
179
|
+
const cli = Cli.from([MigrationFileCommand], {
|
|
180
|
+
binaryName: "migration.ts",
|
|
181
|
+
binaryLabel: "Migration file CLI"
|
|
182
|
+
});
|
|
183
|
+
const input = ctx.argv.slice(2);
|
|
184
|
+
const configError = detectInvalidConfig(input);
|
|
185
|
+
if (configError) {
|
|
186
|
+
writeStructuredError(ctx.stderr, configError);
|
|
187
|
+
return 2;
|
|
188
|
+
}
|
|
189
|
+
let parsed;
|
|
190
|
+
try {
|
|
191
|
+
const command = cli.process({
|
|
192
|
+
input: [...input],
|
|
193
|
+
context: {
|
|
194
|
+
stdout: ctx.stdout,
|
|
195
|
+
stderr: ctx.stderr
|
|
118
196
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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;
|
|
197
|
+
});
|
|
198
|
+
if (!(command instanceof MigrationFileCommand)) {
|
|
199
|
+
ctx.stdout.write(cli.usage(MigrationFileCommand, { detailed: true }));
|
|
200
|
+
return 0;
|
|
131
201
|
}
|
|
202
|
+
parsed = command;
|
|
203
|
+
} catch (err) {
|
|
204
|
+
return renderParseError(err, input, ctx.stderr);
|
|
132
205
|
}
|
|
133
|
-
|
|
206
|
+
if (parsed.help) {
|
|
207
|
+
ctx.stdout.write(cli.usage(MigrationFileCommand, { detailed: true }));
|
|
208
|
+
return 0;
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
await runMigration(importMetaUrl, MigrationClass, parsed, ctx);
|
|
212
|
+
return 0;
|
|
213
|
+
} catch (err) {
|
|
214
|
+
if (CliStructuredError.is(err)) writeStructuredError(ctx.stderr, err);
|
|
215
|
+
else if (MigrationToolsError.is(err)) {
|
|
216
|
+
const fix = err.fix ? `\n${err.fix}` : "";
|
|
217
|
+
ctx.stderr.write(`${err.code}: ${err.message}\n${err.why}${fix}\n`);
|
|
218
|
+
} else ctx.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
|
|
219
|
+
return 1;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Returns an `errorMigrationCliInvalidConfigArg` envelope when `input`
|
|
224
|
+
* contains a malformed `--config`:
|
|
225
|
+
*
|
|
226
|
+
* - `--config` as the last token (no value follows).
|
|
227
|
+
* - `--config <flag>` where `<flag>` starts with `-` (silently
|
|
228
|
+
* consuming the next flag would either drop the flag or serialize
|
|
229
|
+
* against the wrong project).
|
|
230
|
+
* - `--config <empty>` where the value is the empty string. Shells
|
|
231
|
+
* expand `--config ""` (or `--config "$UNSET_VAR"`) into a real
|
|
232
|
+
* empty argv token; treating that as a usage error here surfaces
|
|
233
|
+
* `PN-CLI-4012` instead of a less actionable loader error on an
|
|
234
|
+
* empty path.
|
|
235
|
+
* - `--config=` (the equals form with an empty value). Same shape as
|
|
236
|
+
* the empty-string case above; the user expressed intent to override
|
|
237
|
+
* the config path but the override is empty.
|
|
238
|
+
*
|
|
239
|
+
* `--config=<value>` and `--config <value>` with a non-empty value are
|
|
240
|
+
* both valid (and the equals form's value is allowed to start with
|
|
241
|
+
* `-` — the `=` makes the binding explicit).
|
|
242
|
+
*/
|
|
243
|
+
function detectInvalidConfig(input) {
|
|
244
|
+
for (let i = 0; i < input.length; i++) {
|
|
245
|
+
const token = input[i];
|
|
246
|
+
if (token === "--config") {
|
|
247
|
+
const next = input[i + 1];
|
|
248
|
+
if (next === void 0 || next === "") return errorMigrationCliInvalidConfigArg();
|
|
249
|
+
if (next.startsWith("-")) return errorMigrationCliInvalidConfigArg({ nextToken: next });
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (token === "--config=") return errorMigrationCliInvalidConfigArg();
|
|
253
|
+
}
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Translate clipanion's parse-time errors into the project's structured
|
|
258
|
+
* error envelopes.
|
|
259
|
+
*
|
|
260
|
+
* - `UnknownSyntaxError` covers both unknown flags (`--frobnicate`) and
|
|
261
|
+
* the bare-trailing `--config` case (where arity-1 needs a value but
|
|
262
|
+
* none was supplied). Distinguished by inspecting the input array.
|
|
263
|
+
* - `UsageError` covers schema/validator failures from typanion. None
|
|
264
|
+
* of the migration-file CLI's options have validators today, but we
|
|
265
|
+
* still translate it as a usage error (exit 2) for forward-compat.
|
|
266
|
+
* - Anything else re-throws — caller's outer catch will surface it as
|
|
267
|
+
* exit 1 (runtime error).
|
|
268
|
+
*/
|
|
269
|
+
function renderParseError(err, input, stderr) {
|
|
270
|
+
if (isUnknownSyntaxError(err)) {
|
|
271
|
+
writeStructuredError(stderr, errorMigrationCliUnknownFlag({
|
|
272
|
+
flag: findOffendingFlag(input),
|
|
273
|
+
knownFlags: KNOWN_FLAGS
|
|
274
|
+
}));
|
|
275
|
+
return 2;
|
|
276
|
+
}
|
|
277
|
+
if (err instanceof UsageError) {
|
|
278
|
+
writeStructuredError(stderr, errorMigrationCliInvalidConfigArg({ nextToken: err.message }));
|
|
279
|
+
return 2;
|
|
280
|
+
}
|
|
281
|
+
throw err;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Duck-type check for clipanion's `UnknownSyntaxError`: the class is
|
|
285
|
+
* thrown by the parser but is not re-exported from the package's main
|
|
286
|
+
* entry (only `UsageError` is — see clipanion's `advanced/index.d.ts`).
|
|
287
|
+
* Identified by `name === 'UnknownSyntaxError'` and the
|
|
288
|
+
* `clipanion.type === 'none'` discriminator that clipanion's
|
|
289
|
+
* `ErrorWithMeta` interface guarantees.
|
|
290
|
+
*/
|
|
291
|
+
function isUnknownSyntaxError(err) {
|
|
292
|
+
if (!(err instanceof Error) || err.name !== "UnknownSyntaxError") return false;
|
|
293
|
+
const meta = err.clipanion;
|
|
294
|
+
return typeof meta === "object" && meta !== null && meta.type === "none";
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Best-effort: pull the first input token that doesn't match a known
|
|
298
|
+
* flag. Falls back to the first token when we can't pinpoint it. The
|
|
299
|
+
* returned name is rendered into the user-visible PN-CLI-4013 envelope
|
|
300
|
+
* (`Unknown flag \`<name>\``) and round-tripped via `meta.flag` so
|
|
301
|
+
* agent consumers can render their own "did you mean" suggestions.
|
|
302
|
+
*/
|
|
303
|
+
function findOffendingFlag(input) {
|
|
304
|
+
for (const token of input) {
|
|
305
|
+
if (!token.startsWith("-")) continue;
|
|
306
|
+
const head = token.split("=", 1)[0] ?? token;
|
|
307
|
+
if (!KNOWN_FLAGS.includes(head) && head !== "-h") return head;
|
|
308
|
+
}
|
|
309
|
+
return input[0] ?? "";
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Write a `CliStructuredError` envelope to the given stream. Format
|
|
313
|
+
* matches the legacy hand-rolled writer (`message: why`) so the rest of
|
|
314
|
+
* the project's error rendering stays consistent across surfaces. The
|
|
315
|
+
* full PN code (`PN-<domain>-<code>`) is included so consumers can
|
|
316
|
+
* grep for stable identifiers.
|
|
317
|
+
*/
|
|
318
|
+
function writeStructuredError(stream, err) {
|
|
319
|
+
const envelope = err.toEnvelope();
|
|
320
|
+
const why = envelope.why ?? envelope.summary;
|
|
321
|
+
const fix = envelope.fix ? `\n${envelope.fix}` : "";
|
|
322
|
+
stream.write(`${envelope.code}: ${envelope.summary}\n${why}${fix}\n`);
|
|
323
|
+
}
|
|
134
324
|
/**
|
|
135
325
|
* Read a previously-scaffolded `migration.json` from disk, returning
|
|
136
|
-
* `null` when the file is missing
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
326
|
+
* `null` when the file is missing and throwing `MIGRATION.INVALID_JSON`
|
|
327
|
+
* when the file is present but cannot be parsed as JSON. The CLI feeds
|
|
328
|
+
* this into `buildMigrationArtifacts` so the pure builder can preserve
|
|
329
|
+
* fields owned by `migration plan` (contract bookends, hints, labels,
|
|
330
|
+
* `createdAt`) across re-emits.
|
|
331
|
+
*
|
|
332
|
+
* Author-time path: this loader still does not verify the manifest hash
|
|
333
|
+
* or schema — that is the apply-time loader's job. Hash mismatch is the
|
|
334
|
+
* *expected* outcome of a re-author (the developer's source changes
|
|
335
|
+
* invalidate the prior hash by construction), and verification here
|
|
336
|
+
* would block legitimate regenerations. Syntactic JSON-parse failure,
|
|
337
|
+
* however, is now surfaced rather than swallowed: a malformed
|
|
338
|
+
* `migration.json` indicates either a hand-edit gone wrong or partial
|
|
339
|
+
* write, and silently rebuilding from `describe()` would discard the
|
|
340
|
+
* user's on-disk content (preserved bookends, hints, labels,
|
|
341
|
+
* `createdAt`) without any indication something was wrong on disk.
|
|
342
|
+
* Apply-time consumers always route through the verifying
|
|
343
|
+
* `readMigrationPackage` in `@prisma-next/migration-tools/io` instead.
|
|
140
344
|
*/
|
|
141
|
-
function
|
|
345
|
+
function readExistingMetadata(metadataPath) {
|
|
142
346
|
let raw;
|
|
143
347
|
try {
|
|
144
|
-
raw = readFileSync(
|
|
348
|
+
raw = readFileSync(metadataPath, "utf-8");
|
|
145
349
|
} catch {
|
|
146
350
|
return null;
|
|
147
351
|
}
|
|
148
352
|
try {
|
|
149
353
|
return JSON.parse(raw);
|
|
150
|
-
} catch {
|
|
151
|
-
|
|
354
|
+
} catch (e) {
|
|
355
|
+
throw errorInvalidJson(metadataPath, e instanceof Error ? e.message : String(e));
|
|
152
356
|
}
|
|
153
357
|
}
|
|
154
358
|
/**
|
|
@@ -165,20 +369,39 @@ function readExistingManifest(manifestPath) {
|
|
|
165
369
|
* legitimate site for combining config loading, stack assembly, and
|
|
166
370
|
* filesystem persistence.
|
|
167
371
|
*/
|
|
168
|
-
function serializeMigrationToDisk(instance, migrationDir, dryRun) {
|
|
169
|
-
const
|
|
170
|
-
const { opsJson,
|
|
372
|
+
function serializeMigrationToDisk(instance, migrationDir, dryRun, stdout) {
|
|
373
|
+
const metadataPath = join(migrationDir, "migration.json");
|
|
374
|
+
const { opsJson, metadataJson } = buildMigrationArtifacts(instance, readExistingMetadata(metadataPath));
|
|
171
375
|
if (dryRun) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
376
|
+
stdout.write(`--- migration.json ---\n${metadataJson}\n`);
|
|
377
|
+
stdout.write("--- ops.json ---\n");
|
|
378
|
+
stdout.write(`${opsJson}\n`);
|
|
175
379
|
return;
|
|
176
380
|
}
|
|
177
381
|
writeFileSync(join(migrationDir, "ops.json"), opsJson);
|
|
178
|
-
writeFileSync(
|
|
179
|
-
|
|
382
|
+
writeFileSync(metadataPath, metadataJson);
|
|
383
|
+
stdout.write(`Wrote ops.json + migration.json to ${migrationDir}\n`);
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Inner orchestration: load config, probe-construct the migration,
|
|
387
|
+
* verify target, assemble the stack, construct with the stack, persist.
|
|
388
|
+
*
|
|
389
|
+
* Throws `CliStructuredError` for known failure modes (config not
|
|
390
|
+
* found, target mismatch); the outer `orchestrate` translates those to
|
|
391
|
+
* exit 1.
|
|
392
|
+
*/
|
|
393
|
+
async function runMigration(importMetaUrl, MigrationClass, parsed, ctx) {
|
|
394
|
+
const migrationDir = dirname(fileURLToPath(importMetaUrl));
|
|
395
|
+
const config = await loadConfig(parsed.config);
|
|
396
|
+
const probe = new MigrationClass();
|
|
397
|
+
if (probe.targetId !== config.target.targetId) throw errorMigrationTargetMismatch({
|
|
398
|
+
migrationTargetId: probe.targetId,
|
|
399
|
+
configTargetId: config.target.targetId
|
|
400
|
+
});
|
|
401
|
+
serializeMigrationToDisk(new MigrationClass(createControlStack(config)), migrationDir, parsed.dryRun, ctx.stdout);
|
|
402
|
+
ctx.stderr;
|
|
180
403
|
}
|
|
181
|
-
|
|
182
404
|
//#endregion
|
|
183
405
|
export { MigrationCLI };
|
|
406
|
+
|
|
184
407
|
//# sourceMappingURL=migration-cli.mjs.map
|