prisma-next 0.5.0-dev.74 → 0.5.0-dev.76
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.mjs +8 -8
- package/dist/{client-0ZX24FXF.mjs → client-qVH-rEgd.mjs} +433 -236
- package/dist/client-qVH-rEgd.mjs.map +1 -0
- package/dist/{result-handler-DWb1rFS-.mjs → command-helpers-BeZHkxV8.mjs} +22 -24
- package/dist/command-helpers-BeZHkxV8.mjs.map +1 -0
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +7 -5
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +5 -4
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.mjs +6 -5
- 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 +7 -5
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migration-apply.d.mts +29 -17
- package/dist/commands/migration-apply.d.mts.map +1 -1
- package/dist/commands/migration-apply.mjs +35 -129
- package/dist/commands/migration-apply.mjs.map +1 -1
- package/dist/commands/migration-new.mjs +4 -3
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +19 -1
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +2 -2
- package/dist/commands/migration-ref.d.mts +1 -1
- package/dist/commands/migration-ref.mjs +3 -2
- package/dist/commands/migration-ref.mjs.map +1 -1
- package/dist/commands/migration-show.d.mts +1 -1
- package/dist/commands/migration-show.mjs +5 -4
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +104 -1
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +2 -2
- package/dist/{contract-emit-DkMqO7f2.mjs → contract-emit-9DBda5Ou.mjs} +7 -5
- package/dist/{contract-emit-DkMqO7f2.mjs.map → contract-emit-9DBda5Ou.mjs.map} +1 -1
- package/dist/{contract-emit-B3ChISB_.mjs → contract-emit-B77TsJqf.mjs} +4 -15
- package/dist/{contract-emit-B3ChISB_.mjs.map → contract-emit-B77TsJqf.mjs.map} +1 -1
- package/dist/{contract-enrichment-CF6ogEJ_.mjs → contract-enrichment-Dani0mMW.mjs} +1 -1
- package/dist/{contract-enrichment-CF6ogEJ_.mjs.map → contract-enrichment-Dani0mMW.mjs.map} +1 -1
- package/dist/{contract-infer-BDKAE0B0.mjs → contract-infer-BK9YFGEG.mjs} +5 -4
- package/dist/{contract-infer-BDKAE0B0.mjs.map → contract-infer-BK9YFGEG.mjs.map} +1 -1
- package/dist/{db-verify-B4TdDKOI.mjs → db-verify-C0y1PCO2.mjs} +7 -6
- package/dist/{db-verify-B4TdDKOI.mjs.map → db-verify-C0y1PCO2.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +3 -746
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +3 -3
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/init-output.mjs +1 -1
- 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-gwAHl7ml.mjs → framework-components-ChqVUxR-.mjs} +1 -1
- package/dist/{framework-components-gwAHl7ml.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-Deo7U8_U.mjs → init-CoDVPvQ4.mjs} +4 -4
- package/dist/{init-Deo7U8_U.mjs.map → init-CoDVPvQ4.mjs.map} +1 -1
- package/dist/{inspect-live-schema-BAgQMYpD.mjs → inspect-live-schema-CWYxGKlb.mjs} +4 -4
- package/dist/{inspect-live-schema-BAgQMYpD.mjs.map → inspect-live-schema-CWYxGKlb.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-B8J702Uh.mjs → migration-command-scaffold-B5dORFEv.mjs} +4 -4
- package/dist/{migration-command-scaffold-B8J702Uh.mjs.map → migration-command-scaffold-B5dORFEv.mjs.map} +1 -1
- package/dist/{migration-plan-BcKNnTM7.mjs → migration-plan-C6lVaHsO.mjs} +47 -23
- package/dist/migration-plan-C6lVaHsO.mjs.map +1 -0
- package/dist/{migration-status-CjwB2of-.mjs → migration-status-CZ-D5k7k.mjs} +161 -7
- package/dist/migration-status-CZ-D5k7k.mjs.map +1 -0
- package/dist/{migrations-CIK94AJf.mjs → migrations-D_UJnpuW.mjs} +67 -24
- package/dist/migrations-D_UJnpuW.mjs.map +1 -0
- package/dist/{output-DnjfCC_u.mjs → output-B16Kefzx.mjs} +1 -1
- package/dist/{output-DnjfCC_u.mjs.map → output-B16Kefzx.mjs.map} +1 -1
- package/dist/{progress-adapter-xASh41wr.mjs → progress-adapter-DFfvZcYL.mjs} +1 -1
- package/dist/{progress-adapter-xASh41wr.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-zaRDhJnP.mjs → terminal-ui-C_hFNbAn.mjs} +3 -23
- 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-BEIa9638.mjs → verify-CiwNWM9N.mjs} +2 -2
- package/dist/{verify-BEIa9638.mjs.map → verify-CiwNWM9N.mjs.map} +1 -1
- package/package.json +10 -10
- package/dist/client-0ZX24FXF.mjs.map +0 -1
- package/dist/migration-plan-BcKNnTM7.mjs.map +0 -1
- package/dist/migration-status-CjwB2of-.mjs.map +0 -1
- package/dist/migrations-CIK94AJf.mjs.map +0 -1
- package/dist/result-handler-DWb1rFS-.mjs.map +0 -1
- package/dist/terminal-ui-zaRDhJnP.mjs.map +0 -1
- /package/dist/{cli-errors-QH8kf-C2.d.mts → cli-errors-B9OBbled.d.mts} +0 -0
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { p as errorRunnerFailed, t as CliStructuredError } from "./cli-errors-D3_sMh2K.mjs";
|
|
2
|
-
import { t as assertFrameworkComponentsCompatible } from "./framework-components-
|
|
3
|
-
import { t as enrichContract } from "./contract-enrichment-
|
|
2
|
+
import { t as assertFrameworkComponentsCompatible } from "./framework-components-ChqVUxR-.mjs";
|
|
3
|
+
import { t as enrichContract } from "./contract-enrichment-Dani0mMW.mjs";
|
|
4
|
+
import { n as toExtensionInputs, t as toDeclaredExtensions } from "./extension-pack-inputs-C7xgE-vv.mjs";
|
|
4
5
|
import { emit } from "@prisma-next/emitter";
|
|
5
6
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
6
7
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
7
8
|
import { APP_SPACE_ID, createControlStack, hasMigrations, hasMultiSpaceRunner, hasOperationPreview, hasPslContractInfer, hasSchemaView } from "@prisma-next/framework-components/control";
|
|
8
|
-
import {
|
|
9
|
+
import { findPathWithDecision } from "@prisma-next/migration-tools/migration-graph";
|
|
10
|
+
import { graphWalkStrategy, loadContractSpaceAggregate, planAggregate, verifyAggregate } from "@prisma-next/migration-tools/aggregate";
|
|
9
11
|
import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
|
|
12
|
+
import { errorNoInvariantPath } from "@prisma-next/migration-tools/errors";
|
|
10
13
|
//#region src/control-api/errors.ts
|
|
11
14
|
var ContractValidationError = class extends Error {
|
|
12
15
|
cause;
|
|
@@ -19,38 +22,6 @@ var ContractValidationError = class extends Error {
|
|
|
19
22
|
//#endregion
|
|
20
23
|
//#region src/utils/contract-space-aggregate-loader.ts
|
|
21
24
|
/**
|
|
22
|
-
* Convert the CLI's `Config.extensionPacks` array into the loader's
|
|
23
|
-
* `DeclaredExtensionEntry[]` shape.
|
|
24
|
-
*
|
|
25
|
-
* The loader hashes `contractSpace.contractJson` to compare against the
|
|
26
|
-
* on-disk `refs/head.json.hash` (drift detection). Rather than re-running
|
|
27
|
-
* the canonical-JSON + SHA-256 pipeline at the CLI surface, we look up
|
|
28
|
-
* the descriptor's pre-computed `headRef.hash` via reference identity
|
|
29
|
-
* on the contract JSON value — the loader passes the same
|
|
30
|
-
* `entry.contractSpace.contractJson` reference through to the hasher,
|
|
31
|
-
* so identity-keyed lookup is safe.
|
|
32
|
-
*/
|
|
33
|
-
function toDeclaredExtensions(extensionPacks) {
|
|
34
|
-
const entries = [];
|
|
35
|
-
const hashByContractJson = /* @__PURE__ */ new Map();
|
|
36
|
-
for (const pack of extensionPacks) {
|
|
37
|
-
const entry = pack.contractSpace ? {
|
|
38
|
-
id: pack.id,
|
|
39
|
-
targetId: pack.targetId,
|
|
40
|
-
contractSpace: { contractJson: pack.contractSpace.contractJson }
|
|
41
|
-
} : {
|
|
42
|
-
id: pack.id,
|
|
43
|
-
targetId: pack.targetId
|
|
44
|
-
};
|
|
45
|
-
entries.push(entry);
|
|
46
|
-
if (pack.contractSpace) hashByContractJson.set(pack.contractSpace.contractJson, pack.contractSpace.headRef.hash);
|
|
47
|
-
}
|
|
48
|
-
return {
|
|
49
|
-
entries,
|
|
50
|
-
hashByContractJson
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
25
|
* Render a {@link LoadAggregateError} into a CLI structured-error
|
|
55
26
|
* envelope. Preserves error codes `5001` (layout) and `5002` (marker /
|
|
56
27
|
* drift / disjointness / etc.) so existing integration tests and
|
|
@@ -132,15 +103,18 @@ function mapLoadAggregateError(error) {
|
|
|
132
103
|
* Run the aggregate loader at the CLI surface, mapping any
|
|
133
104
|
* {@link LoadAggregateError} into a {@link CliStructuredError} envelope.
|
|
134
105
|
*
|
|
135
|
-
* App-side migration packages
|
|
136
|
-
* `db init` / `db update`
|
|
137
|
-
* the app member (driven by
|
|
138
|
-
* app's authored `migrations/`
|
|
106
|
+
* App-side migration packages flow through `inputs.appMigrationPackages`
|
|
107
|
+
* (defaulting to `[]`). `db init` / `db update` leave it empty: the
|
|
108
|
+
* planner's `synth` strategy is used for the app member (driven by
|
|
109
|
+
* `callerPolicy.ignoreGraphFor`), so the app's authored `migrations/`
|
|
110
|
+
* graph does not need to be walked. `migration apply` threads the
|
|
111
|
+
* already-loaded app-space packages through so the graph-walk strategy
|
|
112
|
+
* can plot a path through them — replay forbids synth.
|
|
139
113
|
*
|
|
140
114
|
* @see specs/contract-space-aggregate-spec.md § Loader.
|
|
141
115
|
*/
|
|
142
116
|
async function buildContractSpaceAggregate(inputs) {
|
|
143
|
-
const { entries, hashByContractJson } = toDeclaredExtensions(inputs.extensionPacks);
|
|
117
|
+
const { entries, hashByContractJson } = toDeclaredExtensions(toExtensionInputs(inputs.extensionPacks));
|
|
144
118
|
const result = await loadContractSpaceAggregate({
|
|
145
119
|
targetId: inputs.targetId,
|
|
146
120
|
migrationsDir: inputs.migrationsDir,
|
|
@@ -152,12 +126,157 @@ async function buildContractSpaceAggregate(inputs) {
|
|
|
152
126
|
if (precomputed === void 0) throw new Error("CLI aggregate loader: encountered an extension contract without a pre-computed descriptor hash. This is a wiring bug.");
|
|
153
127
|
return precomputed;
|
|
154
128
|
},
|
|
155
|
-
appMigrationPackages: []
|
|
129
|
+
appMigrationPackages: inputs.appMigrationPackages ?? []
|
|
156
130
|
});
|
|
157
131
|
if (!result.ok) return notOk(mapLoadAggregateError(result.failure));
|
|
158
132
|
return ok(result.value.aggregate);
|
|
159
133
|
}
|
|
160
134
|
//#endregion
|
|
135
|
+
//#region src/control-api/operations/apply-aggregate.ts
|
|
136
|
+
/**
|
|
137
|
+
* Span id emitted via `onProgress` for the apply phase. Stable
|
|
138
|
+
* identifier consumed by the structured-output renderer and by tests.
|
|
139
|
+
*/
|
|
140
|
+
const APPLY_SPAN_ID = "apply";
|
|
141
|
+
/**
|
|
142
|
+
* Runner-driving tail shared by every aggregate apply caller — `db init`,
|
|
143
|
+
* `db update`, and `migration apply`. Consumes already-resolved per-space
|
|
144
|
+
* plans (the planner-vs-replay distinction is owned by the caller) and
|
|
145
|
+
* dispatches them to the multi-space runner in canonical order.
|
|
146
|
+
*
|
|
147
|
+
* Marker advancement is part of the runner's per-space transaction
|
|
148
|
+
* (the SQL family runner writes the marker as the last step of each
|
|
149
|
+
* space's transaction), so this primitive does not advance markers
|
|
150
|
+
* separately — by the time `executeAcrossSpaces` returns ok, every
|
|
151
|
+
* space's marker has been advanced to its plan's destination.
|
|
152
|
+
*
|
|
153
|
+
* Span emission (`spanStart 'apply'` / `spanEnd 'apply'`) is owned here
|
|
154
|
+
* so callers don't have to duplicate it; the `action` field on each
|
|
155
|
+
* progress event is taken from the caller's `action` argument.
|
|
156
|
+
*/
|
|
157
|
+
async function applyAggregate(inputs) {
|
|
158
|
+
const { aggregate, perSpacePlans, applyOrder, driver, familyInstance, migrations, frameworkComponents, policy, action, onProgress } = inputs;
|
|
159
|
+
const orderedResolutions = collectOrdered(applyOrder, perSpacePlans);
|
|
160
|
+
const runner = migrations.createRunner(familyInstance);
|
|
161
|
+
if (!hasMultiSpaceRunner(runner)) throw errorRunnerFailed(`Runner for target "${aggregate.targetId}" does not implement \`executeAcrossSpaces\``, { why: `${labelForAction(action)} requires multi-space-capable runners (today: every SQL family runner).` });
|
|
162
|
+
onProgress?.({
|
|
163
|
+
action,
|
|
164
|
+
kind: "spanStart",
|
|
165
|
+
spanId: APPLY_SPAN_ID,
|
|
166
|
+
label: progressLabelForAction(action)
|
|
167
|
+
});
|
|
168
|
+
const perSpaceOptions = orderedResolutions.map((r) => ({
|
|
169
|
+
space: r.spaceId,
|
|
170
|
+
plan: r.entry.plan,
|
|
171
|
+
driver,
|
|
172
|
+
destinationContract: r.entry.destinationContract,
|
|
173
|
+
policy,
|
|
174
|
+
frameworkComponents,
|
|
175
|
+
strictVerification: false
|
|
176
|
+
}));
|
|
177
|
+
const runnerResult = await runner.executeAcrossSpaces({
|
|
178
|
+
driver,
|
|
179
|
+
perSpaceOptions
|
|
180
|
+
});
|
|
181
|
+
if (!runnerResult.ok) {
|
|
182
|
+
onProgress?.({
|
|
183
|
+
action,
|
|
184
|
+
kind: "spanEnd",
|
|
185
|
+
spanId: APPLY_SPAN_ID,
|
|
186
|
+
outcome: "error"
|
|
187
|
+
});
|
|
188
|
+
return notOk({
|
|
189
|
+
summary: runnerResult.failure.summary,
|
|
190
|
+
...ifDefined("why", runnerResult.failure.why),
|
|
191
|
+
meta: {
|
|
192
|
+
...runnerResult.failure.meta ?? {},
|
|
193
|
+
failingSpace: runnerResult.failure.failingSpace
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
onProgress?.({
|
|
198
|
+
action,
|
|
199
|
+
kind: "spanEnd",
|
|
200
|
+
spanId: APPLY_SPAN_ID,
|
|
201
|
+
outcome: "ok"
|
|
202
|
+
});
|
|
203
|
+
return ok({
|
|
204
|
+
orderedResolutions,
|
|
205
|
+
totalOpsPlanned: runnerResult.value.perSpaceResults.reduce((sum, r) => sum + r.value.operationsPlanned, 0),
|
|
206
|
+
totalOpsExecuted: runnerResult.value.perSpaceResults.reduce((sum, r) => sum + r.value.operationsExecuted, 0),
|
|
207
|
+
perSpace: buildPerSpaceBreakdown(orderedResolutions, aggregate.app.spaceId, { includeMarkers: true })
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Project the planner's per-space resolutions into the
|
|
212
|
+
* `AggregatePerSpaceExecutionEntry[]` shape the CLI surfaces.
|
|
213
|
+
*
|
|
214
|
+
* `includeMarkers` is `true` for apply-mode (each space's marker is
|
|
215
|
+
* the `destination.storageHash` of its plan, which the runner
|
|
216
|
+
* advances as the last step of each space's transaction) and `false`
|
|
217
|
+
* for plan-mode (no marker has been written yet).
|
|
218
|
+
*
|
|
219
|
+
* Exported alongside {@link applyAggregate} so plan-mode callers can
|
|
220
|
+
* assemble the same per-space block without going through the runner.
|
|
221
|
+
*/
|
|
222
|
+
function buildPerSpaceBreakdown(orderedResolutions, appSpaceId, options) {
|
|
223
|
+
return orderedResolutions.map((r) => {
|
|
224
|
+
const operations = r.entry.displayOps.map((op) => ({
|
|
225
|
+
id: op.id,
|
|
226
|
+
label: op.label,
|
|
227
|
+
operationClass: op.operationClass
|
|
228
|
+
}));
|
|
229
|
+
const base = {
|
|
230
|
+
spaceId: r.spaceId,
|
|
231
|
+
kind: r.spaceId === appSpaceId ? "app" : "extension",
|
|
232
|
+
operations
|
|
233
|
+
};
|
|
234
|
+
if (!options.includeMarkers) return base;
|
|
235
|
+
return {
|
|
236
|
+
...base,
|
|
237
|
+
marker: { storageHash: r.entry.plan.destination.storageHash }
|
|
238
|
+
};
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Materialise the `applyOrder` ordering into resolved per-space
|
|
243
|
+
* entries. Throws if the planner output is missing a member listed
|
|
244
|
+
* in `applyOrder` — a wiring bug that should never reach runtime.
|
|
245
|
+
*
|
|
246
|
+
* Exported so callers building their own success envelopes after a
|
|
247
|
+
* plan-mode dispatch can replay the same ordering.
|
|
248
|
+
*/
|
|
249
|
+
function collectOrdered(applyOrder, perSpace) {
|
|
250
|
+
return applyOrder.map((spaceId) => {
|
|
251
|
+
const entry = perSpace.get(spaceId);
|
|
252
|
+
if (!entry) throw new Error(`Aggregate planner output missing per-space plan for "${spaceId}"`);
|
|
253
|
+
return {
|
|
254
|
+
spaceId,
|
|
255
|
+
entry
|
|
256
|
+
};
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Action-appropriate label for the `spanStart` event the apply
|
|
261
|
+
* primitive emits. `applyAggregate` is shared by `db init`, `db update`,
|
|
262
|
+
* and `migration apply`; the span label tracks the user-visible action
|
|
263
|
+
* so structured-progress output reads naturally for each surface.
|
|
264
|
+
*/
|
|
265
|
+
function progressLabelForAction(action) {
|
|
266
|
+
switch (action) {
|
|
267
|
+
case "dbInit": return "Initialising database across spaces";
|
|
268
|
+
case "dbUpdate": return "Updating database across spaces";
|
|
269
|
+
case "migrationApply": return "Applying migration plan across spaces";
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function labelForAction(action) {
|
|
273
|
+
switch (action) {
|
|
274
|
+
case "dbInit": return "db init";
|
|
275
|
+
case "dbUpdate": return "db update";
|
|
276
|
+
case "migrationApply": return "migration apply";
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
//#endregion
|
|
161
280
|
//#region src/control-api/operations/migration-helpers.ts
|
|
162
281
|
/**
|
|
163
282
|
* Strips operation objects to their public shape (id, label, operationClass).
|
|
@@ -175,12 +294,13 @@ function stripOperations(operations) {
|
|
|
175
294
|
/**
|
|
176
295
|
* Span IDs emitted via `onProgress` during the aggregate apply flow.
|
|
177
296
|
* Stable identifiers consumed by the structured-output renderer and by
|
|
178
|
-
* tests asserting on span ids.
|
|
297
|
+
* tests asserting on span ids. The `apply` span itself is owned by
|
|
298
|
+
* the {@link applyAggregate} primitive — only the introspect / plan
|
|
299
|
+
* spans are emitted directly here.
|
|
179
300
|
*/
|
|
180
301
|
const SPAN_IDS$1 = {
|
|
181
302
|
introspect: "introspect",
|
|
182
|
-
plan: "plan"
|
|
183
|
-
apply: "apply"
|
|
303
|
+
plan: "plan"
|
|
184
304
|
};
|
|
185
305
|
/**
|
|
186
306
|
* Loader → planner → runner pipeline shared by `db init` and `db update`.
|
|
@@ -268,71 +388,41 @@ async function executeAggregateApply(options) {
|
|
|
268
388
|
if (mode === "plan") {
|
|
269
389
|
const aggregateOps = orderedResolutions.flatMap((r) => r.entry.displayOps);
|
|
270
390
|
const preview = hasOperationPreview(familyInstance) ? familyInstance.toOperationPreview(aggregateOps) : void 0;
|
|
391
|
+
const perSpace = buildPerSpaceBreakdown(orderedResolutions, aggregate.app.spaceId, { includeMarkers: false });
|
|
271
392
|
const summary = `Planned ${aggregateOps.length} operation(s) across ${orderedResolutions.length} space(s)`;
|
|
272
393
|
return wrapPlanResult({
|
|
273
394
|
operations: aggregateOps,
|
|
274
395
|
destination: appPlan.destination,
|
|
275
396
|
preview,
|
|
397
|
+
perSpace,
|
|
276
398
|
summary
|
|
277
399
|
});
|
|
278
400
|
}
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
kind: "spanStart",
|
|
284
|
-
spanId: SPAN_IDS$1.apply,
|
|
285
|
-
label: "Applying migration plan across spaces"
|
|
286
|
-
});
|
|
287
|
-
const perSpaceOptions = orderedResolutions.map((r) => ({
|
|
288
|
-
space: r.spaceId,
|
|
289
|
-
plan: r.entry.plan,
|
|
401
|
+
const applied = await applyAggregate({
|
|
402
|
+
aggregate,
|
|
403
|
+
perSpacePlans: planResult.value.perSpace,
|
|
404
|
+
applyOrder: planResult.value.applyOrder,
|
|
290
405
|
driver,
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
executionChecks: {
|
|
294
|
-
prechecks: false,
|
|
295
|
-
postchecks: false,
|
|
296
|
-
idempotencyChecks: false
|
|
297
|
-
},
|
|
406
|
+
familyInstance,
|
|
407
|
+
migrations,
|
|
298
408
|
frameworkComponents,
|
|
299
|
-
|
|
300
|
-
}));
|
|
301
|
-
const runnerResult = await runner.executeAcrossSpaces({
|
|
302
|
-
driver,
|
|
303
|
-
perSpaceOptions
|
|
304
|
-
});
|
|
305
|
-
if (!runnerResult.ok) {
|
|
306
|
-
onProgress?.({
|
|
307
|
-
action,
|
|
308
|
-
kind: "spanEnd",
|
|
309
|
-
spanId: SPAN_IDS$1.apply,
|
|
310
|
-
outcome: "error"
|
|
311
|
-
});
|
|
312
|
-
return buildRunnerFailure({
|
|
313
|
-
summary: runnerResult.failure.summary,
|
|
314
|
-
...ifDefined("why", runnerResult.failure.why),
|
|
315
|
-
meta: {
|
|
316
|
-
...runnerResult.failure.meta ?? {},
|
|
317
|
-
failingSpace: runnerResult.failure.failingSpace
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
onProgress?.({
|
|
409
|
+
policy,
|
|
322
410
|
action,
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
411
|
+
...ifDefined("onProgress", onProgress)
|
|
412
|
+
});
|
|
413
|
+
if (!applied.ok) return buildRunnerFailure({
|
|
414
|
+
summary: applied.failure.summary,
|
|
415
|
+
...ifDefined("why", applied.failure.why),
|
|
416
|
+
meta: applied.failure.meta
|
|
326
417
|
});
|
|
327
|
-
const
|
|
328
|
-
const
|
|
329
|
-
const aggregateOps = orderedResolutions.flatMap((r) => r.entry.displayOps);
|
|
330
|
-
const summary = action === "dbInit" ? `Applied ${totalOpsExecuted} operation(s) across ${orderedResolutions.length} space(s), database signed` : totalOpsExecuted === 0 ? `Database already matches contract across ${orderedResolutions.length} space(s), signature updated` : `Applied ${totalOpsExecuted} operation(s) across ${orderedResolutions.length} space(s), signature updated`;
|
|
418
|
+
const aggregateOps = applied.value.orderedResolutions.flatMap((r) => r.entry.displayOps);
|
|
419
|
+
const summary = action === "dbInit" ? `Applied ${applied.value.totalOpsExecuted} operation(s) across ${applied.value.orderedResolutions.length} space(s), database signed` : applied.value.totalOpsExecuted === 0 ? `Database already matches contract across ${applied.value.orderedResolutions.length} space(s), signature updated` : `Applied ${applied.value.totalOpsExecuted} operation(s) across ${applied.value.orderedResolutions.length} space(s), signature updated`;
|
|
331
420
|
return wrapApplyResult({
|
|
332
421
|
operations: aggregateOps,
|
|
333
422
|
destination: appPlan.destination,
|
|
334
|
-
operationsPlanned: totalOpsPlanned,
|
|
335
|
-
operationsExecuted: totalOpsExecuted,
|
|
423
|
+
operationsPlanned: applied.value.totalOpsPlanned,
|
|
424
|
+
operationsExecuted: applied.value.totalOpsExecuted,
|
|
425
|
+
perSpace: applied.value.perSpace,
|
|
336
426
|
summary
|
|
337
427
|
});
|
|
338
428
|
}
|
|
@@ -367,16 +457,6 @@ function detectOrphanMarkers(aggregate, markerRows) {
|
|
|
367
457
|
})) }
|
|
368
458
|
});
|
|
369
459
|
}
|
|
370
|
-
function collectOrdered(applyOrder, perSpace) {
|
|
371
|
-
return applyOrder.map((spaceId) => {
|
|
372
|
-
const entry = perSpace.get(spaceId);
|
|
373
|
-
if (!entry) throw new Error(`Aggregate planner output missing per-space plan for "${spaceId}"`);
|
|
374
|
-
return {
|
|
375
|
-
spaceId,
|
|
376
|
-
entry
|
|
377
|
-
};
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
460
|
function mapPlannerError(error) {
|
|
381
461
|
if (error.kind === "appSynthFailure") return notOk({
|
|
382
462
|
code: "PLANNING_FAILED",
|
|
@@ -418,6 +498,7 @@ function wrapPlanResult(args) {
|
|
|
418
498
|
storageHash: args.destination.storageHash,
|
|
419
499
|
...ifDefined("profileHash", args.destination.profileHash)
|
|
420
500
|
},
|
|
501
|
+
perSpace: args.perSpace,
|
|
421
502
|
summary: args.summary
|
|
422
503
|
});
|
|
423
504
|
}
|
|
@@ -437,6 +518,7 @@ function wrapApplyResult(args) {
|
|
|
437
518
|
storageHash: args.destination.storageHash,
|
|
438
519
|
profileHash: args.destination.profileHash
|
|
439
520
|
} : { storageHash: args.destination.storageHash },
|
|
521
|
+
perSpace: args.perSpace,
|
|
440
522
|
summary: args.summary
|
|
441
523
|
});
|
|
442
524
|
}
|
|
@@ -764,150 +846,255 @@ function mapMarkerCheckFailures(appSpaceId, section) {
|
|
|
764
846
|
//#endregion
|
|
765
847
|
//#region src/control-api/operations/migration-apply.ts
|
|
766
848
|
/**
|
|
767
|
-
* Apply
|
|
849
|
+
* Apply pending migrations across every contract space (app +
|
|
850
|
+
* extensions). Replay-only: graph-walk against the on-disk graph for
|
|
851
|
+
* every member; no synth, no introspection.
|
|
852
|
+
*
|
|
853
|
+
* Pipeline:
|
|
768
854
|
*
|
|
769
|
-
*
|
|
770
|
-
*
|
|
771
|
-
*
|
|
855
|
+
* 1. Load aggregate from disk (loader hydrates extension graphs;
|
|
856
|
+
* caller provides app-space packages).
|
|
857
|
+
* 2. Read live marker rows per space (`familyInstance.readAllMarkers`).
|
|
858
|
+
* 3. Per member: `graphWalkStrategy` plots the path from the live
|
|
859
|
+
* marker to `member.headRef.hash` (or `refHash` for the app
|
|
860
|
+
* member when provided). Empty-graph members fail loudly — a
|
|
861
|
+
* "never planned" space is a user-error condition for replay.
|
|
862
|
+
* 4. Hand off to {@link applyAggregate} (the runner-driving tail
|
|
863
|
+
* shared with `db init` / `db update`). Marker advancement is
|
|
864
|
+
* inside the per-space transaction.
|
|
772
865
|
*
|
|
773
|
-
*
|
|
774
|
-
* for upstream verification of the originating migration packages — typically
|
|
775
|
-
* by loading them via `readMigrationPackage` from
|
|
776
|
-
* `@prisma-next/migration-tools/io`, which performs hash-integrity checks at
|
|
777
|
-
* the load boundary. This operation does not re-verify the packages and
|
|
778
|
-
* assumes the `(metadata, ops)` pairs on disk have not been tampered with
|
|
779
|
-
* since emit.
|
|
866
|
+
* Sub-spec § `migration apply` semantics + § Required changes 1.
|
|
780
867
|
*/
|
|
781
868
|
async function executeMigrationApply(options) {
|
|
782
|
-
const { driver, familyInstance,
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
869
|
+
const { driver, familyInstance, contract, migrations, frameworkComponents, migrationsDir, extensionPacks, targetId, appMigrationPackages, refHash, refInvariants, refName, onProgress } = options;
|
|
870
|
+
const loaded = await buildContractSpaceAggregate({
|
|
871
|
+
targetId,
|
|
872
|
+
migrationsDir,
|
|
873
|
+
appContract: contract,
|
|
874
|
+
extensionPacks,
|
|
875
|
+
validateContract: (json) => familyInstance.validateContract(json),
|
|
876
|
+
appMigrationPackages
|
|
877
|
+
});
|
|
878
|
+
if (!loaded.ok) throw loaded.failure;
|
|
879
|
+
const aggregate = loaded.value;
|
|
880
|
+
const markerRows = await familyInstance.readAllMarkers({ driver });
|
|
881
|
+
const allMembers = [aggregate.app, ...aggregate.extensions];
|
|
882
|
+
const perSpacePlans = /* @__PURE__ */ new Map();
|
|
883
|
+
const atHeadResolutions = /* @__PURE__ */ new Map();
|
|
884
|
+
for (const member of allMembers) {
|
|
885
|
+
const isAppMember = member.spaceId === aggregate.app.spaceId;
|
|
886
|
+
const targetHash = isAppMember && refHash !== void 0 ? refHash : member.headRef.hash;
|
|
887
|
+
const liveMarker = markerRows.get(member.spaceId) ?? null;
|
|
888
|
+
if (member.migrations.graph.nodes.size === 0) {
|
|
889
|
+
const liveHash = liveMarker?.storageHash;
|
|
890
|
+
if (targetHash === liveHash || liveHash === void 0 && targetHash === EMPTY_CONTRACT_HASH) {
|
|
891
|
+
atHeadResolutions.set(member.spaceId, buildAtHeadResolution({
|
|
892
|
+
aggregateTargetId: aggregate.targetId,
|
|
893
|
+
member,
|
|
894
|
+
targetHash,
|
|
895
|
+
liveMarker
|
|
896
|
+
}));
|
|
897
|
+
continue;
|
|
791
898
|
}
|
|
792
|
-
|
|
793
|
-
return ok({
|
|
794
|
-
migrationsApplied: 0,
|
|
795
|
-
markerHash: originHash,
|
|
796
|
-
applied: [],
|
|
797
|
-
summary: "Already up to date"
|
|
798
|
-
});
|
|
799
|
-
}
|
|
800
|
-
const firstMigration = pendingMigrations[0];
|
|
801
|
-
const lastMigration = pendingMigrations[pendingMigrations.length - 1];
|
|
802
|
-
const firstFromMarker = firstMigration.from ?? EMPTY_CONTRACT_HASH;
|
|
803
|
-
if (firstFromMarker !== originHash || lastMigration.to !== destinationHash) return notOk({
|
|
804
|
-
code: "MIGRATION_PATH_NOT_FOUND",
|
|
805
|
-
summary: "Migration apply path does not match requested origin and destination",
|
|
806
|
-
why: `Path resolved as ${firstFromMarker} -> ${lastMigration.to}, but requested ${originHash} -> ${destinationHash}`,
|
|
807
|
-
meta: {
|
|
808
|
-
originHash,
|
|
809
|
-
destinationHash,
|
|
810
|
-
pathOrigin: firstFromMarker,
|
|
811
|
-
pathDestination: lastMigration.to
|
|
899
|
+
return notOk(buildNeverPlannedFailure(member.spaceId, targetHash));
|
|
812
900
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
code: "MIGRATION_PATH_NOT_FOUND",
|
|
820
|
-
summary: "Migration apply path contains a discontinuity between adjacent migrations",
|
|
821
|
-
why: `Migration "${previous.dirName}" ends at ${previous.to}, but next migration "${current.dirName}" starts at ${currentFromMarker}`,
|
|
822
|
-
meta: {
|
|
823
|
-
originHash,
|
|
824
|
-
destinationHash,
|
|
825
|
-
previousDirName: previous.dirName,
|
|
826
|
-
previousTo: previous.to,
|
|
827
|
-
currentDirName: current.dirName,
|
|
828
|
-
currentFrom: currentFromMarker,
|
|
829
|
-
discontinuityIndex: i
|
|
901
|
+
const targetInvariants = isAppMember && refHash !== void 0 && refInvariants !== void 0 ? refInvariants : member.headRef.invariants;
|
|
902
|
+
const targetMember = targetHash === member.headRef.hash && targetInvariants === member.headRef.invariants ? member : {
|
|
903
|
+
...member,
|
|
904
|
+
headRef: {
|
|
905
|
+
hash: targetHash,
|
|
906
|
+
invariants: targetInvariants
|
|
830
907
|
}
|
|
908
|
+
};
|
|
909
|
+
const walked = graphWalkStrategy({
|
|
910
|
+
aggregateTargetId: aggregate.targetId,
|
|
911
|
+
member: targetMember,
|
|
912
|
+
currentMarker: liveMarker,
|
|
913
|
+
...isAppMember && refName !== void 0 ? { refName } : {}
|
|
831
914
|
});
|
|
915
|
+
if (walked.kind === "unreachable") return notOk(buildPathNotFoundFailure(member.spaceId, liveMarker, targetHash));
|
|
916
|
+
if (walked.kind === "unsatisfiable") {
|
|
917
|
+
const fromHash = liveMarker?.storageHash ?? "";
|
|
918
|
+
const structural = findPathWithDecision(targetMember.migrations.graph, fromHash, targetHash, { required: /* @__PURE__ */ new Set() });
|
|
919
|
+
const structuralPath = structural.kind === "ok" ? structural.decision.selectedPath.map((edge) => ({
|
|
920
|
+
dirName: edge.dirName,
|
|
921
|
+
migrationHash: edge.migrationHash,
|
|
922
|
+
from: edge.from,
|
|
923
|
+
to: edge.to,
|
|
924
|
+
invariants: edge.invariants
|
|
925
|
+
})) : [];
|
|
926
|
+
throw errorNoInvariantPath({
|
|
927
|
+
...isAppMember && refName !== void 0 ? { refName } : {},
|
|
928
|
+
required: targetInvariants,
|
|
929
|
+
missing: walked.missing,
|
|
930
|
+
structuralPath
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
perSpacePlans.set(member.spaceId, walked.result);
|
|
832
934
|
}
|
|
833
|
-
const
|
|
834
|
-
const
|
|
835
|
-
|
|
836
|
-
const
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
935
|
+
const canonicalOrder = [...aggregate.extensions.map((m) => m.spaceId), aggregate.app.spaceId];
|
|
936
|
+
const applyOrder = canonicalOrder.filter((spaceId) => perSpacePlans.has(spaceId));
|
|
937
|
+
if (sumPlannedOps(applyOrder, perSpacePlans) === 0) {
|
|
938
|
+
const ordered = canonicalOrder.filter((spaceId) => perSpacePlans.has(spaceId) || atHeadResolutions.has(spaceId)).map((spaceId) => {
|
|
939
|
+
const entry = perSpacePlans.get(spaceId) ?? atHeadResolutions.get(spaceId);
|
|
940
|
+
if (entry === void 0) throw new Error(`Unreachable: missing per-space plan for "${spaceId}"`);
|
|
941
|
+
return {
|
|
942
|
+
spaceId,
|
|
943
|
+
entry
|
|
944
|
+
};
|
|
842
945
|
});
|
|
843
|
-
const {
|
|
844
|
-
const
|
|
946
|
+
const perSpace = buildPerSpaceBreakdown(ordered, aggregate.app.spaceId, { includeMarkers: true });
|
|
947
|
+
const totalSpaces = ordered.length;
|
|
948
|
+
return ok(buildSuccess({
|
|
949
|
+
aggregate,
|
|
950
|
+
orderedResolutions: ordered,
|
|
951
|
+
perSpace,
|
|
952
|
+
totalOpsExecuted: 0,
|
|
953
|
+
summary: totalSpaces === 0 ? "Already up to date — no contract spaces are loaded" : totalSpaces === 1 ? "Already up to date" : `Already up to date across ${totalSpaces} space(s)`
|
|
954
|
+
}));
|
|
955
|
+
}
|
|
956
|
+
const applied = await applyAggregate({
|
|
957
|
+
aggregate,
|
|
958
|
+
perSpacePlans,
|
|
959
|
+
applyOrder,
|
|
960
|
+
driver,
|
|
961
|
+
familyInstance,
|
|
962
|
+
migrations,
|
|
963
|
+
frameworkComponents,
|
|
964
|
+
policy: { allowedOperationClasses: [
|
|
845
965
|
"additive",
|
|
846
966
|
"widening",
|
|
847
967
|
"destructive",
|
|
848
968
|
"data"
|
|
849
|
-
] }
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
policy,
|
|
864
|
-
executionChecks: {
|
|
865
|
-
prechecks: true,
|
|
866
|
-
postchecks: true,
|
|
867
|
-
idempotencyChecks: true
|
|
868
|
-
},
|
|
869
|
-
frameworkComponents
|
|
870
|
-
});
|
|
871
|
-
if (!runnerResult.ok) {
|
|
872
|
-
onProgress?.({
|
|
873
|
-
action: "migrationApply",
|
|
874
|
-
kind: "spanEnd",
|
|
875
|
-
spanId: migrationSpanId,
|
|
876
|
-
outcome: "error"
|
|
877
|
-
});
|
|
878
|
-
return notOk({
|
|
879
|
-
code: "RUNNER_FAILED",
|
|
880
|
-
summary: runnerResult.failure.summary,
|
|
881
|
-
why: runnerResult.failure.why,
|
|
882
|
-
meta: {
|
|
883
|
-
migration: migration.dirName,
|
|
884
|
-
from: migration.from,
|
|
885
|
-
to: migration.to,
|
|
886
|
-
...runnerResult.failure.meta ?? {}
|
|
887
|
-
}
|
|
888
|
-
});
|
|
969
|
+
] },
|
|
970
|
+
action: "migrationApply",
|
|
971
|
+
...ifDefined("onProgress", onProgress)
|
|
972
|
+
});
|
|
973
|
+
if (!applied.ok) return notOk({
|
|
974
|
+
code: "RUNNER_FAILED",
|
|
975
|
+
summary: applied.failure.summary,
|
|
976
|
+
why: applied.failure.why,
|
|
977
|
+
meta: applied.failure.meta
|
|
978
|
+
});
|
|
979
|
+
const orderedAll = canonicalOrder.filter((spaceId) => perSpacePlans.has(spaceId) || atHeadResolutions.has(spaceId)).map((spaceId) => {
|
|
980
|
+
if (perSpacePlans.has(spaceId)) {
|
|
981
|
+
const fromRunner = applied.value.orderedResolutions.find((r) => r.spaceId === spaceId);
|
|
982
|
+
if (fromRunner !== void 0) return fromRunner;
|
|
889
983
|
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
984
|
+
const entry = atHeadResolutions.get(spaceId);
|
|
985
|
+
if (entry === void 0) throw new Error(`Unreachable: missing per-space plan for "${spaceId}"`);
|
|
986
|
+
return {
|
|
987
|
+
spaceId,
|
|
988
|
+
entry
|
|
989
|
+
};
|
|
990
|
+
});
|
|
991
|
+
const perSpaceAll = buildPerSpaceBreakdown(orderedAll, aggregate.app.spaceId, { includeMarkers: true });
|
|
992
|
+
const summary = `Applied ${applied.value.orderedResolutions.reduce((sum, r) => sum + (r.entry.migrationEdges?.length ?? 0), 0)} migration(s) (${applied.value.totalOpsExecuted} operation(s)) across ${orderedAll.length} contract space(s)`;
|
|
993
|
+
return ok(buildSuccess({
|
|
994
|
+
aggregate,
|
|
995
|
+
orderedResolutions: orderedAll,
|
|
996
|
+
perSpace: perSpaceAll,
|
|
997
|
+
totalOpsExecuted: applied.value.totalOpsExecuted,
|
|
998
|
+
summary
|
|
999
|
+
}));
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Build a zero-op {@link AggregatePerSpacePlan} for an empty-graph
|
|
1003
|
+
* member whose live marker already matches the target. Lets the apply
|
|
1004
|
+
* pipeline thread the member through `perSpacePlans` -> `applyOrder`
|
|
1005
|
+
* -> the success envelope's `perSpace[]` block so the result reflects
|
|
1006
|
+
* every loaded space, even when there is nothing to execute.
|
|
1007
|
+
*/
|
|
1008
|
+
function buildAtHeadResolution(args) {
|
|
1009
|
+
const { aggregateTargetId, member, targetHash, liveMarker } = args;
|
|
1010
|
+
return {
|
|
1011
|
+
plan: {
|
|
1012
|
+
targetId: aggregateTargetId,
|
|
1013
|
+
spaceId: member.spaceId,
|
|
1014
|
+
origin: liveMarker === null ? null : { storageHash: liveMarker.storageHash },
|
|
1015
|
+
destination: { storageHash: targetHash },
|
|
1016
|
+
operations: [],
|
|
1017
|
+
providedInvariants: []
|
|
1018
|
+
},
|
|
1019
|
+
displayOps: [],
|
|
1020
|
+
destinationContract: member.contract,
|
|
1021
|
+
strategy: "graph-walk",
|
|
1022
|
+
migrationEdges: []
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
function sumPlannedOps(applyOrder, perSpacePlans) {
|
|
1026
|
+
let total = 0;
|
|
1027
|
+
for (const spaceId of applyOrder) {
|
|
1028
|
+
const entry = perSpacePlans.get(spaceId);
|
|
1029
|
+
if (!entry) continue;
|
|
1030
|
+
total += entry.plan.operations.length;
|
|
902
1031
|
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1032
|
+
return total;
|
|
1033
|
+
}
|
|
1034
|
+
function buildSuccess(args) {
|
|
1035
|
+
const appResolution = args.orderedResolutions.find((r) => r.spaceId === args.aggregate.app.spaceId);
|
|
1036
|
+
const appMarkerHash = appResolution?.entry.plan.destination.storageHash ?? args.aggregate.app.headRef.hash;
|
|
1037
|
+
const applied = args.orderedResolutions.flatMap((r) => {
|
|
1038
|
+
return (r.entry.migrationEdges ?? []).map((edge) => ({
|
|
1039
|
+
spaceId: r.spaceId,
|
|
1040
|
+
dirName: edge.dirName,
|
|
1041
|
+
migrationHash: edge.migrationHash,
|
|
1042
|
+
from: edge.from,
|
|
1043
|
+
to: edge.to,
|
|
1044
|
+
operationsExecuted: edge.operationCount
|
|
1045
|
+
}));
|
|
1046
|
+
});
|
|
1047
|
+
const appPlan = appResolution?.entry;
|
|
1048
|
+
const pathDecision = appPlan?.pathDecision ? {
|
|
1049
|
+
fromHash: appPlan.pathDecision.fromHash,
|
|
1050
|
+
toHash: appPlan.pathDecision.toHash,
|
|
1051
|
+
alternativeCount: appPlan.pathDecision.alternativeCount,
|
|
1052
|
+
tieBreakReasons: appPlan.pathDecision.tieBreakReasons,
|
|
1053
|
+
...appPlan.pathDecision.refName !== void 0 ? { refName: appPlan.pathDecision.refName } : {},
|
|
1054
|
+
requiredInvariants: appPlan.pathDecision.requiredInvariants ?? [],
|
|
1055
|
+
satisfiedInvariants: appPlan.pathDecision.satisfiedInvariants ?? [],
|
|
1056
|
+
selectedPath: appPlan.pathDecision.selectedPath.map((entry) => ({
|
|
1057
|
+
dirName: entry.dirName,
|
|
1058
|
+
migrationHash: entry.migrationHash,
|
|
1059
|
+
from: entry.from,
|
|
1060
|
+
to: entry.to,
|
|
1061
|
+
invariants: entry.invariants
|
|
1062
|
+
}))
|
|
1063
|
+
} : void 0;
|
|
1064
|
+
return {
|
|
906
1065
|
migrationsApplied: applied.length,
|
|
907
|
-
markerHash:
|
|
1066
|
+
markerHash: appMarkerHash,
|
|
908
1067
|
applied,
|
|
909
|
-
summary:
|
|
910
|
-
|
|
1068
|
+
summary: args.summary,
|
|
1069
|
+
perSpace: args.perSpace,
|
|
1070
|
+
...pathDecision !== void 0 ? { pathDecision } : {}
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
1073
|
+
function buildNeverPlannedFailure(spaceId, targetHash) {
|
|
1074
|
+
return {
|
|
1075
|
+
code: "MIGRATION_PATH_NOT_FOUND",
|
|
1076
|
+
summary: `No on-disk migrations for contract space "${spaceId}"`,
|
|
1077
|
+
why: `migration apply is replay-only: every contract space must have an authored migration graph on disk. Space "${spaceId}" has no migrations under \`migrations/${spaceId}/\` but its head ref targets "${targetHash}". Run \`prisma-next migration plan\` first to materialise the path.`,
|
|
1078
|
+
meta: {
|
|
1079
|
+
spaceId,
|
|
1080
|
+
target: targetHash,
|
|
1081
|
+
kind: "neverPlanned"
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
function buildPathNotFoundFailure(spaceId, marker, targetHash) {
|
|
1086
|
+
const fromHash = marker?.storageHash ?? "<empty>";
|
|
1087
|
+
return {
|
|
1088
|
+
code: "MIGRATION_PATH_NOT_FOUND",
|
|
1089
|
+
summary: spaceId === "app" ? "Current contract has no planned migration path" : `Current contract has no planned migration path for contract space "${spaceId}"`,
|
|
1090
|
+
why: `Cannot reach target "${targetHash}" from current marker "${fromHash}" in space "${spaceId}". The on-disk migration graph for this space does not connect the two states. Run \`prisma-next migration plan\` to materialise the path.`,
|
|
1091
|
+
meta: {
|
|
1092
|
+
spaceId,
|
|
1093
|
+
fromHash,
|
|
1094
|
+
targetHash,
|
|
1095
|
+
kind: "pathUnreachable"
|
|
1096
|
+
}
|
|
1097
|
+
};
|
|
911
1098
|
}
|
|
912
1099
|
//#endregion
|
|
913
1100
|
//#region src/control-api/client.ts
|
|
@@ -1218,16 +1405,26 @@ var ControlClientImpl = class {
|
|
|
1218
1405
|
await this.connectWithProgress(options.connection, "migrationApply", onProgress);
|
|
1219
1406
|
const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
|
|
1220
1407
|
if (!hasMigrations(this.options.target)) throw new Error(`Target "${this.options.target.targetId}" does not support migrations`);
|
|
1408
|
+
let contract;
|
|
1409
|
+
try {
|
|
1410
|
+
contract = familyInstance.validateContract(options.contract);
|
|
1411
|
+
} catch (error) {
|
|
1412
|
+
throw new ContractValidationError(error instanceof Error ? error.message : String(error), error);
|
|
1413
|
+
}
|
|
1221
1414
|
return executeMigrationApply({
|
|
1222
1415
|
driver,
|
|
1223
1416
|
familyInstance,
|
|
1224
|
-
|
|
1225
|
-
destinationHash: options.destinationHash,
|
|
1226
|
-
pendingMigrations: options.pendingMigrations,
|
|
1417
|
+
contract,
|
|
1227
1418
|
migrations: this.options.target.migrations,
|
|
1228
1419
|
frameworkComponents,
|
|
1420
|
+
migrationsDir: options.migrationsDir,
|
|
1421
|
+
extensionPacks: this.options.extensionPacks ?? [],
|
|
1229
1422
|
targetId: this.options.target.targetId,
|
|
1230
|
-
|
|
1423
|
+
appMigrationPackages: options.appMigrationPackages,
|
|
1424
|
+
...ifDefined("refHash", options.refHash),
|
|
1425
|
+
...ifDefined("refInvariants", options.refInvariants),
|
|
1426
|
+
...ifDefined("refName", options.refName),
|
|
1427
|
+
...ifDefined("onProgress", onProgress)
|
|
1231
1428
|
});
|
|
1232
1429
|
}
|
|
1233
1430
|
async introspect(options) {
|
|
@@ -1393,6 +1590,6 @@ var ControlClientImpl = class {
|
|
|
1393
1590
|
}
|
|
1394
1591
|
};
|
|
1395
1592
|
//#endregion
|
|
1396
|
-
export {
|
|
1593
|
+
export { buildContractSpaceAggregate as a, executeDbInit as i, executeDbVerify as n, ContractValidationError as o, executeDbUpdate as r, createControlClient as t };
|
|
1397
1594
|
|
|
1398
|
-
//# sourceMappingURL=client-
|
|
1595
|
+
//# sourceMappingURL=client-qVH-rEgd.mjs.map
|