@prisma-next/cli 0.14.0-dev.4 → 0.14.0-dev.40
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/README.md +2 -2
- package/dist/cli.mjs +27 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-CJzuo5wX.mjs → client-CWTNqJdj.mjs} +76 -72
- package/dist/client-CWTNqJdj.mjs.map +1 -0
- package/dist/{command-helpers-DGMvGBeX.mjs → command-helpers-6cNJZ863.mjs} +3 -3
- package/dist/{command-helpers-DGMvGBeX.mjs.map → command-helpers-6cNJZ863.mjs.map} +1 -1
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.mjs +3 -3
- package/dist/commands/db-schema.mjs +3 -3
- package/dist/commands/db-sign.mjs +5 -5
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.mjs +4 -4
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +1 -1
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +35 -35
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.d.mts +1 -1
- package/dist/commands/migration-check.mjs +1 -1
- package/dist/commands/migration-graph.d.mts +1 -1
- package/dist/commands/migration-graph.mjs +8 -8
- package/dist/commands/migration-graph.mjs.map +1 -1
- package/dist/commands/migration-list.d.mts +6 -6
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +1 -1
- package/dist/commands/migration-log.d.mts +1 -1
- package/dist/commands/migration-log.mjs +1 -1
- package/dist/commands/migration-new.mjs +4 -4
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.mjs +4 -4
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +1 -1
- package/dist/commands/migration-status.mjs +1 -1
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.mjs +3 -3
- package/dist/commands/ref.mjs.map +1 -1
- package/dist/commands/telemetry/index.mjs +1 -1
- package/dist/{contract-at-errors-CFXsstzm.mjs → contract-at-errors-DdxWRjMc.mjs} +2 -2
- package/dist/{contract-at-errors-CFXsstzm.mjs.map → contract-at-errors-DdxWRjMc.mjs.map} +1 -1
- package/dist/{contract-emit-C8HmtboH.mjs → contract-emit-CMwCj7_m.mjs} +8 -6
- package/dist/contract-emit-CMwCj7_m.mjs.map +1 -0
- package/dist/{contract-emit-B_qriF8B.mjs → contract-emit-klH7zzaV.mjs} +6 -6
- package/dist/contract-emit-klH7zzaV.mjs.map +1 -0
- package/dist/{contract-infer-BYT_ra_U.mjs → contract-infer-B__56PGb.mjs} +3 -3
- package/dist/{contract-infer-BYT_ra_U.mjs.map → contract-infer-B__56PGb.mjs.map} +1 -1
- package/dist/{contract-space-aggregate-loader-ClI1KN6d.mjs → contract-space-aggregate-loader-Bu2fjSWV.mjs} +2 -2
- package/dist/{contract-space-aggregate-loader-ClI1KN6d.mjs.map → contract-space-aggregate-loader-Bu2fjSWV.mjs.map} +1 -1
- package/dist/{db-verify-C24FKhb7.mjs → db-verify-DlqHvkkA.mjs} +69 -49
- package/dist/db-verify-DlqHvkkA.mjs.map +1 -0
- package/dist/exports/control-api.d.mts +3 -3
- package/dist/exports/control-api.mjs +2 -2
- package/dist/exports/index.mjs +2 -2
- package/dist/extension-pack-inputs-1ySHqxKG.mjs.map +1 -1
- package/dist/{format-C8yv6mXH.mjs → format-C3XdaDuA.mjs} +3 -3
- package/dist/format-C3XdaDuA.mjs.map +1 -0
- package/dist/{framework-components-YVQHhPH7.mjs → framework-components-5RljWT7Q.mjs} +2 -2
- package/dist/{framework-components-YVQHhPH7.mjs.map → framework-components-5RljWT7Q.mjs.map} +1 -1
- package/dist/{init-a3-ljrL3.mjs → init-BF3s9NcB.mjs} +3 -3
- package/dist/{init-a3-ljrL3.mjs.map → init-BF3s9NcB.mjs.map} +1 -1
- package/dist/{inspect-live-schema-DF6IwcDl.mjs → inspect-live-schema-Dd1Ft0dw.mjs} +4 -4
- package/dist/inspect-live-schema-Dd1Ft0dw.mjs.map +1 -0
- package/dist/{migration-check-VwM8xCZV.mjs → migration-check-UoHMvsP3.mjs} +10 -11
- package/dist/migration-check-UoHMvsP3.mjs.map +1 -0
- package/dist/migration-cli.mjs +1 -1
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-DA-Lhx6o.mjs → migration-command-scaffold-DW2BpjZW.mjs} +4 -4
- package/dist/migration-command-scaffold-DW2BpjZW.mjs.map +1 -0
- package/dist/{migration-list-DlJJ_38Z.mjs → migration-list-BOzQzJK4.mjs} +15 -15
- package/dist/migration-list-BOzQzJK4.mjs.map +1 -0
- package/dist/{migration-log-CG0qQAFm.mjs → migration-log-q50rqMiU.mjs} +4 -4
- package/dist/migration-log-q50rqMiU.mjs.map +1 -0
- package/dist/{migration-path-target-Ce6OZImp.mjs → migration-path-target-zK6RG6JY.mjs} +2 -2
- package/dist/{migration-path-target-Ce6OZImp.mjs.map → migration-path-target-zK6RG6JY.mjs.map} +1 -1
- package/dist/{migration-plan-W_E8FQOk.mjs → migration-plan-BwJLPkwV.mjs} +24 -24
- package/dist/migration-plan-BwJLPkwV.mjs.map +1 -0
- package/dist/{migration-status-CD-LC2Ip.mjs → migration-status-27NzO2SC.mjs} +13 -14
- package/dist/migration-status-27NzO2SC.mjs.map +1 -0
- package/dist/{telemetry-BIM4beEO.mjs → telemetry-BckOSUWG.mjs} +2 -2
- package/dist/{telemetry-BIM4beEO.mjs.map → telemetry-BckOSUWG.mjs.map} +1 -1
- package/dist/{types-C_tYiJYx.d.mts → types-CKgJmH02.d.mts} +26 -20
- package/dist/types-CKgJmH02.d.mts.map +1 -0
- package/dist/{verify-DcOYZ1tH.mjs → verify-DC14_nPu.mjs} +29 -6
- package/dist/verify-DC14_nPu.mjs.map +1 -0
- package/package.json +21 -24
- package/src/cli.ts +3 -0
- package/src/commands/contract-emit.ts +1 -1
- package/src/commands/db-sign.ts +1 -1
- package/src/commands/db-verify.ts +32 -20
- package/src/commands/inspect-live-schema.ts +1 -1
- package/src/commands/lsp.ts +32 -0
- package/src/commands/migrate.ts +45 -42
- package/src/commands/migration-check.ts +6 -6
- package/src/commands/migration-graph.ts +5 -5
- package/src/commands/migration-list.ts +13 -13
- package/src/commands/migration-log.ts +1 -1
- package/src/commands/migration-new.ts +1 -1
- package/src/commands/migration-plan.ts +4 -4
- package/src/commands/migration-show.ts +1 -1
- package/src/commands/migration-status.ts +10 -10
- package/src/commands/ref.ts +1 -1
- package/src/control-api/client.ts +5 -3
- package/src/control-api/operations/contract-emit.ts +8 -7
- package/src/control-api/operations/db-init.ts +2 -2
- package/src/control-api/operations/db-run.ts +7 -7
- package/src/control-api/operations/db-verify.ts +38 -33
- package/src/control-api/operations/format.ts +1 -2
- package/src/control-api/operations/migrate.ts +66 -66
- package/src/control-api/operations/run-migration.ts +2 -2
- package/src/control-api/types.ts +7 -7
- package/src/migration-cli.ts +1 -1
- package/src/utils/combine-verify-results.ts +113 -0
- package/src/utils/extension-pack-inputs.ts +1 -1
- package/src/utils/formatters/verify.ts +44 -3
- package/src/utils/migration-command-scaffold.ts +1 -1
- package/src/utils/plan-resolution.ts +18 -18
- package/dist/client-CJzuo5wX.mjs.map +0 -1
- package/dist/config-loader-p9JMrekQ.mjs +0 -88
- package/dist/config-loader-p9JMrekQ.mjs.map +0 -1
- package/dist/config-loader.d.mts +0 -16
- package/dist/config-loader.d.mts.map +0 -1
- package/dist/config-loader.mjs +0 -2
- package/dist/contract-emit-B_qriF8B.mjs.map +0 -1
- package/dist/contract-emit-C8HmtboH.mjs.map +0 -1
- package/dist/db-verify-C24FKhb7.mjs.map +0 -1
- package/dist/format-C8yv6mXH.mjs.map +0 -1
- package/dist/inspect-live-schema-DF6IwcDl.mjs.map +0 -1
- package/dist/migration-check-VwM8xCZV.mjs.map +0 -1
- package/dist/migration-command-scaffold-DA-Lhx6o.mjs.map +0 -1
- package/dist/migration-list-DlJJ_38Z.mjs.map +0 -1
- package/dist/migration-log-CG0qQAFm.mjs.map +0 -1
- package/dist/migration-plan-W_E8FQOk.mjs.map +0 -1
- package/dist/migration-status-CD-LC2Ip.mjs.map +0 -1
- package/dist/types-C_tYiJYx.d.mts.map +0 -1
- package/dist/verify-DcOYZ1tH.mjs.map +0 -1
- package/src/config-loader.ts +0 -92
- package/src/config-path-validation.ts +0 -74
- package/src/utils/combine-schema-results.ts +0 -84
|
@@ -98,9 +98,9 @@ export interface ExecuteRunOptions<TFamilyId extends string, TTargetId extends s
|
|
|
98
98
|
* 2. **Read DB state**: marker rows (`familyInstance.readAllMarkers`)
|
|
99
99
|
* + introspected schema (`familyInstance.introspect`).
|
|
100
100
|
* 3. **Plan**: {@link planMigration} chooses graph-walk vs synth per
|
|
101
|
-
*
|
|
101
|
+
* space according to `callerPolicy.ignoreGraphFor`. The app space
|
|
102
102
|
* is forced through synth (today's daily-driver behaviour); every
|
|
103
|
-
* extension
|
|
103
|
+
* extension space walks its on-disk graph.
|
|
104
104
|
* 4. **Apply** (when `mode === 'apply'`): every per-space `MigrationPlan`
|
|
105
105
|
* feeds into the runner's `execute` — one outer
|
|
106
106
|
* transaction across every space; failure on any space rolls back
|
|
@@ -200,7 +200,7 @@ export async function executeRun<TFamilyId extends string, TTargetId extends str
|
|
|
200
200
|
const appResolution = orderedResolutions.find((r) => r.spaceId === aggregate.app.spaceId);
|
|
201
201
|
if (!appResolution) {
|
|
202
202
|
throw new Error(
|
|
203
|
-
'Aggregate planner returned no plan for the app
|
|
203
|
+
'Aggregate planner returned no plan for the app space — the planner is supposed to always emit one.',
|
|
204
204
|
);
|
|
205
205
|
}
|
|
206
206
|
const appPlan = appResolution.entry.plan;
|
|
@@ -280,14 +280,14 @@ function aggregatePlannerWarnings(
|
|
|
280
280
|
|
|
281
281
|
/**
|
|
282
282
|
* Compare the live `_prisma_marker` rows against the aggregate's
|
|
283
|
-
* declared
|
|
283
|
+
* declared contract spaces. Any marker row whose `space` is not a space of
|
|
284
284
|
* the aggregate is an "orphan" — typically a marker left behind by
|
|
285
285
|
* an extension that was removed from `extensionPacks` without first
|
|
286
286
|
* cleaning up its on-disk migrations / database tables.
|
|
287
287
|
*
|
|
288
288
|
* Returns a {@link CliStructuredError} envelope (code `5002`,
|
|
289
289
|
* `kind: 'orphanMarker'`) for the first orphan it finds, or `null`
|
|
290
|
-
* when every marker row maps to a declared
|
|
290
|
+
* when every marker row maps to a declared contract space. Mirrors the M2
|
|
291
291
|
* `runContractSpaceVerifierMarkerCheck` envelope so downstream
|
|
292
292
|
* tooling (integration tests, JSON consumers) keeps asserting on the
|
|
293
293
|
* same shape.
|
|
@@ -296,13 +296,13 @@ function detectOrphanMarkers(
|
|
|
296
296
|
aggregate: ContractSpaceAggregate,
|
|
297
297
|
markerRows: ReadonlyMap<string, unknown>,
|
|
298
298
|
): CliStructuredError | null {
|
|
299
|
-
const
|
|
299
|
+
const aggregateSpaceIds = new Set<string>([
|
|
300
300
|
aggregate.app.spaceId,
|
|
301
301
|
...aggregate.extensions.map((m) => m.spaceId),
|
|
302
302
|
]);
|
|
303
303
|
const orphans: string[] = [];
|
|
304
304
|
for (const [spaceId, row] of markerRows) {
|
|
305
|
-
if (row !== null && row !== undefined && !
|
|
305
|
+
if (row !== null && row !== undefined && !aggregateSpaceIds.has(spaceId)) {
|
|
306
306
|
orphans.push(spaceId);
|
|
307
307
|
}
|
|
308
308
|
}
|
|
@@ -7,13 +7,13 @@ import type {
|
|
|
7
7
|
VerifyDatabaseSchemaResult,
|
|
8
8
|
} from '@prisma-next/framework-components/control';
|
|
9
9
|
import {
|
|
10
|
-
type
|
|
10
|
+
type AggregateContractSpace,
|
|
11
11
|
collectAggregateNamespaces,
|
|
12
12
|
requireHeadRef,
|
|
13
13
|
type VerifierOutput,
|
|
14
14
|
verifyMigration,
|
|
15
15
|
} from '@prisma-next/migration-tools/aggregate';
|
|
16
|
-
import {
|
|
16
|
+
import { castAs } from '@prisma-next/utils/casts';
|
|
17
17
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
18
18
|
import { CliStructuredError } from '../../utils/cli-errors';
|
|
19
19
|
import {
|
|
@@ -37,9 +37,9 @@ const SPAN_IDS = {
|
|
|
37
37
|
*
|
|
38
38
|
* Loader → verifier pipeline. The loader (sole descriptor-import
|
|
39
39
|
* boundary) builds a {@link import('@prisma-next/migration-tools/aggregate').ContractSpaceAggregate};
|
|
40
|
-
* the aggregate verifier bundles `markerCheck` + per-space
|
|
41
|
-
*
|
|
42
|
-
* facing `--strict` flag.
|
|
40
|
+
* the aggregate verifier bundles `markerCheck` + per-space `schemaCheck`
|
|
41
|
+
* (each contract space verified against the full schema; extras stripped to its own view).
|
|
42
|
+
* `mode: 'strict' | 'lenient'` maps directly to the user facing `--strict` flag.
|
|
43
43
|
*/
|
|
44
44
|
export interface ExecuteDbVerifyOptions<TFamilyId extends string, TTargetId extends string> {
|
|
45
45
|
readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;
|
|
@@ -63,13 +63,19 @@ export interface ExecuteDbVerifyOptions<TFamilyId extends string, TTargetId exte
|
|
|
63
63
|
* emitted, so downstream tooling and integration tests assert on the
|
|
64
64
|
* same shape).
|
|
65
65
|
*
|
|
66
|
-
* On success, the per-space
|
|
66
|
+
* On success, the per-space verify results are returned for the CLI to
|
|
67
67
|
* render. When `skipSchema` is true (`--marker-only`), the schema map
|
|
68
68
|
* is empty.
|
|
69
69
|
*/
|
|
70
70
|
export interface ExecuteDbVerifySuccess {
|
|
71
71
|
readonly schemaResults: ReadonlyMap<string, VerifyDatabaseSchemaResult>;
|
|
72
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Live element names no contract space declares, deduplicated and reported
|
|
74
|
+
* once for the whole database (never per space). Strict mode fails on a
|
|
75
|
+
* non-empty list; lenient mode surfaces it informationally.
|
|
76
|
+
*/
|
|
77
|
+
readonly unclaimed: readonly string[];
|
|
78
|
+
readonly spaceOrder: readonly string[];
|
|
73
79
|
readonly appSpaceId: string;
|
|
74
80
|
}
|
|
75
81
|
|
|
@@ -85,11 +91,11 @@ export type ExecuteDbVerifyResult = Result<ExecuteDbVerifySuccess, CliStructured
|
|
|
85
91
|
* structured CLI error.
|
|
86
92
|
* 2. **Read DB state**: marker rows + (when `skipSchema` is `false`)
|
|
87
93
|
* schema introspection.
|
|
88
|
-
* 3. **Verify**: {@link verifyMigration} returns per-space
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* callers (CLI command) can render
|
|
92
|
-
* returned to the caller verbatim.
|
|
94
|
+
* 3. **Verify**: {@link verifyMigration} returns per-space `markerCheck` +
|
|
95
|
+
* per-space `schemaCheck` (each contract space verified against the full schema,
|
|
96
|
+
* then scoped to its own contract space). Marker mismatches map to
|
|
97
|
+
* `CliStructuredError` (code `5002`) so callers (CLI command) can render
|
|
98
|
+
* and exit. Verify results are returned to the caller verbatim.
|
|
93
99
|
*/
|
|
94
100
|
export async function executeDbVerify<TFamilyId extends string, TTargetId extends string>(
|
|
95
101
|
options: ExecuteDbVerifyOptions<TFamilyId, TTargetId>,
|
|
@@ -115,7 +121,7 @@ export async function executeDbVerify<TFamilyId extends string, TTargetId extend
|
|
|
115
121
|
markersBySpaceId,
|
|
116
122
|
schemaIntrospection,
|
|
117
123
|
mode: options.mode,
|
|
118
|
-
|
|
124
|
+
verifySchemaForSpace: createPerSpaceVerifier(options),
|
|
119
125
|
});
|
|
120
126
|
return finaliseVerifyResult({ verifyResult, aggregate, skipMarker, onProgress });
|
|
121
127
|
}
|
|
@@ -166,30 +172,27 @@ async function runIntrospection<TFamilyId extends string, TTargetId extends stri
|
|
|
166
172
|
}
|
|
167
173
|
|
|
168
174
|
/**
|
|
169
|
-
* Build the per-
|
|
175
|
+
* Build the per-space schema callback handed to the aggregate verifier.
|
|
170
176
|
* When `skipSchema` is true the callback short-circuits with a synthetic
|
|
171
177
|
* `ok` result so the verifier still runs the (cheap) schemaCheck loop
|
|
172
178
|
* without invoking the family's verification path.
|
|
173
179
|
*/
|
|
174
|
-
export function
|
|
180
|
+
export function createPerSpaceVerifier<TFamilyId extends string, TTargetId extends string>(
|
|
175
181
|
options: ExecuteDbVerifyOptions<TFamilyId, TTargetId>,
|
|
176
182
|
): (
|
|
177
|
-
|
|
178
|
-
|
|
183
|
+
schema: unknown,
|
|
184
|
+
space: AggregateContractSpace,
|
|
179
185
|
verifyMode: 'strict' | 'lenient',
|
|
180
186
|
) => VerifyDatabaseSchemaResult {
|
|
181
187
|
const { skipSchema, familyInstance, frameworkComponents } = options;
|
|
182
|
-
return (
|
|
183
|
-
if (skipSchema) return buildSkippedSchemaResult(
|
|
188
|
+
return (schema, space, verifyMode) => {
|
|
189
|
+
if (skipSchema) return buildSkippedSchemaResult(space);
|
|
184
190
|
return familyInstance.verifySchema({
|
|
185
|
-
contract:
|
|
186
|
-
//
|
|
187
|
-
//
|
|
188
|
-
// family
|
|
189
|
-
schema
|
|
190
|
-
never,
|
|
191
|
-
'family TSchemaIR is opaque to migration-tools; projectedSchema is passed straight through'
|
|
192
|
-
>(projectedSchema),
|
|
191
|
+
contract: space.contract(),
|
|
192
|
+
// `familyInstance` is `ControlFamilyInstance<_, unknown>`, so `verifySchema`
|
|
193
|
+
// takes its `TSchemaIR` as `unknown` — the introspected schema passes
|
|
194
|
+
// straight through; the family narrows to its own IR node internally.
|
|
195
|
+
schema,
|
|
193
196
|
strict: verifyMode === 'strict',
|
|
194
197
|
frameworkComponents,
|
|
195
198
|
});
|
|
@@ -223,7 +226,7 @@ function emitVerifySpan(
|
|
|
223
226
|
* by the CLI's `--schema-only` mode.
|
|
224
227
|
*/
|
|
225
228
|
function finaliseVerifyResult(args: {
|
|
226
|
-
verifyResult: VerifierOutput
|
|
229
|
+
verifyResult: VerifierOutput;
|
|
227
230
|
aggregate: {
|
|
228
231
|
readonly app: { readonly spaceId: string };
|
|
229
232
|
readonly extensions: ReadonlyArray<{ readonly spaceId: string }>;
|
|
@@ -253,14 +256,15 @@ function finaliseVerifyResult(args: {
|
|
|
253
256
|
emitVerifySpan(onProgress, 'spanEndOk');
|
|
254
257
|
return ok({
|
|
255
258
|
schemaResults: verifyResult.value.schemaCheck.perSpace,
|
|
256
|
-
|
|
259
|
+
unclaimed: verifyResult.value.schemaCheck.unclaimed,
|
|
260
|
+
spaceOrder: [aggregate.app.spaceId, ...aggregate.extensions.map((e) => e.spaceId)],
|
|
257
261
|
appSpaceId: aggregate.app.spaceId,
|
|
258
262
|
});
|
|
259
263
|
}
|
|
260
264
|
|
|
261
|
-
function buildSkippedSchemaResult(
|
|
262
|
-
const contract =
|
|
263
|
-
const headRef = requireHeadRef(
|
|
265
|
+
function buildSkippedSchemaResult(space: AggregateContractSpace): VerifyDatabaseSchemaResult {
|
|
266
|
+
const contract = space.contract();
|
|
267
|
+
const headRef = requireHeadRef(space);
|
|
264
268
|
const profileHash = castAs<{ profileHash?: string }>(contract).profileHash;
|
|
265
269
|
return {
|
|
266
270
|
ok: true,
|
|
@@ -272,10 +276,11 @@ function buildSkippedSchemaResult(member: ContractSpaceMember): VerifyDatabaseSc
|
|
|
272
276
|
target: { expected: contract.target },
|
|
273
277
|
schema: {
|
|
274
278
|
issues: [],
|
|
279
|
+
schemaDiffIssues: [],
|
|
275
280
|
root: {
|
|
276
281
|
status: 'pass',
|
|
277
282
|
kind: 'skipped',
|
|
278
|
-
name:
|
|
283
|
+
name: space.spaceId,
|
|
279
284
|
contractPath: '',
|
|
280
285
|
code: 'SKIPPED',
|
|
281
286
|
message: 'Schema verification skipped',
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { EOL } from 'node:os';
|
|
3
|
+
import { loadConfig } from '@prisma-next/config-loader';
|
|
3
4
|
import { type FormatOptions, format, PslFormatError } from '@prisma-next/psl-parser/format';
|
|
4
5
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
5
|
-
import { loadConfig } from '../../config-loader';
|
|
6
6
|
import { CliStructuredError, errorRuntime, errorUnexpected } from '../../utils/cli-errors';
|
|
7
7
|
|
|
8
8
|
export interface FormatOperationOptions {
|
|
9
9
|
readonly configPath?: string;
|
|
10
|
-
/** Injected at the CLI boundary so the formatter engine never reads `os`. */
|
|
11
10
|
readonly eol?: string;
|
|
12
11
|
}
|
|
13
12
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Backs the `migrate` command. Strategy: graph-walk-all-
|
|
2
|
+
* Backs the `migrate` command. Strategy: graph-walk-all-spaces, replay-only (no introspect/synth/planner).
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { Contract } from '@prisma-next/contract/types';
|
|
@@ -11,10 +11,10 @@ import type {
|
|
|
11
11
|
TargetMigrationsCapability,
|
|
12
12
|
} from '@prisma-next/framework-components/control';
|
|
13
13
|
import {
|
|
14
|
+
type AggregateContractSpace,
|
|
14
15
|
buildSynthMigrationEdge,
|
|
15
16
|
type ContractMarkerRecordLike,
|
|
16
17
|
type ContractSpaceAggregate,
|
|
17
|
-
type ContractSpaceMember,
|
|
18
18
|
graphWalkStrategy,
|
|
19
19
|
type PerSpacePlan,
|
|
20
20
|
requireHeadRef,
|
|
@@ -62,8 +62,8 @@ export interface ExecuteMigrateOptions<TFamilyId extends string, TTargetId exten
|
|
|
62
62
|
readonly extensionPacks: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
63
63
|
readonly targetId: TTargetId;
|
|
64
64
|
/**
|
|
65
|
-
* Optional app-space ref override. When provided, the app
|
|
66
|
-
* graph-walk targets this hash instead of `
|
|
65
|
+
* Optional app-space ref override. When provided, the app space's
|
|
66
|
+
* graph-walk targets this hash instead of `space.headRef.hash`.
|
|
67
67
|
* Extensions are unaffected — they always walk to their own head.
|
|
68
68
|
*/
|
|
69
69
|
readonly refHash?: string;
|
|
@@ -72,7 +72,7 @@ export interface ExecuteMigrateOptions<TFamilyId extends string, TTargetId exten
|
|
|
72
72
|
* Threaded into the graph-walk's `required` calculation so the
|
|
73
73
|
* planner picks an invariant-bearing path and surfaces the
|
|
74
74
|
* required/satisfied set on the success envelope. When `refHash`
|
|
75
|
-
* is absent the file's `
|
|
75
|
+
* is absent the file's `space.headRef.invariants` are used.
|
|
76
76
|
*/
|
|
77
77
|
readonly refInvariants?: readonly string[];
|
|
78
78
|
/**
|
|
@@ -89,16 +89,16 @@ export interface ExecuteMigrateOptions<TFamilyId extends string, TTargetId exten
|
|
|
89
89
|
/**
|
|
90
90
|
* Apply pending migrations across every contract space (app +
|
|
91
91
|
* extensions). Replay-only: graph-walk against the on-disk graph for
|
|
92
|
-
* every
|
|
92
|
+
* every contract space; no synth, no introspection.
|
|
93
93
|
*
|
|
94
94
|
* Pipeline:
|
|
95
95
|
*
|
|
96
96
|
* 1. Load aggregate from disk (loader hydrates extension graphs;
|
|
97
97
|
* caller provides app-space packages).
|
|
98
98
|
* 2. Read live marker rows per space (`familyInstance.readAllMarkers`).
|
|
99
|
-
* 3. Per
|
|
100
|
-
* marker to `
|
|
101
|
-
*
|
|
99
|
+
* 3. Per space: `graphWalkStrategy` plots the path from the live
|
|
100
|
+
* marker to `space.headRef.hash` (or `refHash` for the app
|
|
101
|
+
* space when provided). Empty-graph spaces fail loudly — a
|
|
102
102
|
* "never planned" space is a user-error condition for replay.
|
|
103
103
|
* 4. Hand off to {@link runMigration} (the runner-driving tail
|
|
104
104
|
* shared with `db init` / `db update`). Marker advancement is
|
|
@@ -140,41 +140,41 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
|
|
|
140
140
|
|
|
141
141
|
const markerRows = await familyInstance.readAllMarkers({ driver });
|
|
142
142
|
|
|
143
|
-
// Plan every
|
|
143
|
+
// Plan every space via graph-walk. App space targets `refHash`
|
|
144
144
|
// when provided, otherwise its own head; extensions always walk
|
|
145
145
|
// to their own head ref.
|
|
146
|
-
const
|
|
146
|
+
const allSpaces: ReadonlyArray<AggregateContractSpace> = [aggregate.app, ...aggregate.extensions];
|
|
147
147
|
const perSpacePlans = new Map<string, PerSpacePlan>();
|
|
148
|
-
// Already-at-head empty-graph
|
|
148
|
+
// Already-at-head empty-graph spaces (typically extensions whose
|
|
149
149
|
// head ref is the empty sentinel, or whose live marker already
|
|
150
150
|
// matches the target). Kept out of the runner schedule so we don't
|
|
151
151
|
// write spurious markers for greenfield extensions, but merged back
|
|
152
|
-
// into the success envelope so every loaded
|
|
152
|
+
// into the success envelope so every loaded space is represented.
|
|
153
153
|
const atHeadResolutions = new Map<string, PerSpacePlan>();
|
|
154
|
-
for (const
|
|
155
|
-
const
|
|
156
|
-
// The aggregate passed the integrity gate, so every
|
|
154
|
+
for (const space of allSpaces) {
|
|
155
|
+
const isAppSpace = space.spaceId === aggregate.app.spaceId;
|
|
156
|
+
// The aggregate passed the integrity gate, so every space's head ref
|
|
157
157
|
// is resolved (the app's is synthesised from the live contract).
|
|
158
|
-
const headRef = requireHeadRef(
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
const liveMarker = markerRows.get(
|
|
158
|
+
const headRef = requireHeadRef(space);
|
|
159
|
+
const spaceTargetHash = isAppSpace && refHash !== undefined ? refHash : headRef.hash;
|
|
160
|
+
const spaceRefInvariants = isAppSpace && refHash !== undefined ? refInvariants : undefined;
|
|
161
|
+
const liveMarker = markerRows.get(space.spaceId) ?? null;
|
|
162
162
|
|
|
163
|
-
const outcome =
|
|
164
|
-
|
|
163
|
+
const outcome = planSpacePath({
|
|
164
|
+
space,
|
|
165
165
|
aggregate,
|
|
166
|
-
targetHash:
|
|
167
|
-
refInvariants:
|
|
166
|
+
targetHash: spaceTargetHash,
|
|
167
|
+
refInvariants: spaceRefInvariants,
|
|
168
168
|
liveMarker,
|
|
169
|
-
...(
|
|
169
|
+
...(isAppSpace ? { refName } : {}),
|
|
170
170
|
});
|
|
171
171
|
|
|
172
172
|
if (outcome.kind === 'at-head') {
|
|
173
|
-
// Empty-graph
|
|
173
|
+
// Empty-graph space whose live marker already matches the target.
|
|
174
174
|
// Kept out of the runner schedule so we don't write spurious markers
|
|
175
175
|
// for greenfield extensions, but merged back into the success envelope
|
|
176
|
-
// so every loaded
|
|
177
|
-
atHeadResolutions.set(
|
|
176
|
+
// so every loaded space is represented.
|
|
177
|
+
atHeadResolutions.set(space.spaceId, outcome.plan);
|
|
178
178
|
continue;
|
|
179
179
|
}
|
|
180
180
|
if (outcome.kind === 'never-planned') {
|
|
@@ -197,9 +197,9 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
|
|
|
197
197
|
// is never a graph node, producing an empty `structuralPath` and
|
|
198
198
|
// a less actionable diagnostic.
|
|
199
199
|
const structural = findPathWithDecision(
|
|
200
|
-
outcome.
|
|
200
|
+
outcome.targetSpace.graph(),
|
|
201
201
|
outcome.liveHash,
|
|
202
|
-
|
|
202
|
+
spaceTargetHash,
|
|
203
203
|
{ required: new Set<string>() },
|
|
204
204
|
);
|
|
205
205
|
const structuralPath =
|
|
@@ -220,14 +220,14 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
|
|
|
220
220
|
});
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
-
perSpacePlans.set(
|
|
223
|
+
perSpacePlans.set(space.spaceId, outcome.plan);
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
const canonicalOrder = [...aggregate.extensions.map((m) => m.spaceId), aggregate.app.spaceId];
|
|
227
227
|
const applyOrder = canonicalOrder.filter((spaceId) => perSpacePlans.has(spaceId));
|
|
228
228
|
|
|
229
229
|
// Short-circuit: nothing pending across any space (no runner-bound
|
|
230
|
-
// plans). Surfaces every loaded
|
|
230
|
+
// plans). Surfaces every loaded space — including at-head empty-
|
|
231
231
|
// graph extensions — in `perSpace[]` so the result reflects the
|
|
232
232
|
// full aggregate, not just the spaces the runner would have touched.
|
|
233
233
|
const totalPlannedOps = sumPlannedOps(applyOrder, perSpacePlans);
|
|
@@ -285,7 +285,7 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
|
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
// Merge at-head zero-op resolutions back into the canonical order
|
|
288
|
-
// so the success envelope surfaces every loaded
|
|
288
|
+
// so the success envelope surfaces every loaded space, not just
|
|
289
289
|
// those the runner executed.
|
|
290
290
|
const orderedAll = canonicalOrder
|
|
291
291
|
.filter((spaceId) => perSpacePlans.has(spaceId) || atHeadResolutions.has(spaceId))
|
|
@@ -321,7 +321,7 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
|
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
/**
|
|
324
|
-
* Outcome variants for one
|
|
324
|
+
* Outcome variants for one space's path computation.
|
|
325
325
|
*
|
|
326
326
|
* Callers switch on `kind` and map to their own error representation:
|
|
327
327
|
* `executeMigrate` throws / returns `notOk`; `executeMigrateShowCommand`
|
|
@@ -330,7 +330,7 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
|
|
|
330
330
|
*
|
|
331
331
|
* @internal Exported for `executeMigrateShowCommand` to call.
|
|
332
332
|
*/
|
|
333
|
-
export type
|
|
333
|
+
export type SpacePathOutcome =
|
|
334
334
|
| { readonly kind: 'ok'; readonly plan: PerSpacePlan }
|
|
335
335
|
| { readonly kind: 'at-head'; readonly plan: PerSpacePlan }
|
|
336
336
|
| { readonly kind: 'never-planned'; readonly spaceId: string; readonly targetHash: string }
|
|
@@ -343,16 +343,16 @@ export type MemberPathOutcome =
|
|
|
343
343
|
| {
|
|
344
344
|
readonly kind: 'unsatisfiable';
|
|
345
345
|
readonly spaceId: string;
|
|
346
|
-
readonly
|
|
346
|
+
readonly isAppSpace: boolean;
|
|
347
347
|
readonly missing: readonly string[];
|
|
348
348
|
readonly targetInvariants: readonly string[];
|
|
349
|
-
readonly
|
|
349
|
+
readonly targetSpace: AggregateContractSpace;
|
|
350
350
|
readonly liveHash: string;
|
|
351
351
|
readonly refName: string | undefined;
|
|
352
352
|
};
|
|
353
353
|
|
|
354
354
|
/**
|
|
355
|
-
* Compute the graph-walk path for one contract
|
|
355
|
+
* Compute the graph-walk path for one contract space.
|
|
356
356
|
*
|
|
357
357
|
* Encapsulates the invariant-correct input assembly that both
|
|
358
358
|
* `executeMigrate` and `executeMigrateShowCommand` must use:
|
|
@@ -361,71 +361,71 @@ export type MemberPathOutcome =
|
|
|
361
361
|
* - `targetInvariants` uses the caller-supplied `refInvariants` when a
|
|
362
362
|
* `--to` ref was resolved (not always the file head ref's invariants).
|
|
363
363
|
*
|
|
364
|
-
* Both callers map the returned `
|
|
364
|
+
* Both callers map the returned `SpacePathOutcome` to their own error
|
|
365
365
|
* representation; the path-compute logic is shared and identical.
|
|
366
366
|
*
|
|
367
367
|
* @internal Exported for `executeMigrateShowCommand`.
|
|
368
368
|
*/
|
|
369
|
-
export function
|
|
370
|
-
|
|
369
|
+
export function planSpacePath({
|
|
370
|
+
space,
|
|
371
371
|
aggregate,
|
|
372
372
|
targetHash,
|
|
373
373
|
refInvariants,
|
|
374
374
|
liveMarker,
|
|
375
375
|
refName,
|
|
376
376
|
}: {
|
|
377
|
-
readonly
|
|
377
|
+
readonly space: AggregateContractSpace;
|
|
378
378
|
readonly aggregate: Pick<ContractSpaceAggregate, 'targetId' | 'app'>;
|
|
379
379
|
readonly targetHash: string;
|
|
380
380
|
readonly refInvariants: readonly string[] | undefined;
|
|
381
381
|
readonly liveMarker: ContractMarkerRecordLike | null;
|
|
382
382
|
readonly refName?: string;
|
|
383
|
-
}):
|
|
384
|
-
const
|
|
385
|
-
const headRef = requireHeadRef(
|
|
383
|
+
}): SpacePathOutcome {
|
|
384
|
+
const isAppSpace = space.spaceId === aggregate.app.spaceId;
|
|
385
|
+
const headRef = requireHeadRef(space);
|
|
386
386
|
|
|
387
|
-
if (
|
|
387
|
+
if (space.graph().nodes.size === 0) {
|
|
388
388
|
const liveHash = liveMarker?.storageHash;
|
|
389
389
|
if (targetHash === liveHash || (liveHash === undefined && targetHash === EMPTY_CONTRACT_HASH)) {
|
|
390
390
|
return {
|
|
391
391
|
kind: 'at-head',
|
|
392
392
|
plan: buildAtHeadResolution({
|
|
393
393
|
aggregateTargetId: aggregate.targetId,
|
|
394
|
-
|
|
394
|
+
space,
|
|
395
395
|
targetHash,
|
|
396
396
|
liveMarker,
|
|
397
397
|
}),
|
|
398
398
|
};
|
|
399
399
|
}
|
|
400
|
-
return { kind: 'never-planned', spaceId:
|
|
400
|
+
return { kind: 'never-planned', spaceId: space.spaceId, targetHash };
|
|
401
401
|
}
|
|
402
402
|
|
|
403
403
|
const targetInvariants =
|
|
404
|
-
|
|
405
|
-
const
|
|
404
|
+
isAppSpace && refInvariants !== undefined ? refInvariants : headRef.invariants;
|
|
405
|
+
const targetSpace: AggregateContractSpace =
|
|
406
406
|
targetHash === headRef.hash && targetInvariants === headRef.invariants
|
|
407
|
-
?
|
|
408
|
-
: { ...
|
|
407
|
+
? space
|
|
408
|
+
: { ...space, headRef: { hash: targetHash, invariants: targetInvariants } };
|
|
409
409
|
|
|
410
410
|
const walked = graphWalkStrategy({
|
|
411
411
|
aggregateTargetId: aggregate.targetId,
|
|
412
|
-
|
|
412
|
+
space: targetSpace,
|
|
413
413
|
currentMarker: liveMarker,
|
|
414
|
-
...(
|
|
414
|
+
...(isAppSpace && refName !== undefined ? { refName } : {}),
|
|
415
415
|
});
|
|
416
416
|
|
|
417
417
|
if (walked.kind === 'unreachable') {
|
|
418
|
-
return { kind: 'unreachable', spaceId:
|
|
418
|
+
return { kind: 'unreachable', spaceId: space.spaceId, liveMarker, targetHash };
|
|
419
419
|
}
|
|
420
420
|
if (walked.kind === 'unsatisfiable') {
|
|
421
421
|
const liveHash = liveMarker?.storageHash ?? EMPTY_CONTRACT_HASH;
|
|
422
422
|
return {
|
|
423
423
|
kind: 'unsatisfiable',
|
|
424
|
-
spaceId:
|
|
425
|
-
|
|
424
|
+
spaceId: space.spaceId,
|
|
425
|
+
isAppSpace,
|
|
426
426
|
missing: walked.missing,
|
|
427
427
|
targetInvariants,
|
|
428
|
-
|
|
428
|
+
targetSpace,
|
|
429
429
|
liveHash,
|
|
430
430
|
refName,
|
|
431
431
|
};
|
|
@@ -435,29 +435,29 @@ export function planMemberPath({
|
|
|
435
435
|
|
|
436
436
|
/**
|
|
437
437
|
* Build a zero-op {@link PerSpacePlan} for an empty-graph
|
|
438
|
-
*
|
|
439
|
-
* pipeline thread the
|
|
438
|
+
* space whose live marker already matches the target. Lets the apply
|
|
439
|
+
* pipeline thread the space through `perSpacePlans` -> `applyOrder`
|
|
440
440
|
* -> the success envelope's `perSpace[]` block so the result reflects
|
|
441
441
|
* every loaded space, even when there is nothing to execute.
|
|
442
442
|
*/
|
|
443
443
|
function buildAtHeadResolution(args: {
|
|
444
444
|
readonly aggregateTargetId: string;
|
|
445
|
-
readonly
|
|
445
|
+
readonly space: AggregateContractSpace;
|
|
446
446
|
readonly targetHash: string;
|
|
447
447
|
readonly liveMarker: ContractMarkerRecordLike | null;
|
|
448
448
|
}): PerSpacePlan {
|
|
449
|
-
const { aggregateTargetId,
|
|
449
|
+
const { aggregateTargetId, space, targetHash, liveMarker } = args;
|
|
450
450
|
return {
|
|
451
451
|
plan: {
|
|
452
452
|
targetId: aggregateTargetId,
|
|
453
|
-
spaceId:
|
|
453
|
+
spaceId: space.spaceId,
|
|
454
454
|
origin: liveMarker === null ? null : { storageHash: liveMarker.storageHash },
|
|
455
455
|
destination: { storageHash: targetHash },
|
|
456
456
|
operations: [],
|
|
457
457
|
providedInvariants: [],
|
|
458
458
|
},
|
|
459
459
|
displayOps: [],
|
|
460
|
-
destinationContract:
|
|
460
|
+
destinationContract: space.contract(),
|
|
461
461
|
strategy: 'graph-walk',
|
|
462
462
|
migrationEdges: [
|
|
463
463
|
buildSynthMigrationEdge({
|
|
@@ -494,7 +494,7 @@ interface BuildSuccessArgs {
|
|
|
494
494
|
}
|
|
495
495
|
|
|
496
496
|
function buildSuccess(args: BuildSuccessArgs): MigrateSuccess {
|
|
497
|
-
// The marker hash surfaced at the top level is the **app
|
|
497
|
+
// The marker hash surfaced at the top level is the **app space's**
|
|
498
498
|
// post-migrate marker (the top-level `markerHash` field).
|
|
499
499
|
// Per-space markers live on `perSpace[].marker.storageHash`.
|
|
500
500
|
const appResolution = args.orderedResolutions.find(
|
|
@@ -586,7 +586,7 @@ export function buildPathNotFoundFailure(
|
|
|
586
586
|
const fromHash = marker?.storageHash ?? '<empty>';
|
|
587
587
|
// The app-case phrasing names the user-visible condition (a
|
|
588
588
|
// contract has been emitted that no on-disk migration reaches) so
|
|
589
|
-
// the error reads naturally for the app
|
|
589
|
+
// the error reads naturally for the app space. Extension spaces
|
|
590
590
|
// see the same condition expressed against the offending space.
|
|
591
591
|
const summary =
|
|
592
592
|
spaceId === 'app'
|
|
@@ -48,7 +48,7 @@ export interface RunMigrationInputs<TFamilyId extends string, TTargetId extends
|
|
|
48
48
|
* {@link planMigration} pipeline (`db init` / `db update` — synth
|
|
49
49
|
* for the app, graph-walk for extensions) or by direct
|
|
50
50
|
* {@link graphWalkStrategy} calls (`migrate` — graph-walk
|
|
51
|
-
* for every
|
|
51
|
+
* for every contract space). Either way, the runner consumes the same shape.
|
|
52
52
|
*/
|
|
53
53
|
readonly perSpacePlans: ReadonlyMap<string, PerSpacePlan>;
|
|
54
54
|
/**
|
|
@@ -229,7 +229,7 @@ export function buildPerSpaceBreakdown(
|
|
|
229
229
|
|
|
230
230
|
/**
|
|
231
231
|
* Materialise the `applyOrder` ordering into resolved per-space
|
|
232
|
-
* entries. Throws if the planner output is missing a
|
|
232
|
+
* entries. Throws if the planner output is missing a contract space listed
|
|
233
233
|
* in `applyOrder` — a wiring bug that should never reach runtime.
|
|
234
234
|
*
|
|
235
235
|
* Exported so callers building their own success envelopes after a
|
package/src/control-api/types.ts
CHANGED
|
@@ -557,9 +557,9 @@ export interface MigrateOptions {
|
|
|
557
557
|
/** Migrations root directory (`migrations/` under the project). */
|
|
558
558
|
readonly migrationsDir: string;
|
|
559
559
|
/**
|
|
560
|
-
* Optional app-space ref override. When provided, the app
|
|
560
|
+
* Optional app-space ref override. When provided, the app space's
|
|
561
561
|
* graph-walk targets this hash instead of `contract.storage.storageHash`.
|
|
562
|
-
* Extension
|
|
562
|
+
* Extension spaces always walk to their own `headRef.hash`.
|
|
563
563
|
*/
|
|
564
564
|
readonly refHash?: string;
|
|
565
565
|
/**
|
|
@@ -631,17 +631,17 @@ export interface MigrateRanEntry {
|
|
|
631
631
|
|
|
632
632
|
/**
|
|
633
633
|
* Successful migrate result. Carries both the top-level fields
|
|
634
|
-
* (`markerHash` is the **app
|
|
634
|
+
* (`markerHash` is the **app space's** post-migrate marker) and the
|
|
635
635
|
* per-space breakdown (`perSpace` — markers / operations in canonical
|
|
636
636
|
* schedule order).
|
|
637
637
|
*/
|
|
638
638
|
/**
|
|
639
|
-
* Path-decision summary for the **app
|
|
639
|
+
* Path-decision summary for the **app space** post-migrate. Surfaced
|
|
640
640
|
* at the top level (and consumed by the cli-journeys suite, which
|
|
641
641
|
* inspects `requiredInvariants`/`satisfiedInvariants`/
|
|
642
642
|
* `selectedPath` to validate invariant routing).
|
|
643
643
|
*
|
|
644
|
-
* Per-space path decisions for extension
|
|
644
|
+
* Per-space path decisions for extension spaces are not surfaced —
|
|
645
645
|
* extensions own their own ref/invariant control.
|
|
646
646
|
*/
|
|
647
647
|
export interface MigratePathDecision {
|
|
@@ -673,7 +673,7 @@ export interface MigrateSuccess {
|
|
|
673
673
|
*/
|
|
674
674
|
readonly perSpace: ReadonlyArray<PerSpaceExecutionEntry>;
|
|
675
675
|
/**
|
|
676
|
-
* Path-decision data for the app
|
|
676
|
+
* Path-decision data for the app space. Present whenever the
|
|
677
677
|
* graph-walk strategy ran for the app (i.e. always for the
|
|
678
678
|
* aggregate-walking migrate path). Absent only for the no-op
|
|
679
679
|
* "Already up to date" early return when the app has no plan.
|
|
@@ -864,7 +864,7 @@ export interface ControlClient {
|
|
|
864
864
|
* markers, and (unless `skipSchema` is true) per-space schema
|
|
865
865
|
* verification with pre-projection (closes F23).
|
|
866
866
|
*
|
|
867
|
-
* @returns Result pattern: per-space
|
|
867
|
+
* @returns Result pattern: per-space verify results on success;
|
|
868
868
|
* structured CLI error on marker / loader failure.
|
|
869
869
|
* @throws If not connected or infrastructure failure
|
|
870
870
|
*/
|
package/src/migration-cli.ts
CHANGED
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
import { readFileSync, realpathSync, writeFileSync } from 'node:fs';
|
|
46
46
|
import type { Writable } from 'node:stream';
|
|
47
47
|
import { fileURLToPath } from 'node:url';
|
|
48
|
+
import { loadConfig } from '@prisma-next/config-loader';
|
|
48
49
|
import {
|
|
49
50
|
CliStructuredError,
|
|
50
51
|
errorMigrationCliInvalidConfigArg,
|
|
@@ -57,7 +58,6 @@ import type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';
|
|
|
57
58
|
import { buildMigrationArtifacts, type Migration } from '@prisma-next/migration-tools/migration';
|
|
58
59
|
import { Cli, Command, Option, UsageError } from 'clipanion';
|
|
59
60
|
import { dirname, join } from 'pathe';
|
|
60
|
-
import { loadConfig } from './config-loader';
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* Constructor shape accepted by `MigrationCLI.run`. `Migration` subclasses
|