@prisma-next/cli 0.3.0-dev.7 → 0.3.0-dev.70
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/LICENSE +201 -0
- package/README.md +314 -80
- package/dist/cli-errors-JlPTsazx.mjs +3 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.js +1 -2376
- package/dist/cli.mjs +203 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/client-PimzSD1f.mjs +981 -0
- package/dist/client-PimzSD1f.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts +7 -0
- package/dist/commands/contract-emit.d.mts.map +1 -0
- package/dist/commands/contract-emit.mjs +151 -0
- package/dist/commands/contract-emit.mjs.map +1 -0
- package/dist/commands/db-init.d.mts +7 -0
- package/dist/commands/db-init.d.mts.map +1 -0
- package/dist/commands/db-init.mjs +134 -0
- package/dist/commands/db-init.mjs.map +1 -0
- package/dist/commands/db-introspect.d.mts +7 -0
- package/dist/commands/db-introspect.d.mts.map +1 -0
- package/dist/commands/db-introspect.mjs +118 -0
- package/dist/commands/db-introspect.mjs.map +1 -0
- package/dist/commands/db-schema-verify.d.mts +7 -0
- package/dist/commands/db-schema-verify.d.mts.map +1 -0
- package/dist/commands/db-schema-verify.mjs +120 -0
- package/dist/commands/db-schema-verify.mjs.map +1 -0
- package/dist/commands/db-sign.d.mts +7 -0
- package/dist/commands/db-sign.d.mts.map +1 -0
- package/dist/commands/db-sign.mjs +142 -0
- package/dist/commands/db-sign.mjs.map +1 -0
- package/dist/commands/db-update.d.mts +7 -0
- package/dist/commands/db-update.d.mts.map +1 -0
- package/dist/commands/db-update.mjs +123 -0
- package/dist/commands/db-update.mjs.map +1 -0
- package/dist/commands/db-verify.d.mts +7 -0
- package/dist/commands/db-verify.d.mts.map +1 -0
- package/dist/commands/db-verify.mjs +133 -0
- package/dist/commands/db-verify.mjs.map +1 -0
- package/dist/commands/migration-apply.d.mts +23 -0
- package/dist/commands/migration-apply.d.mts.map +1 -0
- package/dist/commands/migration-apply.mjs +250 -0
- package/dist/commands/migration-apply.mjs.map +1 -0
- package/dist/commands/migration-plan.d.mts +25 -0
- package/dist/commands/migration-plan.d.mts.map +1 -0
- package/dist/commands/migration-plan.mjs +266 -0
- package/dist/commands/migration-plan.mjs.map +1 -0
- package/dist/commands/migration-show.d.mts +28 -0
- package/dist/commands/migration-show.d.mts.map +1 -0
- package/dist/commands/migration-show.mjs +138 -0
- package/dist/commands/migration-show.mjs.map +1 -0
- package/dist/commands/migration-status.d.mts +35 -0
- package/dist/commands/migration-status.d.mts.map +1 -0
- package/dist/commands/migration-status.mjs +260 -0
- package/dist/commands/migration-status.mjs.map +1 -0
- package/dist/commands/migration-verify.d.mts +16 -0
- package/dist/commands/migration-verify.d.mts.map +1 -0
- package/dist/commands/migration-verify.mjs +86 -0
- package/dist/commands/migration-verify.mjs.map +1 -0
- package/dist/config-loader-PPf4CtDj.mjs +43 -0
- package/dist/config-loader-PPf4CtDj.mjs.map +1 -0
- package/dist/{config-loader.d.ts → config-loader.d.mts} +8 -3
- package/dist/config-loader.d.mts.map +1 -0
- package/dist/config-loader.mjs +3 -0
- package/dist/exports/config-types.d.mts +2 -0
- package/dist/exports/config-types.mjs +3 -0
- package/dist/exports/control-api.d.mts +621 -0
- package/dist/exports/control-api.d.mts.map +1 -0
- package/dist/exports/control-api.mjs +98 -0
- package/dist/exports/control-api.mjs.map +1 -0
- package/dist/{load-ts-contract.d.ts → exports/index.d.mts} +10 -5
- package/dist/exports/index.d.mts.map +1 -0
- package/dist/exports/index.mjs +135 -0
- package/dist/exports/index.mjs.map +1 -0
- package/dist/extract-sql-ddl-BmlKvk4o.mjs +26 -0
- package/dist/extract-sql-ddl-BmlKvk4o.mjs.map +1 -0
- package/dist/framework-components-CjV_jD8f.mjs +59 -0
- package/dist/framework-components-CjV_jD8f.mjs.map +1 -0
- package/dist/migration-command-scaffold-DfY_F3ev.mjs +97 -0
- package/dist/migration-command-scaffold-DfY_F3ev.mjs.map +1 -0
- package/dist/progress-adapter-DENrzF6I.mjs +49 -0
- package/dist/progress-adapter-DENrzF6I.mjs.map +1 -0
- package/dist/result-handler-iA9JtUC7.mjs +1186 -0
- package/dist/result-handler-iA9JtUC7.mjs.map +1 -0
- package/package.json +74 -37
- package/src/cli.ts +43 -0
- package/src/commands/contract-emit.ts +221 -111
- package/src/commands/db-init.ts +217 -426
- package/src/commands/db-introspect.ts +148 -185
- package/src/commands/db-schema-verify.ts +162 -149
- package/src/commands/db-sign.ts +215 -202
- package/src/commands/db-update.ts +220 -0
- package/src/commands/db-verify.ts +193 -156
- package/src/commands/migration-apply.ts +431 -0
- package/src/commands/migration-plan.ts +446 -0
- package/src/commands/migration-show.ts +255 -0
- package/src/commands/migration-status.ts +436 -0
- package/src/commands/migration-verify.ts +151 -0
- package/src/config-loader.ts +13 -3
- package/src/control-api/client.ts +605 -0
- package/src/control-api/errors.ts +9 -0
- package/src/control-api/operations/contract-emit.ts +161 -0
- package/src/control-api/operations/db-init.ts +286 -0
- package/src/control-api/operations/db-update.ts +221 -0
- package/src/control-api/operations/extract-sql-ddl.ts +47 -0
- package/src/control-api/operations/migration-apply.ts +195 -0
- package/src/control-api/operations/migration-helpers.ts +49 -0
- package/src/control-api/types.ts +687 -0
- package/src/exports/config-types.ts +3 -3
- package/src/exports/control-api.ts +53 -0
- package/src/load-ts-contract.ts +16 -11
- package/src/utils/cli-errors.ts +3 -1
- package/src/utils/command-helpers.ts +92 -3
- package/src/utils/framework-components.ts +11 -30
- package/src/utils/migration-command-scaffold.ts +190 -0
- package/src/utils/output.ts +363 -25
- package/src/utils/progress-adapter.ts +86 -0
- package/dist/chunk-464LNZCE.js +0 -134
- package/dist/chunk-464LNZCE.js.map +0 -1
- package/dist/chunk-BZMBKEEQ.js +0 -997
- package/dist/chunk-BZMBKEEQ.js.map +0 -1
- package/dist/chunk-HWYQOCAJ.js +0 -47
- package/dist/chunk-HWYQOCAJ.js.map +0 -1
- package/dist/chunk-ZKYEJROM.js +0 -94
- package/dist/chunk-ZKYEJROM.js.map +0 -1
- package/dist/cli.d.ts +0 -2
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/contract-emit.d.ts +0 -3
- package/dist/commands/contract-emit.d.ts.map +0 -1
- package/dist/commands/contract-emit.js +0 -9
- package/dist/commands/contract-emit.js.map +0 -1
- package/dist/commands/db-init.d.ts +0 -3
- package/dist/commands/db-init.d.ts.map +0 -1
- package/dist/commands/db-init.js +0 -341
- package/dist/commands/db-init.js.map +0 -1
- package/dist/commands/db-introspect.d.ts +0 -3
- package/dist/commands/db-introspect.d.ts.map +0 -1
- package/dist/commands/db-introspect.js +0 -190
- package/dist/commands/db-introspect.js.map +0 -1
- package/dist/commands/db-schema-verify.d.ts +0 -3
- package/dist/commands/db-schema-verify.d.ts.map +0 -1
- package/dist/commands/db-schema-verify.js +0 -164
- package/dist/commands/db-schema-verify.js.map +0 -1
- package/dist/commands/db-sign.d.ts +0 -3
- package/dist/commands/db-sign.d.ts.map +0 -1
- package/dist/commands/db-sign.js +0 -199
- package/dist/commands/db-sign.js.map +0 -1
- package/dist/commands/db-verify.d.ts +0 -3
- package/dist/commands/db-verify.d.ts.map +0 -1
- package/dist/commands/db-verify.js +0 -173
- package/dist/commands/db-verify.js.map +0 -1
- package/dist/config-loader.d.ts.map +0 -1
- package/dist/config-loader.js +0 -7
- package/dist/config-loader.js.map +0 -1
- package/dist/exports/config-types.d.ts +0 -3
- package/dist/exports/config-types.d.ts.map +0 -1
- package/dist/exports/config-types.js +0 -6
- package/dist/exports/config-types.js.map +0 -1
- package/dist/exports/index.d.ts +0 -4
- package/dist/exports/index.d.ts.map +0 -1
- package/dist/exports/index.js +0 -175
- package/dist/exports/index.js.map +0 -1
- package/dist/load-ts-contract.d.ts.map +0 -1
- package/dist/utils/action.d.ts +0 -16
- package/dist/utils/action.d.ts.map +0 -1
- package/dist/utils/cli-errors.d.ts +0 -7
- package/dist/utils/cli-errors.d.ts.map +0 -1
- package/dist/utils/command-helpers.d.ts +0 -12
- package/dist/utils/command-helpers.d.ts.map +0 -1
- package/dist/utils/framework-components.d.ts +0 -81
- package/dist/utils/framework-components.d.ts.map +0 -1
- package/dist/utils/global-flags.d.ts +0 -25
- package/dist/utils/global-flags.d.ts.map +0 -1
- package/dist/utils/output.d.ts +0 -142
- package/dist/utils/output.d.ts.map +0 -1
- package/dist/utils/result-handler.d.ts +0 -15
- package/dist/utils/result-handler.d.ts.map +0 -1
- package/dist/utils/spinner.d.ts +0 -29
- package/dist/utils/spinner.d.ts.map +0 -1
- package/src/utils/action.ts +0 -43
- package/src/utils/spinner.ts +0 -67
|
@@ -0,0 +1,981 @@
|
|
|
1
|
+
import { t as assertFrameworkComponentsCompatible } from "./framework-components-CjV_jD8f.mjs";
|
|
2
|
+
import { t as extractSqlDdl } from "./extract-sql-ddl-BmlKvk4o.mjs";
|
|
3
|
+
import { notOk, ok } from "@prisma-next/utils/result";
|
|
4
|
+
import { createControlPlaneStack } from "@prisma-next/core-control-plane/stack";
|
|
5
|
+
import { ifDefined } from "@prisma-next/utils/defined";
|
|
6
|
+
import { EMPTY_CONTRACT_HASH } from "@prisma-next/core-control-plane/constants";
|
|
7
|
+
|
|
8
|
+
//#region src/control-api/errors.ts
|
|
9
|
+
var ContractValidationError = class extends Error {
|
|
10
|
+
cause;
|
|
11
|
+
constructor(message, cause) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "ContractValidationError";
|
|
14
|
+
this.cause = cause;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/control-api/operations/migration-helpers.ts
|
|
20
|
+
/**
|
|
21
|
+
* Strips operation objects to their public shape (id, label, operationClass).
|
|
22
|
+
* Used at the API boundary to avoid leaking internal fields (precheck, execute, postcheck, etc.).
|
|
23
|
+
*/
|
|
24
|
+
function stripOperations(operations) {
|
|
25
|
+
return operations.map((op) => ({
|
|
26
|
+
id: op.id,
|
|
27
|
+
label: op.label,
|
|
28
|
+
operationClass: op.operationClass
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Creates per-operation progress callbacks for the runner.
|
|
33
|
+
* Returns undefined when no onProgress callback is provided.
|
|
34
|
+
*/
|
|
35
|
+
function createOperationCallbacks(onProgress, action, parentSpanId) {
|
|
36
|
+
if (!onProgress) return;
|
|
37
|
+
return {
|
|
38
|
+
onOperationStart: (op) => {
|
|
39
|
+
onProgress({
|
|
40
|
+
action,
|
|
41
|
+
kind: "spanStart",
|
|
42
|
+
spanId: `operation:${op.id}`,
|
|
43
|
+
parentSpanId,
|
|
44
|
+
label: op.label
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
onOperationComplete: (op) => {
|
|
48
|
+
onProgress({
|
|
49
|
+
action,
|
|
50
|
+
kind: "spanEnd",
|
|
51
|
+
spanId: `operation:${op.id}`,
|
|
52
|
+
outcome: "ok"
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/control-api/operations/db-init.ts
|
|
60
|
+
/**
|
|
61
|
+
* Executes the dbInit operation.
|
|
62
|
+
*
|
|
63
|
+
* This is the core logic extracted from the CLI command, without any file I/O,
|
|
64
|
+
* process.exit(), or console output. It uses the Result pattern to return
|
|
65
|
+
* success or failure details.
|
|
66
|
+
*
|
|
67
|
+
* @param options - The options for executing dbInit
|
|
68
|
+
* @returns Result with DbInitSuccess on success, DbInitFailure on failure
|
|
69
|
+
*/
|
|
70
|
+
async function executeDbInit(options) {
|
|
71
|
+
const { driver, familyInstance, contractIR, mode, migrations, frameworkComponents, onProgress } = options;
|
|
72
|
+
const planner = migrations.createPlanner(familyInstance);
|
|
73
|
+
const runner = migrations.createRunner(familyInstance);
|
|
74
|
+
const introspectSpanId = "introspect";
|
|
75
|
+
onProgress?.({
|
|
76
|
+
action: "dbInit",
|
|
77
|
+
kind: "spanStart",
|
|
78
|
+
spanId: introspectSpanId,
|
|
79
|
+
label: "Introspecting database schema"
|
|
80
|
+
});
|
|
81
|
+
const schemaIR = await familyInstance.introspect({ driver });
|
|
82
|
+
onProgress?.({
|
|
83
|
+
action: "dbInit",
|
|
84
|
+
kind: "spanEnd",
|
|
85
|
+
spanId: introspectSpanId,
|
|
86
|
+
outcome: "ok"
|
|
87
|
+
});
|
|
88
|
+
const policy = { allowedOperationClasses: ["additive"] };
|
|
89
|
+
const planSpanId = "plan";
|
|
90
|
+
onProgress?.({
|
|
91
|
+
action: "dbInit",
|
|
92
|
+
kind: "spanStart",
|
|
93
|
+
spanId: planSpanId,
|
|
94
|
+
label: "Planning migration"
|
|
95
|
+
});
|
|
96
|
+
const plannerResult = await planner.plan({
|
|
97
|
+
contract: contractIR,
|
|
98
|
+
schema: schemaIR,
|
|
99
|
+
policy,
|
|
100
|
+
frameworkComponents
|
|
101
|
+
});
|
|
102
|
+
if (plannerResult.kind === "failure") {
|
|
103
|
+
onProgress?.({
|
|
104
|
+
action: "dbInit",
|
|
105
|
+
kind: "spanEnd",
|
|
106
|
+
spanId: planSpanId,
|
|
107
|
+
outcome: "error"
|
|
108
|
+
});
|
|
109
|
+
return notOk({
|
|
110
|
+
code: "PLANNING_FAILED",
|
|
111
|
+
summary: "Migration planning failed due to conflicts",
|
|
112
|
+
conflicts: plannerResult.conflicts,
|
|
113
|
+
why: void 0,
|
|
114
|
+
meta: void 0
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
const migrationPlan = plannerResult.plan;
|
|
118
|
+
onProgress?.({
|
|
119
|
+
action: "dbInit",
|
|
120
|
+
kind: "spanEnd",
|
|
121
|
+
spanId: planSpanId,
|
|
122
|
+
outcome: "ok"
|
|
123
|
+
});
|
|
124
|
+
const checkMarkerSpanId = "checkMarker";
|
|
125
|
+
onProgress?.({
|
|
126
|
+
action: "dbInit",
|
|
127
|
+
kind: "spanStart",
|
|
128
|
+
spanId: checkMarkerSpanId,
|
|
129
|
+
label: "Checking database signature"
|
|
130
|
+
});
|
|
131
|
+
const existingMarker = await familyInstance.readMarker({ driver });
|
|
132
|
+
if (existingMarker) {
|
|
133
|
+
if (existingMarker.storageHash === migrationPlan.destination.storageHash && (!migrationPlan.destination.profileHash || existingMarker.profileHash === migrationPlan.destination.profileHash)) {
|
|
134
|
+
onProgress?.({
|
|
135
|
+
action: "dbInit",
|
|
136
|
+
kind: "spanEnd",
|
|
137
|
+
spanId: checkMarkerSpanId,
|
|
138
|
+
outcome: "skipped"
|
|
139
|
+
});
|
|
140
|
+
return ok({
|
|
141
|
+
mode,
|
|
142
|
+
plan: { operations: [] },
|
|
143
|
+
destination: {
|
|
144
|
+
storageHash: migrationPlan.destination.storageHash,
|
|
145
|
+
...ifDefined("profileHash", migrationPlan.destination.profileHash)
|
|
146
|
+
},
|
|
147
|
+
...ifDefined("execution", mode === "apply" ? {
|
|
148
|
+
operationsPlanned: 0,
|
|
149
|
+
operationsExecuted: 0
|
|
150
|
+
} : void 0),
|
|
151
|
+
...ifDefined("marker", mode === "apply" ? {
|
|
152
|
+
storageHash: existingMarker.storageHash,
|
|
153
|
+
profileHash: existingMarker.profileHash
|
|
154
|
+
} : void 0),
|
|
155
|
+
summary: "Database already at target contract state"
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
onProgress?.({
|
|
159
|
+
action: "dbInit",
|
|
160
|
+
kind: "spanEnd",
|
|
161
|
+
spanId: checkMarkerSpanId,
|
|
162
|
+
outcome: "error"
|
|
163
|
+
});
|
|
164
|
+
return notOk({
|
|
165
|
+
code: "MARKER_ORIGIN_MISMATCH",
|
|
166
|
+
summary: "Existing contract marker does not match plan destination",
|
|
167
|
+
marker: {
|
|
168
|
+
storageHash: existingMarker.storageHash,
|
|
169
|
+
profileHash: existingMarker.profileHash
|
|
170
|
+
},
|
|
171
|
+
destination: {
|
|
172
|
+
storageHash: migrationPlan.destination.storageHash,
|
|
173
|
+
profileHash: migrationPlan.destination.profileHash
|
|
174
|
+
},
|
|
175
|
+
why: void 0,
|
|
176
|
+
conflicts: void 0,
|
|
177
|
+
meta: void 0
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
onProgress?.({
|
|
181
|
+
action: "dbInit",
|
|
182
|
+
kind: "spanEnd",
|
|
183
|
+
spanId: checkMarkerSpanId,
|
|
184
|
+
outcome: "ok"
|
|
185
|
+
});
|
|
186
|
+
if (mode === "plan") {
|
|
187
|
+
const planSql = familyInstance.familyId === "sql" ? extractSqlDdl(migrationPlan.operations) : void 0;
|
|
188
|
+
return ok({
|
|
189
|
+
mode: "plan",
|
|
190
|
+
plan: {
|
|
191
|
+
operations: stripOperations(migrationPlan.operations),
|
|
192
|
+
...ifDefined("sql", planSql)
|
|
193
|
+
},
|
|
194
|
+
destination: {
|
|
195
|
+
storageHash: migrationPlan.destination.storageHash,
|
|
196
|
+
...ifDefined("profileHash", migrationPlan.destination.profileHash)
|
|
197
|
+
},
|
|
198
|
+
summary: `Planned ${migrationPlan.operations.length} operation(s)`
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
const applySpanId = "apply";
|
|
202
|
+
onProgress?.({
|
|
203
|
+
action: "dbInit",
|
|
204
|
+
kind: "spanStart",
|
|
205
|
+
spanId: applySpanId,
|
|
206
|
+
label: "Applying migration plan"
|
|
207
|
+
});
|
|
208
|
+
const callbacks = createOperationCallbacks(onProgress, "dbInit", applySpanId);
|
|
209
|
+
const runnerResult = await runner.execute({
|
|
210
|
+
plan: migrationPlan,
|
|
211
|
+
driver,
|
|
212
|
+
destinationContract: contractIR,
|
|
213
|
+
policy,
|
|
214
|
+
...ifDefined("callbacks", callbacks),
|
|
215
|
+
executionChecks: {
|
|
216
|
+
prechecks: false,
|
|
217
|
+
postchecks: false,
|
|
218
|
+
idempotencyChecks: false
|
|
219
|
+
},
|
|
220
|
+
frameworkComponents
|
|
221
|
+
});
|
|
222
|
+
if (!runnerResult.ok) {
|
|
223
|
+
onProgress?.({
|
|
224
|
+
action: "dbInit",
|
|
225
|
+
kind: "spanEnd",
|
|
226
|
+
spanId: applySpanId,
|
|
227
|
+
outcome: "error"
|
|
228
|
+
});
|
|
229
|
+
return notOk({
|
|
230
|
+
code: "RUNNER_FAILED",
|
|
231
|
+
summary: runnerResult.failure.summary,
|
|
232
|
+
why: runnerResult.failure.why,
|
|
233
|
+
meta: runnerResult.failure.meta,
|
|
234
|
+
conflicts: void 0
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
const execution = runnerResult.value;
|
|
238
|
+
onProgress?.({
|
|
239
|
+
action: "dbInit",
|
|
240
|
+
kind: "spanEnd",
|
|
241
|
+
spanId: applySpanId,
|
|
242
|
+
outcome: "ok"
|
|
243
|
+
});
|
|
244
|
+
return ok({
|
|
245
|
+
mode: "apply",
|
|
246
|
+
plan: { operations: stripOperations(migrationPlan.operations) },
|
|
247
|
+
destination: {
|
|
248
|
+
storageHash: migrationPlan.destination.storageHash,
|
|
249
|
+
...ifDefined("profileHash", migrationPlan.destination.profileHash)
|
|
250
|
+
},
|
|
251
|
+
execution: {
|
|
252
|
+
operationsPlanned: execution.operationsPlanned,
|
|
253
|
+
operationsExecuted: execution.operationsExecuted
|
|
254
|
+
},
|
|
255
|
+
marker: migrationPlan.destination.profileHash ? {
|
|
256
|
+
storageHash: migrationPlan.destination.storageHash,
|
|
257
|
+
profileHash: migrationPlan.destination.profileHash
|
|
258
|
+
} : { storageHash: migrationPlan.destination.storageHash },
|
|
259
|
+
summary: `Applied ${execution.operationsExecuted} operation(s), database signed`
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
//#endregion
|
|
264
|
+
//#region src/control-api/operations/db-update.ts
|
|
265
|
+
const DB_UPDATE_POLICY = { allowedOperationClasses: [
|
|
266
|
+
"additive",
|
|
267
|
+
"widening",
|
|
268
|
+
"destructive"
|
|
269
|
+
] };
|
|
270
|
+
/**
|
|
271
|
+
* Executes the db update operation: introspect → plan → (optionally) apply → marker.
|
|
272
|
+
*
|
|
273
|
+
* db update is a pure reconciliation command: it introspects the live schema, plans the diff
|
|
274
|
+
* to the destination contract, and applies operations. The marker is bookkeeping only — written
|
|
275
|
+
* after apply so that `verify` and `db init` can reference it, but never read or validated
|
|
276
|
+
* by db update itself. The runner creates the marker table if it does not exist.
|
|
277
|
+
*/
|
|
278
|
+
async function executeDbUpdate(options) {
|
|
279
|
+
const { driver, familyInstance, contractIR, mode, migrations, frameworkComponents, onProgress } = options;
|
|
280
|
+
const planner = migrations.createPlanner(familyInstance);
|
|
281
|
+
const runner = migrations.createRunner(familyInstance);
|
|
282
|
+
const introspectSpanId = "introspect";
|
|
283
|
+
onProgress?.({
|
|
284
|
+
action: "dbUpdate",
|
|
285
|
+
kind: "spanStart",
|
|
286
|
+
spanId: introspectSpanId,
|
|
287
|
+
label: "Introspecting database schema"
|
|
288
|
+
});
|
|
289
|
+
const schemaIR = await familyInstance.introspect({ driver });
|
|
290
|
+
onProgress?.({
|
|
291
|
+
action: "dbUpdate",
|
|
292
|
+
kind: "spanEnd",
|
|
293
|
+
spanId: introspectSpanId,
|
|
294
|
+
outcome: "ok"
|
|
295
|
+
});
|
|
296
|
+
const policy = DB_UPDATE_POLICY;
|
|
297
|
+
const planSpanId = "plan";
|
|
298
|
+
onProgress?.({
|
|
299
|
+
action: "dbUpdate",
|
|
300
|
+
kind: "spanStart",
|
|
301
|
+
spanId: planSpanId,
|
|
302
|
+
label: "Planning migration"
|
|
303
|
+
});
|
|
304
|
+
const plannerResult = await planner.plan({
|
|
305
|
+
contract: contractIR,
|
|
306
|
+
schema: schemaIR,
|
|
307
|
+
policy,
|
|
308
|
+
frameworkComponents
|
|
309
|
+
});
|
|
310
|
+
if (plannerResult.kind === "failure") {
|
|
311
|
+
onProgress?.({
|
|
312
|
+
action: "dbUpdate",
|
|
313
|
+
kind: "spanEnd",
|
|
314
|
+
spanId: planSpanId,
|
|
315
|
+
outcome: "error"
|
|
316
|
+
});
|
|
317
|
+
return notOk({
|
|
318
|
+
code: "PLANNING_FAILED",
|
|
319
|
+
summary: "Migration planning failed due to conflicts",
|
|
320
|
+
conflicts: plannerResult.conflicts,
|
|
321
|
+
why: void 0,
|
|
322
|
+
meta: void 0
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
onProgress?.({
|
|
326
|
+
action: "dbUpdate",
|
|
327
|
+
kind: "spanEnd",
|
|
328
|
+
spanId: planSpanId,
|
|
329
|
+
outcome: "ok"
|
|
330
|
+
});
|
|
331
|
+
const migrationPlan = plannerResult.plan;
|
|
332
|
+
if (mode === "plan") {
|
|
333
|
+
const planSql = familyInstance.familyId === "sql" ? extractSqlDdl(migrationPlan.operations) : void 0;
|
|
334
|
+
return ok({
|
|
335
|
+
mode: "plan",
|
|
336
|
+
plan: {
|
|
337
|
+
operations: stripOperations(migrationPlan.operations),
|
|
338
|
+
...planSql !== void 0 ? { sql: planSql } : {}
|
|
339
|
+
},
|
|
340
|
+
destination: {
|
|
341
|
+
storageHash: migrationPlan.destination.storageHash,
|
|
342
|
+
...ifDefined("profileHash", migrationPlan.destination.profileHash)
|
|
343
|
+
},
|
|
344
|
+
summary: `Planned ${migrationPlan.operations.length} operation(s)`
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
if (!options.acceptDataLoss) {
|
|
348
|
+
const destructiveOps = migrationPlan.operations.filter((op) => op.operationClass === "destructive").map((op) => ({
|
|
349
|
+
id: op.id,
|
|
350
|
+
label: op.label
|
|
351
|
+
}));
|
|
352
|
+
if (destructiveOps.length > 0) return notOk({
|
|
353
|
+
code: "DESTRUCTIVE_CHANGES",
|
|
354
|
+
summary: `Planned ${destructiveOps.length} destructive operation(s) that require confirmation`,
|
|
355
|
+
why: "Use --plan to preview destructive operations, then re-run with --accept-data-loss to apply",
|
|
356
|
+
conflicts: void 0,
|
|
357
|
+
meta: { destructiveOperations: destructiveOps }
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
const applySpanId = "apply";
|
|
361
|
+
onProgress?.({
|
|
362
|
+
action: "dbUpdate",
|
|
363
|
+
kind: "spanStart",
|
|
364
|
+
spanId: applySpanId,
|
|
365
|
+
label: "Applying migration plan"
|
|
366
|
+
});
|
|
367
|
+
const callbacks = createOperationCallbacks(onProgress, "dbUpdate", applySpanId);
|
|
368
|
+
const runnerResult = await runner.execute({
|
|
369
|
+
plan: migrationPlan,
|
|
370
|
+
driver,
|
|
371
|
+
destinationContract: contractIR,
|
|
372
|
+
policy,
|
|
373
|
+
...callbacks ? { callbacks } : {},
|
|
374
|
+
executionChecks: {
|
|
375
|
+
prechecks: false,
|
|
376
|
+
postchecks: false,
|
|
377
|
+
idempotencyChecks: false
|
|
378
|
+
},
|
|
379
|
+
frameworkComponents
|
|
380
|
+
});
|
|
381
|
+
if (!runnerResult.ok) {
|
|
382
|
+
onProgress?.({
|
|
383
|
+
action: "dbUpdate",
|
|
384
|
+
kind: "spanEnd",
|
|
385
|
+
spanId: applySpanId,
|
|
386
|
+
outcome: "error"
|
|
387
|
+
});
|
|
388
|
+
return notOk({
|
|
389
|
+
code: "RUNNER_FAILED",
|
|
390
|
+
summary: runnerResult.failure.summary,
|
|
391
|
+
why: runnerResult.failure.why,
|
|
392
|
+
meta: runnerResult.failure.meta,
|
|
393
|
+
conflicts: void 0
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
const execution = runnerResult.value;
|
|
397
|
+
onProgress?.({
|
|
398
|
+
action: "dbUpdate",
|
|
399
|
+
kind: "spanEnd",
|
|
400
|
+
spanId: applySpanId,
|
|
401
|
+
outcome: "ok"
|
|
402
|
+
});
|
|
403
|
+
return ok({
|
|
404
|
+
mode: "apply",
|
|
405
|
+
plan: { operations: stripOperations(migrationPlan.operations) },
|
|
406
|
+
destination: {
|
|
407
|
+
storageHash: migrationPlan.destination.storageHash,
|
|
408
|
+
...ifDefined("profileHash", migrationPlan.destination.profileHash)
|
|
409
|
+
},
|
|
410
|
+
execution: {
|
|
411
|
+
operationsPlanned: execution.operationsPlanned,
|
|
412
|
+
operationsExecuted: execution.operationsExecuted
|
|
413
|
+
},
|
|
414
|
+
marker: migrationPlan.destination.profileHash ? {
|
|
415
|
+
storageHash: migrationPlan.destination.storageHash,
|
|
416
|
+
profileHash: migrationPlan.destination.profileHash
|
|
417
|
+
} : { storageHash: migrationPlan.destination.storageHash },
|
|
418
|
+
summary: execution.operationsExecuted === 0 ? "Database already matches contract, signature updated" : `Applied ${execution.operationsExecuted} operation(s), signature updated`
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
//#endregion
|
|
423
|
+
//#region src/control-api/operations/migration-apply.ts
|
|
424
|
+
async function executeMigrationApply(options) {
|
|
425
|
+
const { driver, familyInstance, originHash, destinationHash, pendingMigrations, migrations, frameworkComponents, targetId, onProgress } = options;
|
|
426
|
+
if (pendingMigrations.length === 0) {
|
|
427
|
+
if (originHash !== destinationHash) return notOk({
|
|
428
|
+
code: "MIGRATION_PATH_NOT_FOUND",
|
|
429
|
+
summary: "No migrations provided for requested origin and destination",
|
|
430
|
+
why: `Requested ${originHash} -> ${destinationHash} but pendingMigrations is empty`,
|
|
431
|
+
meta: {
|
|
432
|
+
originHash,
|
|
433
|
+
destinationHash
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
return ok({
|
|
437
|
+
migrationsApplied: 0,
|
|
438
|
+
markerHash: originHash,
|
|
439
|
+
applied: [],
|
|
440
|
+
summary: "Already up to date"
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
const firstMigration = pendingMigrations[0];
|
|
444
|
+
const lastMigration = pendingMigrations[pendingMigrations.length - 1];
|
|
445
|
+
if (firstMigration.from !== originHash || lastMigration.to !== destinationHash) return notOk({
|
|
446
|
+
code: "MIGRATION_PATH_NOT_FOUND",
|
|
447
|
+
summary: "Migration apply path does not match requested origin and destination",
|
|
448
|
+
why: `Path resolved as ${firstMigration.from} -> ${lastMigration.to}, but requested ${originHash} -> ${destinationHash}`,
|
|
449
|
+
meta: {
|
|
450
|
+
originHash,
|
|
451
|
+
destinationHash,
|
|
452
|
+
pathOrigin: firstMigration.from,
|
|
453
|
+
pathDestination: lastMigration.to
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
for (let i = 1; i < pendingMigrations.length; i++) {
|
|
457
|
+
const previous = pendingMigrations[i - 1];
|
|
458
|
+
const current = pendingMigrations[i];
|
|
459
|
+
if (previous.to !== current.from) return notOk({
|
|
460
|
+
code: "MIGRATION_PATH_NOT_FOUND",
|
|
461
|
+
summary: "Migration apply path contains a discontinuity between adjacent migrations",
|
|
462
|
+
why: `Migration "${previous.dirName}" ends at ${previous.to}, but next migration "${current.dirName}" starts at ${current.from}`,
|
|
463
|
+
meta: {
|
|
464
|
+
originHash,
|
|
465
|
+
destinationHash,
|
|
466
|
+
previousDirName: previous.dirName,
|
|
467
|
+
previousTo: previous.to,
|
|
468
|
+
currentDirName: current.dirName,
|
|
469
|
+
currentFrom: current.from,
|
|
470
|
+
discontinuityIndex: i
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
const runner = migrations.createRunner(familyInstance);
|
|
475
|
+
const applied = [];
|
|
476
|
+
for (const migration of pendingMigrations) {
|
|
477
|
+
const migrationSpanId = `migration:${migration.dirName}`;
|
|
478
|
+
onProgress?.({
|
|
479
|
+
action: "migrationApply",
|
|
480
|
+
kind: "spanStart",
|
|
481
|
+
spanId: migrationSpanId,
|
|
482
|
+
label: `Applying ${migration.dirName}`
|
|
483
|
+
});
|
|
484
|
+
const operations = migration.operations;
|
|
485
|
+
const policy = { allowedOperationClasses: [
|
|
486
|
+
"additive",
|
|
487
|
+
"widening",
|
|
488
|
+
"destructive"
|
|
489
|
+
] };
|
|
490
|
+
const plan = {
|
|
491
|
+
targetId,
|
|
492
|
+
origin: migration.from === EMPTY_CONTRACT_HASH ? null : { storageHash: migration.from },
|
|
493
|
+
destination: { storageHash: migration.to },
|
|
494
|
+
operations
|
|
495
|
+
};
|
|
496
|
+
const destinationContract = familyInstance.validateContractIR(migration.toContract);
|
|
497
|
+
const runnerResult = await runner.execute({
|
|
498
|
+
plan,
|
|
499
|
+
driver,
|
|
500
|
+
destinationContract,
|
|
501
|
+
policy,
|
|
502
|
+
executionChecks: {
|
|
503
|
+
prechecks: true,
|
|
504
|
+
postchecks: true,
|
|
505
|
+
idempotencyChecks: true
|
|
506
|
+
},
|
|
507
|
+
frameworkComponents
|
|
508
|
+
});
|
|
509
|
+
if (!runnerResult.ok) {
|
|
510
|
+
onProgress?.({
|
|
511
|
+
action: "migrationApply",
|
|
512
|
+
kind: "spanEnd",
|
|
513
|
+
spanId: migrationSpanId,
|
|
514
|
+
outcome: "error"
|
|
515
|
+
});
|
|
516
|
+
return notOk({
|
|
517
|
+
code: "RUNNER_FAILED",
|
|
518
|
+
summary: runnerResult.failure.summary,
|
|
519
|
+
why: runnerResult.failure.why,
|
|
520
|
+
meta: {
|
|
521
|
+
migration: migration.dirName,
|
|
522
|
+
from: migration.from,
|
|
523
|
+
to: migration.to,
|
|
524
|
+
...runnerResult.failure.meta ?? {}
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
onProgress?.({
|
|
529
|
+
action: "migrationApply",
|
|
530
|
+
kind: "spanEnd",
|
|
531
|
+
spanId: migrationSpanId,
|
|
532
|
+
outcome: "ok"
|
|
533
|
+
});
|
|
534
|
+
applied.push({
|
|
535
|
+
dirName: migration.dirName,
|
|
536
|
+
from: migration.from,
|
|
537
|
+
to: migration.to,
|
|
538
|
+
operationsExecuted: runnerResult.value.operationsExecuted
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
const finalHash = pendingMigrations[pendingMigrations.length - 1].to;
|
|
542
|
+
const totalOps = applied.reduce((sum, a) => sum + a.operationsExecuted, 0);
|
|
543
|
+
return ok({
|
|
544
|
+
migrationsApplied: applied.length,
|
|
545
|
+
markerHash: finalHash,
|
|
546
|
+
applied,
|
|
547
|
+
summary: `Applied ${applied.length} migration(s) (${totalOps} operation(s)), marker at ${finalHash}`
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
//#endregion
|
|
552
|
+
//#region src/control-api/client.ts
|
|
553
|
+
/**
|
|
554
|
+
* Creates a programmatic control client for Prisma Next operations.
|
|
555
|
+
*
|
|
556
|
+
* The client accepts framework component descriptors at creation time,
|
|
557
|
+
* manages driver lifecycle via connect()/close(), and exposes domain
|
|
558
|
+
* operations that delegate to the existing family instance methods.
|
|
559
|
+
*
|
|
560
|
+
* @see {@link ControlClient} for the client interface
|
|
561
|
+
* @see README.md "Programmatic Control API" section for usage examples
|
|
562
|
+
*/
|
|
563
|
+
function createControlClient(options) {
|
|
564
|
+
return new ControlClientImpl(options);
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Implementation of ControlClient.
|
|
568
|
+
* Manages initialization and connection state, delegates operations to family instance.
|
|
569
|
+
*/
|
|
570
|
+
var ControlClientImpl = class {
|
|
571
|
+
options;
|
|
572
|
+
stack = null;
|
|
573
|
+
driver = null;
|
|
574
|
+
familyInstance = null;
|
|
575
|
+
frameworkComponents = null;
|
|
576
|
+
initialized = false;
|
|
577
|
+
defaultConnection;
|
|
578
|
+
constructor(options) {
|
|
579
|
+
this.options = options;
|
|
580
|
+
this.defaultConnection = options.connection;
|
|
581
|
+
}
|
|
582
|
+
init() {
|
|
583
|
+
if (this.initialized) return;
|
|
584
|
+
this.stack = createControlPlaneStack({
|
|
585
|
+
target: this.options.target,
|
|
586
|
+
adapter: this.options.adapter,
|
|
587
|
+
driver: this.options.driver,
|
|
588
|
+
extensionPacks: this.options.extensionPacks
|
|
589
|
+
});
|
|
590
|
+
this.familyInstance = this.options.family.create(this.stack);
|
|
591
|
+
const rawComponents = [
|
|
592
|
+
this.options.target,
|
|
593
|
+
this.options.adapter,
|
|
594
|
+
...this.options.extensionPacks ?? []
|
|
595
|
+
];
|
|
596
|
+
this.frameworkComponents = assertFrameworkComponentsCompatible(this.options.family.familyId, this.options.target.targetId, rawComponents);
|
|
597
|
+
this.initialized = true;
|
|
598
|
+
}
|
|
599
|
+
async connect(connection) {
|
|
600
|
+
this.init();
|
|
601
|
+
if (this.driver) throw new Error("Already connected. Call close() before reconnecting.");
|
|
602
|
+
const resolvedConnection = connection ?? this.defaultConnection;
|
|
603
|
+
if (resolvedConnection === void 0) throw new Error("No connection provided. Pass a connection to connect() or provide a default connection when creating the client.");
|
|
604
|
+
if (!this.stack?.driver) throw new Error("Driver is not configured. Pass a driver descriptor when creating the control client to enable database operations.");
|
|
605
|
+
this.driver = await this.stack?.driver.create(resolvedConnection);
|
|
606
|
+
}
|
|
607
|
+
async close() {
|
|
608
|
+
if (this.driver) {
|
|
609
|
+
await this.driver.close();
|
|
610
|
+
this.driver = null;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
async ensureConnected() {
|
|
614
|
+
this.init();
|
|
615
|
+
if (!this.driver && this.defaultConnection !== void 0) await this.connect(this.defaultConnection);
|
|
616
|
+
if (!this.driver || !this.familyInstance || !this.frameworkComponents) throw new Error("Not connected. Call connect(connection) first.");
|
|
617
|
+
return {
|
|
618
|
+
driver: this.driver,
|
|
619
|
+
familyInstance: this.familyInstance,
|
|
620
|
+
frameworkComponents: this.frameworkComponents
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
async connectWithProgress(connection, action, onProgress) {
|
|
624
|
+
if (connection === void 0) return;
|
|
625
|
+
onProgress?.({
|
|
626
|
+
action,
|
|
627
|
+
kind: "spanStart",
|
|
628
|
+
spanId: "connect",
|
|
629
|
+
label: "Connecting to database..."
|
|
630
|
+
});
|
|
631
|
+
try {
|
|
632
|
+
await this.connect(connection);
|
|
633
|
+
onProgress?.({
|
|
634
|
+
action,
|
|
635
|
+
kind: "spanEnd",
|
|
636
|
+
spanId: "connect",
|
|
637
|
+
outcome: "ok"
|
|
638
|
+
});
|
|
639
|
+
} catch (error) {
|
|
640
|
+
onProgress?.({
|
|
641
|
+
action,
|
|
642
|
+
kind: "spanEnd",
|
|
643
|
+
spanId: "connect",
|
|
644
|
+
outcome: "error"
|
|
645
|
+
});
|
|
646
|
+
throw error;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
async verify(options) {
|
|
650
|
+
const { onProgress } = options;
|
|
651
|
+
await this.connectWithProgress(options.connection, "verify", onProgress);
|
|
652
|
+
const { driver, familyInstance } = await this.ensureConnected();
|
|
653
|
+
let contractIR;
|
|
654
|
+
try {
|
|
655
|
+
contractIR = familyInstance.validateContractIR(options.contractIR);
|
|
656
|
+
} catch (error) {
|
|
657
|
+
throw new ContractValidationError(error instanceof Error ? error.message : String(error), error);
|
|
658
|
+
}
|
|
659
|
+
onProgress?.({
|
|
660
|
+
action: "verify",
|
|
661
|
+
kind: "spanStart",
|
|
662
|
+
spanId: "verify",
|
|
663
|
+
label: "Verifying database signature..."
|
|
664
|
+
});
|
|
665
|
+
try {
|
|
666
|
+
const result = await familyInstance.verify({
|
|
667
|
+
driver,
|
|
668
|
+
contractIR,
|
|
669
|
+
expectedTargetId: this.options.target.targetId,
|
|
670
|
+
contractPath: ""
|
|
671
|
+
});
|
|
672
|
+
onProgress?.({
|
|
673
|
+
action: "verify",
|
|
674
|
+
kind: "spanEnd",
|
|
675
|
+
spanId: "verify",
|
|
676
|
+
outcome: result.ok ? "ok" : "error"
|
|
677
|
+
});
|
|
678
|
+
return result;
|
|
679
|
+
} catch (error) {
|
|
680
|
+
onProgress?.({
|
|
681
|
+
action: "verify",
|
|
682
|
+
kind: "spanEnd",
|
|
683
|
+
spanId: "verify",
|
|
684
|
+
outcome: "error"
|
|
685
|
+
});
|
|
686
|
+
throw error;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
async schemaVerify(options) {
|
|
690
|
+
const { onProgress } = options;
|
|
691
|
+
await this.connectWithProgress(options.connection, "schemaVerify", onProgress);
|
|
692
|
+
const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
|
|
693
|
+
let contractIR;
|
|
694
|
+
try {
|
|
695
|
+
contractIR = familyInstance.validateContractIR(options.contractIR);
|
|
696
|
+
} catch (error) {
|
|
697
|
+
throw new ContractValidationError(error instanceof Error ? error.message : String(error), error);
|
|
698
|
+
}
|
|
699
|
+
onProgress?.({
|
|
700
|
+
action: "schemaVerify",
|
|
701
|
+
kind: "spanStart",
|
|
702
|
+
spanId: "schemaVerify",
|
|
703
|
+
label: "Verifying database schema..."
|
|
704
|
+
});
|
|
705
|
+
try {
|
|
706
|
+
const result = await familyInstance.schemaVerify({
|
|
707
|
+
driver,
|
|
708
|
+
contractIR,
|
|
709
|
+
strict: options.strict ?? false,
|
|
710
|
+
contractPath: "",
|
|
711
|
+
frameworkComponents
|
|
712
|
+
});
|
|
713
|
+
onProgress?.({
|
|
714
|
+
action: "schemaVerify",
|
|
715
|
+
kind: "spanEnd",
|
|
716
|
+
spanId: "schemaVerify",
|
|
717
|
+
outcome: result.ok ? "ok" : "error"
|
|
718
|
+
});
|
|
719
|
+
return result;
|
|
720
|
+
} catch (error) {
|
|
721
|
+
onProgress?.({
|
|
722
|
+
action: "schemaVerify",
|
|
723
|
+
kind: "spanEnd",
|
|
724
|
+
spanId: "schemaVerify",
|
|
725
|
+
outcome: "error"
|
|
726
|
+
});
|
|
727
|
+
throw error;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
async sign(options) {
|
|
731
|
+
const { onProgress } = options;
|
|
732
|
+
await this.connectWithProgress(options.connection, "sign", onProgress);
|
|
733
|
+
const { driver, familyInstance } = await this.ensureConnected();
|
|
734
|
+
let contractIR;
|
|
735
|
+
try {
|
|
736
|
+
contractIR = familyInstance.validateContractIR(options.contractIR);
|
|
737
|
+
} catch (error) {
|
|
738
|
+
throw new ContractValidationError(error instanceof Error ? error.message : String(error), error);
|
|
739
|
+
}
|
|
740
|
+
onProgress?.({
|
|
741
|
+
action: "sign",
|
|
742
|
+
kind: "spanStart",
|
|
743
|
+
spanId: "sign",
|
|
744
|
+
label: "Signing database..."
|
|
745
|
+
});
|
|
746
|
+
try {
|
|
747
|
+
const result = await familyInstance.sign({
|
|
748
|
+
driver,
|
|
749
|
+
contractIR,
|
|
750
|
+
contractPath: options.contractPath ?? "",
|
|
751
|
+
...ifDefined("configPath", options.configPath)
|
|
752
|
+
});
|
|
753
|
+
onProgress?.({
|
|
754
|
+
action: "sign",
|
|
755
|
+
kind: "spanEnd",
|
|
756
|
+
spanId: "sign",
|
|
757
|
+
outcome: "ok"
|
|
758
|
+
});
|
|
759
|
+
return result;
|
|
760
|
+
} catch (error) {
|
|
761
|
+
onProgress?.({
|
|
762
|
+
action: "sign",
|
|
763
|
+
kind: "spanEnd",
|
|
764
|
+
spanId: "sign",
|
|
765
|
+
outcome: "error"
|
|
766
|
+
});
|
|
767
|
+
throw error;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
async dbInit(options) {
|
|
771
|
+
const { onProgress } = options;
|
|
772
|
+
await this.connectWithProgress(options.connection, "dbInit", onProgress);
|
|
773
|
+
const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
|
|
774
|
+
if (!this.options.target.migrations) throw new Error(`Target "${this.options.target.targetId}" does not support migrations`);
|
|
775
|
+
let contractIR;
|
|
776
|
+
try {
|
|
777
|
+
contractIR = familyInstance.validateContractIR(options.contractIR);
|
|
778
|
+
} catch (error) {
|
|
779
|
+
throw new ContractValidationError(error instanceof Error ? error.message : String(error), error);
|
|
780
|
+
}
|
|
781
|
+
return executeDbInit({
|
|
782
|
+
driver,
|
|
783
|
+
familyInstance,
|
|
784
|
+
contractIR,
|
|
785
|
+
mode: options.mode,
|
|
786
|
+
migrations: this.options.target.migrations,
|
|
787
|
+
frameworkComponents,
|
|
788
|
+
...ifDefined("onProgress", onProgress)
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
async dbUpdate(options) {
|
|
792
|
+
const { onProgress } = options;
|
|
793
|
+
await this.connectWithProgress(options.connection, "dbUpdate", onProgress);
|
|
794
|
+
const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
|
|
795
|
+
if (!this.options.target.migrations) throw new Error(`Target "${this.options.target.targetId}" does not support migrations`);
|
|
796
|
+
let contractIR;
|
|
797
|
+
try {
|
|
798
|
+
contractIR = familyInstance.validateContractIR(options.contractIR);
|
|
799
|
+
} catch (error) {
|
|
800
|
+
throw new ContractValidationError(error instanceof Error ? error.message : String(error), error);
|
|
801
|
+
}
|
|
802
|
+
return executeDbUpdate({
|
|
803
|
+
driver,
|
|
804
|
+
familyInstance,
|
|
805
|
+
contractIR,
|
|
806
|
+
mode: options.mode,
|
|
807
|
+
migrations: this.options.target.migrations,
|
|
808
|
+
frameworkComponents,
|
|
809
|
+
...ifDefined("acceptDataLoss", options.acceptDataLoss),
|
|
810
|
+
...ifDefined("onProgress", onProgress)
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
async readMarker() {
|
|
814
|
+
const { driver, familyInstance } = await this.ensureConnected();
|
|
815
|
+
return familyInstance.readMarker({ driver });
|
|
816
|
+
}
|
|
817
|
+
async migrationApply(options) {
|
|
818
|
+
const { onProgress } = options;
|
|
819
|
+
await this.connectWithProgress(options.connection, "migrationApply", onProgress);
|
|
820
|
+
const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
|
|
821
|
+
if (!this.options.target.migrations) throw new Error(`Target "${this.options.target.targetId}" does not support migrations`);
|
|
822
|
+
return executeMigrationApply({
|
|
823
|
+
driver,
|
|
824
|
+
familyInstance,
|
|
825
|
+
originHash: options.originHash,
|
|
826
|
+
destinationHash: options.destinationHash,
|
|
827
|
+
pendingMigrations: options.pendingMigrations,
|
|
828
|
+
migrations: this.options.target.migrations,
|
|
829
|
+
frameworkComponents,
|
|
830
|
+
targetId: this.options.target.targetId,
|
|
831
|
+
...onProgress ? { onProgress } : {}
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
async introspect(options) {
|
|
835
|
+
const onProgress = options?.onProgress;
|
|
836
|
+
await this.connectWithProgress(options?.connection, "introspect", onProgress);
|
|
837
|
+
const { driver, familyInstance } = await this.ensureConnected();
|
|
838
|
+
options?.schema;
|
|
839
|
+
onProgress?.({
|
|
840
|
+
action: "introspect",
|
|
841
|
+
kind: "spanStart",
|
|
842
|
+
spanId: "introspect",
|
|
843
|
+
label: "Introspecting database schema..."
|
|
844
|
+
});
|
|
845
|
+
try {
|
|
846
|
+
const result = await familyInstance.introspect({ driver });
|
|
847
|
+
onProgress?.({
|
|
848
|
+
action: "introspect",
|
|
849
|
+
kind: "spanEnd",
|
|
850
|
+
spanId: "introspect",
|
|
851
|
+
outcome: "ok"
|
|
852
|
+
});
|
|
853
|
+
return result;
|
|
854
|
+
} catch (error) {
|
|
855
|
+
onProgress?.({
|
|
856
|
+
action: "introspect",
|
|
857
|
+
kind: "spanEnd",
|
|
858
|
+
spanId: "introspect",
|
|
859
|
+
outcome: "error"
|
|
860
|
+
});
|
|
861
|
+
throw error;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
toSchemaView(schemaIR) {
|
|
865
|
+
this.init();
|
|
866
|
+
if (this.familyInstance?.toSchemaView) return this.familyInstance.toSchemaView(schemaIR);
|
|
867
|
+
}
|
|
868
|
+
async emit(options) {
|
|
869
|
+
const { onProgress, contractConfig } = options;
|
|
870
|
+
this.init();
|
|
871
|
+
if (!this.familyInstance) throw new Error("Family instance was not initialized. This is a bug.");
|
|
872
|
+
let contractRaw;
|
|
873
|
+
onProgress?.({
|
|
874
|
+
action: "emit",
|
|
875
|
+
kind: "spanStart",
|
|
876
|
+
spanId: "resolveSource",
|
|
877
|
+
label: "Resolving contract source..."
|
|
878
|
+
});
|
|
879
|
+
try {
|
|
880
|
+
const providerResult = await contractConfig.sourceProvider();
|
|
881
|
+
if (!providerResult.ok) {
|
|
882
|
+
onProgress?.({
|
|
883
|
+
action: "emit",
|
|
884
|
+
kind: "spanEnd",
|
|
885
|
+
spanId: "resolveSource",
|
|
886
|
+
outcome: "error"
|
|
887
|
+
});
|
|
888
|
+
return notOk({
|
|
889
|
+
code: "CONTRACT_SOURCE_INVALID",
|
|
890
|
+
summary: providerResult.failure.summary,
|
|
891
|
+
why: providerResult.failure.summary,
|
|
892
|
+
meta: providerResult.failure.meta,
|
|
893
|
+
diagnostics: providerResult.failure
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
contractRaw = providerResult.value;
|
|
897
|
+
onProgress?.({
|
|
898
|
+
action: "emit",
|
|
899
|
+
kind: "spanEnd",
|
|
900
|
+
spanId: "resolveSource",
|
|
901
|
+
outcome: "ok"
|
|
902
|
+
});
|
|
903
|
+
} catch (error) {
|
|
904
|
+
onProgress?.({
|
|
905
|
+
action: "emit",
|
|
906
|
+
kind: "spanEnd",
|
|
907
|
+
spanId: "resolveSource",
|
|
908
|
+
outcome: "error"
|
|
909
|
+
});
|
|
910
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
911
|
+
return notOk({
|
|
912
|
+
code: "CONTRACT_SOURCE_INVALID",
|
|
913
|
+
summary: "Failed to resolve contract source",
|
|
914
|
+
why: message,
|
|
915
|
+
diagnostics: {
|
|
916
|
+
summary: "Contract source provider threw an exception",
|
|
917
|
+
diagnostics: [{
|
|
918
|
+
code: "PROVIDER_THROW",
|
|
919
|
+
message
|
|
920
|
+
}]
|
|
921
|
+
},
|
|
922
|
+
meta: void 0
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
onProgress?.({
|
|
926
|
+
action: "emit",
|
|
927
|
+
kind: "spanStart",
|
|
928
|
+
spanId: "emit",
|
|
929
|
+
label: "Emitting contract..."
|
|
930
|
+
});
|
|
931
|
+
try {
|
|
932
|
+
try {
|
|
933
|
+
this.familyInstance.validateContractIR(contractRaw);
|
|
934
|
+
} catch (error) {
|
|
935
|
+
onProgress?.({
|
|
936
|
+
action: "emit",
|
|
937
|
+
kind: "spanEnd",
|
|
938
|
+
spanId: "emit",
|
|
939
|
+
outcome: "error"
|
|
940
|
+
});
|
|
941
|
+
return notOk({
|
|
942
|
+
code: "CONTRACT_VALIDATION_FAILED",
|
|
943
|
+
summary: "Contract validation failed",
|
|
944
|
+
why: error instanceof Error ? error.message : String(error),
|
|
945
|
+
meta: void 0
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
const emitResult = await this.familyInstance.emitContract({ contractIR: contractRaw });
|
|
949
|
+
onProgress?.({
|
|
950
|
+
action: "emit",
|
|
951
|
+
kind: "spanEnd",
|
|
952
|
+
spanId: "emit",
|
|
953
|
+
outcome: "ok"
|
|
954
|
+
});
|
|
955
|
+
return ok({
|
|
956
|
+
storageHash: emitResult.storageHash,
|
|
957
|
+
...ifDefined("executionHash", emitResult.executionHash),
|
|
958
|
+
profileHash: emitResult.profileHash,
|
|
959
|
+
contractJson: emitResult.contractJson,
|
|
960
|
+
contractDts: emitResult.contractDts
|
|
961
|
+
});
|
|
962
|
+
} catch (error) {
|
|
963
|
+
onProgress?.({
|
|
964
|
+
action: "emit",
|
|
965
|
+
kind: "spanEnd",
|
|
966
|
+
spanId: "emit",
|
|
967
|
+
outcome: "error"
|
|
968
|
+
});
|
|
969
|
+
return notOk({
|
|
970
|
+
code: "EMIT_FAILED",
|
|
971
|
+
summary: "Failed to emit contract",
|
|
972
|
+
why: error instanceof Error ? error.message : String(error),
|
|
973
|
+
meta: void 0
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
|
|
979
|
+
//#endregion
|
|
980
|
+
export { ContractValidationError as n, createControlClient as t };
|
|
981
|
+
//# sourceMappingURL=client-PimzSD1f.mjs.map
|