@prisma-next/cli 0.11.0 → 0.12.0-dev.10
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 +13 -9
- package/dist/cli.mjs +259 -12
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-oXO2WCPD.mjs → client-CDr4o07S.mjs} +88 -63
- package/dist/client-CDr4o07S.mjs.map +1 -0
- package/dist/{command-helpers-BSb0tRC8.mjs → command-helpers-Bbw1GbwL.mjs} +646 -46
- package/dist/command-helpers-Bbw1GbwL.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.d.mts.map +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 +32 -7
- 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 +3 -4
- 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 +12 -10
- 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 +41 -11
- 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 -1
- package/dist/commands/migrate.d.mts +6 -2
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +75 -40
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.d.mts +4 -3
- package/dist/commands/migration-check.d.mts.map +1 -1
- package/dist/commands/migration-check.mjs +1 -280
- package/dist/commands/migration-graph.d.mts +31 -2
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +2 -137
- package/dist/commands/migration-list.d.mts +64 -4
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +143 -56
- package/dist/commands/migration-list.mjs.map +1 -1
- package/dist/commands/migration-log.d.mts +10 -1
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +10 -15
- package/dist/commands/migration-log.mjs.map +1 -1
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +32 -38
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +3 -2
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +4 -55
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +61 -153
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +12 -49
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +86 -82
- package/dist/commands/migration-status.mjs.map +1 -1
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.d.mts.map +1 -1
- package/dist/commands/ref.mjs +38 -10
- package/dist/commands/ref.mjs.map +1 -1
- package/dist/config-loader-B6sJjXTv.mjs.map +1 -1
- package/dist/config-loader.d.mts.map +1 -1
- package/dist/contract-at-errors-BxP-TOMl.mjs +42 -0
- package/dist/contract-at-errors-BxP-TOMl.mjs.map +1 -0
- package/dist/{contract-emit-bcrpT-wD.mjs → contract-emit-D-4jrNve.mjs} +25 -10
- package/dist/contract-emit-D-4jrNve.mjs.map +1 -0
- package/dist/{contract-emit-r4y8Zhf1.mjs → contract-emit-DxcGl4Uq.mjs} +19 -14
- package/dist/contract-emit-DxcGl4Uq.mjs.map +1 -0
- package/dist/{contract-enrichment-Dani0mMW.mjs → contract-enrichment-a0V5Y_mL.mjs} +4 -25
- package/dist/contract-enrichment-a0V5Y_mL.mjs.map +1 -0
- package/dist/{contract-infer-BmySmqVT.mjs → contract-infer-C8J1WMvO.mjs} +4 -5
- package/dist/{contract-infer-BmySmqVT.mjs.map → contract-infer-C8J1WMvO.mjs.map} +1 -1
- package/dist/contract-space-aggregate-loader-DvZwdkrr.mjs +247 -0
- package/dist/contract-space-aggregate-loader-DvZwdkrr.mjs.map +1 -0
- package/dist/{db-verify-BClPs3ph.mjs → db-verify-BeRHwN8M.mjs} +5 -7
- package/dist/{db-verify-BClPs3ph.mjs.map → db-verify-BeRHwN8M.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +3 -3
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +3 -3
- package/dist/exports/index.d.mts.map +1 -1
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.d.mts.map +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/extension-pack-inputs-IDvjRCi3.mjs +62 -0
- package/dist/extension-pack-inputs-IDvjRCi3.mjs.map +1 -0
- package/dist/{framework-components-65gOHkHB.mjs → framework-components-fYXjz_in.mjs} +2 -2
- package/dist/{framework-components-65gOHkHB.mjs.map → framework-components-fYXjz_in.mjs.map} +1 -1
- package/dist/global-flags-DEHjV8_s.d.mts +34 -0
- package/dist/global-flags-DEHjV8_s.d.mts.map +1 -0
- package/dist/{graph-render-DJVv0_uf.mjs → graph-render-rFAqZujX.mjs} +2 -2
- package/dist/{graph-render-DJVv0_uf.mjs.map → graph-render-rFAqZujX.mjs.map} +1 -1
- package/dist/{init-BCJZPWE1.mjs → init-Cv9UzWL5.mjs} +20 -269
- package/dist/init-Cv9UzWL5.mjs.map +1 -0
- package/dist/{inspect-live-schema-DSRbFoOL.mjs → inspect-live-schema-BlKR2Zln.mjs} +4 -5
- package/dist/{inspect-live-schema-DSRbFoOL.mjs.map → inspect-live-schema-BlKR2Zln.mjs.map} +1 -1
- package/dist/migration-check-BiBJoYYW.mjs +341 -0
- package/dist/migration-check-BiBJoYYW.mjs.map +1 -0
- package/dist/migration-cli.d.mts.map +1 -1
- package/dist/migration-cli.mjs +4 -4
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-Bzd9La5c.mjs → migration-command-scaffold-BAGUiGOK.mjs} +4 -5
- package/dist/{migration-command-scaffold-Bzd9La5c.mjs.map → migration-command-scaffold-BAGUiGOK.mjs.map} +1 -1
- package/dist/migration-graph-C9WC-7eO.mjs +1478 -0
- package/dist/migration-graph-C9WC-7eO.mjs.map +1 -0
- package/dist/migration-list-styler-BRwF4-gy.mjs +399 -0
- package/dist/migration-list-styler-BRwF4-gy.mjs.map +1 -0
- package/dist/{migration-plan-CFwqw3Gk.mjs → migration-plan-9DJ7q7_z.mjs} +372 -133
- package/dist/migration-plan-9DJ7q7_z.mjs.map +1 -0
- package/dist/{migration-types-BXWvz12q.d.mts → migration-types-D2FW63pr.d.mts} +1 -1
- package/dist/{migration-types-BXWvz12q.d.mts.map → migration-types-D2FW63pr.d.mts.map} +1 -1
- package/dist/{migrations-CwZMa1Ck.mjs → migrations-Cv2jxNNK.mjs} +12 -13
- package/dist/migrations-Cv2jxNNK.mjs.map +1 -0
- package/dist/{output-BlsrGMEF.mjs → output-B60Gw5fu.mjs} +1 -1
- package/dist/{output-BlsrGMEF.mjs.map → output-B60Gw5fu.mjs.map} +1 -1
- package/dist/{progress-adapter-DFfvZcYL.mjs → progress-adapter-C644QK8l.mjs} +1 -1
- package/dist/{progress-adapter-DFfvZcYL.mjs.map → progress-adapter-C644QK8l.mjs.map} +1 -1
- package/dist/ref-advancement-DUZqsue6.mjs +50 -0
- package/dist/ref-advancement-DUZqsue6.mjs.map +1 -0
- package/dist/terminal-ui-5Y6mrg93.d.mts +133 -0
- package/dist/terminal-ui-5Y6mrg93.d.mts.map +1 -0
- package/dist/{types--CqjMdk0.d.mts → types-CeC5ec2Y.d.mts} +35 -29
- package/dist/types-CeC5ec2Y.d.mts.map +1 -0
- package/dist/{verify-Bom75OYI.mjs → verify-DCA9Sldu.mjs} +2 -2
- package/dist/{verify-Bom75OYI.mjs.map → verify-DCA9Sldu.mjs.map} +1 -1
- package/package.json +35 -24
- package/src/commands/contract-emit.ts +19 -7
- package/src/commands/contract-infer.ts +1 -1
- package/src/commands/db-init.ts +48 -2
- package/src/commands/db-sign.ts +9 -5
- package/src/commands/db-update.ts +54 -8
- package/src/commands/init/hygiene-gitattributes.ts +2 -2
- package/src/commands/init/index.ts +2 -1
- package/src/commands/init/templates/code-templates.ts +4 -2
- package/src/commands/init/templates/env.ts +13 -14
- package/src/commands/migrate.ts +125 -44
- package/src/commands/migration-check.ts +43 -83
- package/src/commands/migration-graph.ts +116 -60
- package/src/commands/migration-list.ts +220 -74
- package/src/commands/migration-log.ts +8 -14
- package/src/commands/migration-new.ts +44 -48
- package/src/commands/migration-plan.ts +412 -197
- package/src/commands/migration-show.ts +65 -284
- package/src/commands/migration-status.ts +128 -125
- package/src/commands/ref.ts +53 -8
- package/src/control-api/client.ts +11 -2
- package/src/control-api/contract-enrichment.ts +6 -42
- package/src/control-api/operations/{apply-aggregate.ts → apply.ts} +45 -75
- package/src/control-api/operations/contract-emit.ts +14 -6
- package/src/control-api/operations/{db-apply-aggregate.ts → db-apply.ts} +19 -19
- package/src/control-api/operations/db-init.ts +4 -4
- package/src/control-api/operations/db-update.ts +4 -4
- package/src/control-api/operations/db-verify.ts +15 -11
- package/src/control-api/operations/migration-apply.ts +66 -50
- package/src/control-api/types.ts +38 -28
- package/src/migration-cli.ts +4 -4
- package/src/utils/cli-errors.ts +234 -0
- package/src/utils/command-helpers.ts +9 -24
- package/src/utils/contract-at-errors.ts +96 -0
- package/src/utils/contract-space-aggregate-loader.ts +336 -117
- package/src/utils/formatters/migration-graph-lane-colors.ts +31 -0
- package/src/utils/formatters/migration-graph-layout.ts +1141 -0
- package/src/utils/formatters/migration-graph-rows.ts +336 -0
- package/src/utils/formatters/migration-graph-tree-render.ts +768 -0
- package/src/utils/formatters/migration-list-data-column.ts +115 -0
- package/src/utils/formatters/migration-list-graph-topology.ts +368 -0
- package/src/utils/formatters/migration-list-render.ts +191 -0
- package/src/utils/formatters/migration-list-styler.ts +63 -0
- package/src/utils/formatters/migration-list-types.ts +21 -0
- package/src/utils/formatters/migrations.ts +37 -46
- package/src/utils/glyph-mode.ts +22 -0
- package/src/utils/integrity-violation-to-check-failure.ts +130 -0
- package/src/utils/plan-resolution.ts +258 -0
- package/src/utils/ref-advancement.ts +68 -0
- package/src/utils/terminal-ui.ts +42 -1
- package/dist/cli-errors-Czmx92Zy.d.mts +0 -3
- package/dist/cli-errors-Djtz98Vm.mjs +0 -71
- package/dist/cli-errors-Djtz98Vm.mjs.map +0 -1
- package/dist/client-oXO2WCPD.mjs.map +0 -1
- package/dist/command-helpers-BSb0tRC8.mjs.map +0 -1
- package/dist/commands/migration-check.mjs.map +0 -1
- package/dist/commands/migration-graph.mjs.map +0 -1
- package/dist/contract-emit-bcrpT-wD.mjs.map +0 -1
- package/dist/contract-emit-r4y8Zhf1.mjs.map +0 -1
- package/dist/contract-enrichment-Dani0mMW.mjs.map +0 -1
- package/dist/contract-space-aggregate-loader-BmNQwlws.mjs +0 -160
- package/dist/contract-space-aggregate-loader-BmNQwlws.mjs.map +0 -1
- package/dist/global-flags-CdE7M0d9.d.mts +0 -15
- package/dist/global-flags-CdE7M0d9.d.mts.map +0 -1
- package/dist/init-BCJZPWE1.mjs.map +0 -1
- package/dist/migration-plan-CFwqw3Gk.mjs.map +0 -1
- package/dist/migrations-CwZMa1Ck.mjs.map +0 -1
- package/dist/rolldown-runtime-twds-ZHy.mjs +0 -14
- package/dist/terminal-ui-BiB_8KNo.mjs +0 -379
- package/dist/terminal-ui-BiB_8KNo.mjs.map +0 -1
- package/dist/types--CqjMdk0.d.mts.map +0 -1
|
@@ -7,16 +7,17 @@ import type {
|
|
|
7
7
|
TargetMigrationsCapability,
|
|
8
8
|
} from '@prisma-next/framework-components/control';
|
|
9
9
|
import {
|
|
10
|
-
|
|
10
|
+
buildSynthMigrationEdge,
|
|
11
11
|
type ContractMarkerRecordLike,
|
|
12
12
|
type ContractSpaceAggregate,
|
|
13
13
|
type ContractSpaceMember,
|
|
14
14
|
graphWalkStrategy,
|
|
15
|
+
type PerSpacePlan,
|
|
16
|
+
requireHeadRef,
|
|
15
17
|
} from '@prisma-next/migration-tools/aggregate';
|
|
16
18
|
import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
|
|
17
19
|
import { errorNoInvariantPath } from '@prisma-next/migration-tools/errors';
|
|
18
20
|
import { findPathWithDecision } from '@prisma-next/migration-tools/migration-graph';
|
|
19
|
-
import type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';
|
|
20
21
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
21
22
|
import { notOk, ok } from '@prisma-next/utils/result';
|
|
22
23
|
import {
|
|
@@ -24,14 +25,14 @@ import {
|
|
|
24
25
|
buildContractSpaceAggregate,
|
|
25
26
|
} from '../../utils/contract-space-aggregate-loader';
|
|
26
27
|
import type {
|
|
27
|
-
AggregatePerSpaceExecutionEntry,
|
|
28
28
|
MigrationApplyFailure,
|
|
29
29
|
MigrationApplyPathDecision,
|
|
30
30
|
MigrationApplyResult,
|
|
31
31
|
MigrationApplySuccess,
|
|
32
32
|
OnControlProgress,
|
|
33
|
+
PerSpaceExecutionEntry,
|
|
33
34
|
} from '../types';
|
|
34
|
-
import {
|
|
35
|
+
import { applyMigration, buildPerSpaceBreakdown } from './apply';
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
38
|
* Inputs for the aggregate-walking `migrate` control-api
|
|
@@ -56,21 +57,10 @@ export interface ExecuteMigrationApplyOptions<TFamilyId extends string, TTargetI
|
|
|
56
57
|
readonly migrationsDir: string;
|
|
57
58
|
readonly extensionPacks: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
58
59
|
readonly targetId: TTargetId;
|
|
59
|
-
/**
|
|
60
|
-
* Already-loaded app-space migration packages. The CLI command
|
|
61
|
-
* loads these via `loadMigrationPackages(appMigrationsDir)`; the
|
|
62
|
-
* operation hydrates the app member's graph with them. Required
|
|
63
|
-
* because the framework-neutral aggregate loader doesn't know how
|
|
64
|
-
* to read the user's `migrations/` directory layout (it's family-
|
|
65
|
-
* aware: ops.json shape, manifest keys, etc.).
|
|
66
|
-
*/
|
|
67
|
-
readonly appMigrationPackages: ReadonlyArray<OnDiskMigrationPackage>;
|
|
68
60
|
/**
|
|
69
61
|
* Optional app-space ref override. When provided, the app member's
|
|
70
62
|
* graph-walk targets this hash instead of `member.headRef.hash`.
|
|
71
63
|
* Extensions are unaffected — they always walk to their own head.
|
|
72
|
-
*
|
|
73
|
-
* Sub-spec § `--ref <hash>` semantics under multi-space.
|
|
74
64
|
*/
|
|
75
65
|
readonly refHash?: string;
|
|
76
66
|
/**
|
|
@@ -106,7 +96,7 @@ export interface ExecuteMigrationApplyOptions<TFamilyId extends string, TTargetI
|
|
|
106
96
|
* marker to `member.headRef.hash` (or `refHash` for the app
|
|
107
97
|
* member when provided). Empty-graph members fail loudly — a
|
|
108
98
|
* "never planned" space is a user-error condition for replay.
|
|
109
|
-
* 4. Hand off to {@link
|
|
99
|
+
* 4. Hand off to {@link applyMigration} (the runner-driving tail
|
|
110
100
|
* shared with `db init` / `db update`). Marker advancement is
|
|
111
101
|
* inside the per-space transaction.
|
|
112
102
|
*
|
|
@@ -125,7 +115,6 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
|
|
|
125
115
|
migrationsDir,
|
|
126
116
|
extensionPacks,
|
|
127
117
|
targetId,
|
|
128
|
-
appMigrationPackages,
|
|
129
118
|
refHash,
|
|
130
119
|
refInvariants,
|
|
131
120
|
refName,
|
|
@@ -138,7 +127,6 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
|
|
|
138
127
|
appContract: contract,
|
|
139
128
|
extensionPacks,
|
|
140
129
|
deserializeContract: (json) => familyInstance.deserializeContract(json),
|
|
141
|
-
appMigrationPackages,
|
|
142
130
|
};
|
|
143
131
|
const loaded = await buildContractSpaceAggregate(loadInputs);
|
|
144
132
|
if (!loaded.ok) {
|
|
@@ -152,21 +140,24 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
|
|
|
152
140
|
// when provided, otherwise its own head; extensions always walk
|
|
153
141
|
// to their own head ref.
|
|
154
142
|
const allMembers: ReadonlyArray<ContractSpaceMember> = [aggregate.app, ...aggregate.extensions];
|
|
155
|
-
const perSpacePlans = new Map<string,
|
|
143
|
+
const perSpacePlans = new Map<string, PerSpacePlan>();
|
|
156
144
|
// Already-at-head empty-graph members (typically extensions whose
|
|
157
145
|
// head ref is the empty sentinel, or whose live marker already
|
|
158
146
|
// matches the target). Kept out of the runner schedule so we don't
|
|
159
147
|
// write spurious markers for greenfield extensions, but merged back
|
|
160
148
|
// into the success envelope so every loaded member is represented.
|
|
161
|
-
const atHeadResolutions = new Map<string,
|
|
149
|
+
const atHeadResolutions = new Map<string, PerSpacePlan>();
|
|
162
150
|
for (const member of allMembers) {
|
|
163
151
|
const isAppMember = member.spaceId === aggregate.app.spaceId;
|
|
164
|
-
|
|
152
|
+
// The aggregate passed the integrity gate, so every member's head ref
|
|
153
|
+
// is resolved (the app's is synthesised from the live contract).
|
|
154
|
+
const headRef = requireHeadRef(member);
|
|
155
|
+
const targetHash = isAppMember && refHash !== undefined ? refHash : headRef.hash;
|
|
165
156
|
const liveMarker = markerRows.get(member.spaceId) ?? null;
|
|
166
157
|
|
|
167
158
|
// Empty-graph members fail loudly: replay needs an on-disk path
|
|
168
159
|
// and an empty graph means the user has never planned this space.
|
|
169
|
-
if (member.
|
|
160
|
+
if (member.graph().nodes.size === 0) {
|
|
170
161
|
// Edge case: target == EMPTY (greenfield, nothing to do) or
|
|
171
162
|
// the live marker already matches the target. Loader integrity
|
|
172
163
|
// allows this for extensions whose head ref is the empty
|
|
@@ -197,9 +188,9 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
|
|
|
197
188
|
const targetInvariants =
|
|
198
189
|
isAppMember && refHash !== undefined && refInvariants !== undefined
|
|
199
190
|
? refInvariants
|
|
200
|
-
:
|
|
191
|
+
: headRef.invariants;
|
|
201
192
|
const targetMember: ContractSpaceMember =
|
|
202
|
-
targetHash ===
|
|
193
|
+
targetHash === headRef.hash && targetInvariants === headRef.invariants
|
|
203
194
|
? member
|
|
204
195
|
: { ...member, headRef: { hash: targetHash, invariants: targetInvariants } };
|
|
205
196
|
|
|
@@ -224,7 +215,7 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
|
|
|
224
215
|
// is never a graph node, producing an empty `structuralPath` and
|
|
225
216
|
// a less actionable diagnostic.
|
|
226
217
|
const fromHash = liveMarker?.storageHash ?? EMPTY_CONTRACT_HASH;
|
|
227
|
-
const structural = findPathWithDecision(targetMember.
|
|
218
|
+
const structural = findPathWithDecision(targetMember.graph(), fromHash, targetHash, {
|
|
228
219
|
required: new Set<string>(),
|
|
229
220
|
});
|
|
230
221
|
const structuralPath =
|
|
@@ -286,7 +277,7 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
|
|
|
286
277
|
);
|
|
287
278
|
}
|
|
288
279
|
|
|
289
|
-
const applied = await
|
|
280
|
+
const applied = await applyMigration({
|
|
290
281
|
aggregate,
|
|
291
282
|
perSpacePlans,
|
|
292
283
|
applyOrder,
|
|
@@ -329,7 +320,7 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
|
|
|
329
320
|
includeMarkers: true,
|
|
330
321
|
});
|
|
331
322
|
const totalMigrationsApplied = applied.value.orderedResolutions.reduce(
|
|
332
|
-
(sum, r) => sum +
|
|
323
|
+
(sum, r) => sum + r.entry.migrationEdges.length,
|
|
333
324
|
0,
|
|
334
325
|
);
|
|
335
326
|
const summary = `Applied ${totalMigrationsApplied} migration(s) (${applied.value.totalOpsExecuted} operation(s)) across ${orderedAll.length} contract space(s)`;
|
|
@@ -346,7 +337,7 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
|
|
|
346
337
|
}
|
|
347
338
|
|
|
348
339
|
/**
|
|
349
|
-
* Build a zero-op {@link
|
|
340
|
+
* Build a zero-op {@link PerSpacePlan} for an empty-graph
|
|
350
341
|
* member whose live marker already matches the target. Lets the apply
|
|
351
342
|
* pipeline thread the member through `perSpacePlans` -> `applyOrder`
|
|
352
343
|
* -> the success envelope's `perSpace[]` block so the result reflects
|
|
@@ -357,7 +348,7 @@ function buildAtHeadResolution(args: {
|
|
|
357
348
|
readonly member: ContractSpaceMember;
|
|
358
349
|
readonly targetHash: string;
|
|
359
350
|
readonly liveMarker: ContractMarkerRecordLike | null;
|
|
360
|
-
}):
|
|
351
|
+
}): PerSpacePlan {
|
|
361
352
|
const { aggregateTargetId, member, targetHash, liveMarker } = args;
|
|
362
353
|
return {
|
|
363
354
|
plan: {
|
|
@@ -369,15 +360,21 @@ function buildAtHeadResolution(args: {
|
|
|
369
360
|
providedInvariants: [],
|
|
370
361
|
},
|
|
371
362
|
displayOps: [],
|
|
372
|
-
destinationContract: member.contract,
|
|
363
|
+
destinationContract: member.contract(),
|
|
373
364
|
strategy: 'graph-walk',
|
|
374
|
-
migrationEdges: [
|
|
365
|
+
migrationEdges: [
|
|
366
|
+
buildSynthMigrationEdge({
|
|
367
|
+
currentMarkerStorageHash: liveMarker?.storageHash,
|
|
368
|
+
destinationStorageHash: targetHash,
|
|
369
|
+
operationCount: 0,
|
|
370
|
+
}),
|
|
371
|
+
],
|
|
375
372
|
};
|
|
376
373
|
}
|
|
377
374
|
|
|
378
375
|
function sumPlannedOps(
|
|
379
376
|
applyOrder: readonly string[],
|
|
380
|
-
perSpacePlans: ReadonlyMap<string,
|
|
377
|
+
perSpacePlans: ReadonlyMap<string, PerSpacePlan>,
|
|
381
378
|
): number {
|
|
382
379
|
let total = 0;
|
|
383
380
|
for (const spaceId of applyOrder) {
|
|
@@ -392,30 +389,29 @@ interface BuildSuccessArgs {
|
|
|
392
389
|
readonly aggregate: ContractSpaceAggregate;
|
|
393
390
|
readonly orderedResolutions: ReadonlyArray<{
|
|
394
391
|
readonly spaceId: string;
|
|
395
|
-
readonly entry:
|
|
392
|
+
readonly entry: PerSpacePlan;
|
|
396
393
|
}>;
|
|
397
|
-
readonly perSpace: ReadonlyArray<
|
|
394
|
+
readonly perSpace: ReadonlyArray<PerSpaceExecutionEntry>;
|
|
398
395
|
readonly totalOpsExecuted: number;
|
|
399
396
|
readonly summary: string;
|
|
400
397
|
}
|
|
401
398
|
|
|
402
399
|
function buildSuccess(args: BuildSuccessArgs): MigrationApplySuccess {
|
|
403
400
|
// The marker hash surfaced at the top level is the **app member's**
|
|
404
|
-
// post-apply marker (
|
|
401
|
+
// post-apply marker (the top-level `markerHash` field).
|
|
405
402
|
// Per-space markers live on `perSpace[].marker.storageHash`.
|
|
406
403
|
const appResolution = args.orderedResolutions.find(
|
|
407
404
|
(r) => r.spaceId === args.aggregate.app.spaceId,
|
|
408
405
|
);
|
|
409
406
|
const appMarkerHash =
|
|
410
|
-
appResolution?.entry.plan.destination.storageHash ?? args.aggregate.app.
|
|
407
|
+
appResolution?.entry.plan.destination.storageHash ?? requireHeadRef(args.aggregate.app).hash;
|
|
411
408
|
|
|
412
409
|
// Per-migration entries (one per authored edge) preserve the
|
|
413
|
-
//
|
|
414
|
-
//
|
|
415
|
-
//
|
|
416
|
-
// `perSpace[]`.
|
|
410
|
+
// `migrationsApplied` count semantics for back-compat with existing
|
|
411
|
+
// JSON-shape consumers (e.g. `parsed.applied.length` in integration
|
|
412
|
+
// tests). The aggregate per-space breakdown lives on `perSpace[]`.
|
|
417
413
|
const applied = args.orderedResolutions.flatMap((r) => {
|
|
418
|
-
const edges = r.entry.migrationEdges
|
|
414
|
+
const edges = r.entry.migrationEdges;
|
|
419
415
|
return edges.map((edge) => ({
|
|
420
416
|
spaceId: r.spaceId,
|
|
421
417
|
dirName: edge.dirName,
|
|
@@ -458,26 +454,46 @@ function buildSuccess(args: BuildSuccessArgs): MigrationApplySuccess {
|
|
|
458
454
|
};
|
|
459
455
|
}
|
|
460
456
|
|
|
461
|
-
|
|
457
|
+
/**
|
|
458
|
+
* Build the `neverPlanned` failure raised when a contract space has no on-disk
|
|
459
|
+
* migration graph but migrate was asked to reach a target hash. The `why`
|
|
460
|
+
* states only the condition; the recovery sequence is composed by
|
|
461
|
+
* `errorPathUnreachable`'s `fix`.
|
|
462
|
+
*
|
|
463
|
+
* @internal Exported for testing only.
|
|
464
|
+
*/
|
|
465
|
+
export function buildNeverPlannedFailure(
|
|
466
|
+
spaceId: string,
|
|
467
|
+
targetHash: string,
|
|
468
|
+
): MigrationApplyFailure {
|
|
462
469
|
return {
|
|
463
470
|
code: 'MIGRATION_PATH_NOT_FOUND',
|
|
464
471
|
summary: `No on-disk migrations for contract space "${spaceId}"`,
|
|
465
|
-
why: `migrate 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}"
|
|
472
|
+
why: `migrate 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}".`,
|
|
466
473
|
meta: { spaceId, target: targetHash, kind: 'neverPlanned' },
|
|
467
474
|
};
|
|
468
475
|
}
|
|
469
476
|
|
|
470
|
-
|
|
477
|
+
/**
|
|
478
|
+
* Build the `pathUnreachable` failure raised when an emitted contract has no
|
|
479
|
+
* on-disk migration edge from the current marker to the target. The `why`
|
|
480
|
+
* states only the condition (no edge between the two named states, and migrate
|
|
481
|
+
* replays edges rather than inventing them); the recovery sequence — plan the
|
|
482
|
+
* edge, then re-apply — is composed by `errorPathUnreachable`'s `fix`, so the
|
|
483
|
+
* two read as one non-redundant plan-then-apply story.
|
|
484
|
+
*
|
|
485
|
+
* @internal Exported for testing only.
|
|
486
|
+
*/
|
|
487
|
+
export function buildPathNotFoundFailure(
|
|
471
488
|
spaceId: string,
|
|
472
489
|
marker: ContractMarkerRecordLike | null,
|
|
473
490
|
targetHash: string,
|
|
474
491
|
): MigrationApplyFailure {
|
|
475
492
|
const fromHash = marker?.storageHash ?? '<empty>';
|
|
476
|
-
// The
|
|
477
|
-
//
|
|
478
|
-
//
|
|
479
|
-
//
|
|
480
|
-
// condition expressed against the offending space.
|
|
493
|
+
// The app-case phrasing names the user-visible condition (a
|
|
494
|
+
// contract has been emitted that no on-disk migration reaches) so
|
|
495
|
+
// the error reads naturally for the app member. Extension spaces
|
|
496
|
+
// see the same condition expressed against the offending space.
|
|
481
497
|
const summary =
|
|
482
498
|
spaceId === 'app'
|
|
483
499
|
? 'Current contract has no planned migration path'
|
|
@@ -485,7 +501,7 @@ function buildPathNotFoundFailure(
|
|
|
485
501
|
return {
|
|
486
502
|
code: 'MIGRATION_PATH_NOT_FOUND',
|
|
487
503
|
summary,
|
|
488
|
-
why: `
|
|
504
|
+
why: `No migration edge connects the current state "${fromHash}" to the target "${targetHash}" in contract space "${spaceId}". The on-disk migration graph does not join the two, and migrate replays existing edges — it never invents one.`,
|
|
489
505
|
meta: { spaceId, fromHash, targetHash, kind: 'pathUnreachable' },
|
|
490
506
|
};
|
|
491
507
|
}
|
package/src/control-api/types.ts
CHANGED
|
@@ -2,7 +2,11 @@ import type {
|
|
|
2
2
|
ContractSourceDiagnostics,
|
|
3
3
|
ContractSourceProvider,
|
|
4
4
|
} from '@prisma-next/config/config-types';
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
Contract,
|
|
7
|
+
ContractMarkerRecord,
|
|
8
|
+
LedgerEntryRecord,
|
|
9
|
+
} from '@prisma-next/contract/types';
|
|
6
10
|
import type {
|
|
7
11
|
ControlAdapterDescriptor,
|
|
8
12
|
ControlDriverDescriptor,
|
|
@@ -18,7 +22,6 @@ import type {
|
|
|
18
22
|
VerifyDatabaseSchemaResult,
|
|
19
23
|
} from '@prisma-next/framework-components/control';
|
|
20
24
|
import type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';
|
|
21
|
-
import type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';
|
|
22
25
|
import type { Result } from '@prisma-next/utils/result';
|
|
23
26
|
import type { ExecuteDbVerifyResult } from './operations/db-verify';
|
|
24
27
|
|
|
@@ -246,7 +249,7 @@ export interface DbUpdateOptions {
|
|
|
246
249
|
* Options for the dbVerify operation.
|
|
247
250
|
*
|
|
248
251
|
* Drives the loader → aggregate-verifier pipeline. `strict` maps to
|
|
249
|
-
* `
|
|
252
|
+
* `verifyMigration({ mode: 'strict' | 'lenient' })`; `skipSchema`
|
|
250
253
|
* mirrors the `--marker-only` CLI flag and short-circuits the schema
|
|
251
254
|
* portion of the verifier.
|
|
252
255
|
*/
|
|
@@ -327,7 +330,7 @@ export interface EmitOptions {
|
|
|
327
330
|
* to the user instead of being collapsed into a single ambiguous
|
|
328
331
|
* top-level hash.
|
|
329
332
|
*/
|
|
330
|
-
export interface
|
|
333
|
+
export interface PerSpaceExecutionEntry {
|
|
331
334
|
readonly spaceId: string;
|
|
332
335
|
/** `'app'` for the application's contract space; `'extension'` for any extension space. */
|
|
333
336
|
readonly kind: 'app' | 'extension';
|
|
@@ -388,9 +391,9 @@ export interface DbInitSuccess {
|
|
|
388
391
|
* alphabetically, then app). Present whenever the aggregate flow
|
|
389
392
|
* produced one — both `mode: 'plan'` and `mode: 'apply'`.
|
|
390
393
|
*
|
|
391
|
-
* See {@link
|
|
394
|
+
* See {@link PerSpaceExecutionEntry}.
|
|
392
395
|
*/
|
|
393
|
-
readonly perSpace?: ReadonlyArray<
|
|
396
|
+
readonly perSpace?: ReadonlyArray<PerSpaceExecutionEntry>;
|
|
394
397
|
readonly summary: string;
|
|
395
398
|
}
|
|
396
399
|
|
|
@@ -458,9 +461,9 @@ export interface DbUpdateSuccess {
|
|
|
458
461
|
};
|
|
459
462
|
/**
|
|
460
463
|
* Per-space breakdown in canonical schedule order (extensions
|
|
461
|
-
* alphabetically, then app). See {@link
|
|
464
|
+
* alphabetically, then app). See {@link PerSpaceExecutionEntry}.
|
|
462
465
|
*/
|
|
463
|
-
readonly perSpace?: ReadonlyArray<
|
|
466
|
+
readonly perSpace?: ReadonlyArray<PerSpaceExecutionEntry>;
|
|
464
467
|
readonly summary: string;
|
|
465
468
|
}
|
|
466
469
|
|
|
@@ -539,7 +542,7 @@ export type EmitResult = Result<EmitSuccess, EmitFailure>;
|
|
|
539
542
|
* contract-space aggregate, reading per-space marker rows from the
|
|
540
543
|
* live database, plotting per-space paths via `graphWalkStrategy`
|
|
541
544
|
* (replay-only — no synth, no introspection), and dispatching
|
|
542
|
-
* through the shared `
|
|
545
|
+
* through the shared `applyMigration` primitive. The CLI command
|
|
543
546
|
* just resolves the descriptor surface (config, refs, contract
|
|
544
547
|
* envelope, app-space migration packages) and hands the inputs in.
|
|
545
548
|
*/
|
|
@@ -548,12 +551,6 @@ export interface MigrationApplyOptions {
|
|
|
548
551
|
readonly contract: unknown;
|
|
549
552
|
/** Migrations root directory (`migrations/` under the project). */
|
|
550
553
|
readonly migrationsDir: string;
|
|
551
|
-
/**
|
|
552
|
-
* Already-loaded app-space migration packages. The CLI loads these
|
|
553
|
-
* via `loadMigrationPackages(appMigrationsDir)` before invoking
|
|
554
|
-
* `migrationApply`.
|
|
555
|
-
*/
|
|
556
|
-
readonly appMigrationPackages: ReadonlyArray<OnDiskMigrationPackage>;
|
|
557
554
|
/**
|
|
558
555
|
* Optional app-space ref override. When provided, the app member's
|
|
559
556
|
* graph-walk targets this hash instead of `contract.storage.storageHash`.
|
|
@@ -584,11 +581,11 @@ export interface MigrationApplyOptions {
|
|
|
584
581
|
|
|
585
582
|
/**
|
|
586
583
|
* A single on-disk migration package surfaced to the operation. The
|
|
587
|
-
* SQL family
|
|
588
|
-
* the operation hands it through to the
|
|
589
|
-
* loader's `appMigrationPackages` slot.
|
|
584
|
+
* SQL family surfaces this shape from the tolerant contract-space
|
|
585
|
+
* aggregate's app packages; the operation hands it through to the
|
|
586
|
+
* framework-neutral aggregate loader's `appMigrationPackages` slot.
|
|
590
587
|
*
|
|
591
|
-
* (Originally named `MigrationApplyStep` for the
|
|
588
|
+
* (Originally named `MigrationApplyStep` for the earlier app-only
|
|
592
589
|
* apply path; the name is kept for compatibility with existing CLI
|
|
593
590
|
* callers and tests.)
|
|
594
591
|
*/
|
|
@@ -612,8 +609,8 @@ export interface MigrationApplyStep {
|
|
|
612
609
|
*/
|
|
613
610
|
/**
|
|
614
611
|
* One entry per authored migration package applied. Preserves the
|
|
615
|
-
*
|
|
616
|
-
*
|
|
612
|
+
* `migrationsApplied` count semantics (each entry is one migration
|
|
613
|
+
* directory) so `applied.length === migrationsApplied`.
|
|
617
614
|
*
|
|
618
615
|
* Per-space aggregate detail (markers, ops grouped by space) lives
|
|
619
616
|
* on `perSpace[]`; this list is the per-edge view.
|
|
@@ -628,16 +625,15 @@ export interface MigrationApplyAppliedEntry {
|
|
|
628
625
|
}
|
|
629
626
|
|
|
630
627
|
/**
|
|
631
|
-
* Successful migrationApply result. Carries both the
|
|
632
|
-
*
|
|
633
|
-
* marker, surfaced for back-compat with single-space callers) and the
|
|
628
|
+
* Successful migrationApply result. Carries both the top-level fields
|
|
629
|
+
* (`markerHash` is the **app member's** post-apply marker) and the
|
|
634
630
|
* per-space breakdown (`perSpace` — markers / operations in canonical
|
|
635
631
|
* schedule order).
|
|
636
632
|
*/
|
|
637
633
|
/**
|
|
638
634
|
* Path-decision summary for the **app member** post-apply. Surfaced
|
|
639
|
-
*
|
|
640
|
-
*
|
|
635
|
+
* at the top level (and consumed by the cli-journeys suite, which
|
|
636
|
+
* inspects `requiredInvariants`/`satisfiedInvariants`/
|
|
641
637
|
* `selectedPath` to validate invariant routing).
|
|
642
638
|
*
|
|
643
639
|
* Per-space path decisions for extension members are not surfaced —
|
|
@@ -667,10 +663,10 @@ export interface MigrationApplySuccess {
|
|
|
667
663
|
readonly summary: string;
|
|
668
664
|
/**
|
|
669
665
|
* Per-space breakdown in canonical schedule order (extensions
|
|
670
|
-
* alphabetically, then app). See {@link
|
|
666
|
+
* alphabetically, then app). See {@link PerSpaceExecutionEntry}.
|
|
671
667
|
* Always present for the aggregate-walking operation.
|
|
672
668
|
*/
|
|
673
|
-
readonly perSpace: ReadonlyArray<
|
|
669
|
+
readonly perSpace: ReadonlyArray<PerSpaceExecutionEntry>;
|
|
674
670
|
/**
|
|
675
671
|
* Path-decision data for the app member. Present whenever the
|
|
676
672
|
* graph-walk strategy ran for the app (i.e. always for the
|
|
@@ -719,6 +715,13 @@ export type MigrationApplyResult = Result<MigrationApplySuccess, MigrationApplyF
|
|
|
719
715
|
export interface ContractEmitOptions {
|
|
720
716
|
/** Path to the prisma-next.config.ts file */
|
|
721
717
|
readonly configPath: string;
|
|
718
|
+
/**
|
|
719
|
+
* Directory to write contract artifacts into. When set, `contract.json` and
|
|
720
|
+
* `contract.d.ts` are written inside this directory, taking precedence over
|
|
721
|
+
* any output path from the loaded config. The value must be an absolute path;
|
|
722
|
+
* resolution against cwd is the caller's responsibility.
|
|
723
|
+
*/
|
|
724
|
+
readonly outputPath?: string;
|
|
722
725
|
/** Optional AbortSignal for cancelling the in-flight emit */
|
|
723
726
|
readonly signal?: AbortSignal;
|
|
724
727
|
/** Optional progress callback for observing source-resolution and emit spans */
|
|
@@ -877,6 +880,13 @@ export interface ControlClient {
|
|
|
877
880
|
*/
|
|
878
881
|
readAllMarkers(): Promise<ReadonlyMap<string, ContractMarkerRecord>>;
|
|
879
882
|
|
|
883
|
+
/**
|
|
884
|
+
* Reads the per-migration ledger journal for `space` in apply order.
|
|
885
|
+
* Returns an empty array when the ledger store does not yet exist or
|
|
886
|
+
* has no rows for that space.
|
|
887
|
+
*/
|
|
888
|
+
readLedger(space?: string): Promise<readonly LedgerEntryRecord[]>;
|
|
889
|
+
|
|
880
890
|
/**
|
|
881
891
|
* Applies pre-planned on-disk migrations to the database.
|
|
882
892
|
* Each migration runs in its own transaction with full execution checks.
|
package/src/migration-cli.ts
CHANGED
|
@@ -461,8 +461,8 @@ function writeStructuredError(stream: MigrationCliWritable, err: CliStructuredEr
|
|
|
461
461
|
* `null` when the file is missing and throwing `MIGRATION.INVALID_JSON`
|
|
462
462
|
* when the file is present but cannot be parsed as JSON. The CLI feeds
|
|
463
463
|
* this into `buildMigrationArtifacts` so the pure builder can preserve
|
|
464
|
-
* fields owned by `migration plan` (contract bookends,
|
|
465
|
-
*
|
|
464
|
+
* fields owned by `migration plan` (contract bookends, `createdAt`) across
|
|
465
|
+
* re-emits.
|
|
466
466
|
*
|
|
467
467
|
* Author-time path: this loader still does not verify the manifest hash
|
|
468
468
|
* or schema — that is the apply-time loader's job. Hash mismatch is the
|
|
@@ -472,8 +472,8 @@ function writeStructuredError(stream: MigrationCliWritable, err: CliStructuredEr
|
|
|
472
472
|
* however, is now surfaced rather than swallowed: a malformed
|
|
473
473
|
* `migration.json` indicates either a hand-edit gone wrong or partial
|
|
474
474
|
* write, and silently rebuilding from `describe()` would discard the
|
|
475
|
-
* user's on-disk content (preserved bookends,
|
|
476
|
-
*
|
|
475
|
+
* user's on-disk content (preserved bookends, `createdAt`) without any
|
|
476
|
+
* indication something was wrong on disk.
|
|
477
477
|
* Apply-time consumers always route through the verifying
|
|
478
478
|
* `readMigrationPackage` in `@prisma-next/migration-tools/io` instead.
|
|
479
479
|
*/
|