prisma-next 0.12.0-dev.4 → 0.12.0-dev.41
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 +180 -163
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-KgJorIvG.mjs → client-Dk-zRFuT.mjs} +83 -58
- package/dist/client-Dk-zRFuT.mjs.map +1 -0
- package/dist/{command-helpers-Bbw1GbwL.mjs → command-helpers-xvg9oq4T.mjs} +301 -23
- package/dist/command-helpers-xvg9oq4T.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.mjs +4 -5
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +3 -3
- package/dist/commands/db-sign.mjs +4 -4
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +10 -7
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +2 -2
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +6 -8
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.d.mts +55 -1
- package/dist/commands/migration-check.d.mts.map +1 -1
- package/dist/commands/migration-check.mjs +2 -2
- package/dist/commands/migration-graph.d.mts +25 -7
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +170 -2
- package/dist/commands/migration-graph.mjs.map +1 -0
- package/dist/commands/migration-list.d.mts +24 -26
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +2 -190
- package/dist/commands/migration-log.d.mts +20 -15
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +1 -137
- package/dist/commands/migration-new.mjs +3 -3
- package/dist/commands/migration-plan.d.mts +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +1 -4
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +13 -25
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +41 -141
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +2 -759
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.mjs +3 -3
- package/dist/commands/telemetry/index.d.mts +7 -0
- package/dist/commands/telemetry/index.d.mts.map +1 -0
- package/dist/commands/telemetry/index.mjs +2 -0
- package/dist/{contract-at-errors-BxP-TOMl.mjs → contract-at-errors-Wj3u4Xco.mjs} +2 -2
- package/dist/{contract-at-errors-BxP-TOMl.mjs.map → contract-at-errors-Wj3u4Xco.mjs.map} +1 -1
- package/dist/{contract-emit-DxcGl4Uq.mjs → contract-emit-CZU0UO6M.mjs} +3 -3
- package/dist/{contract-emit-DxcGl4Uq.mjs.map → contract-emit-CZU0UO6M.mjs.map} +1 -1
- package/dist/{contract-emit-D-4jrNve.mjs → contract-emit-FetLZ3jn.mjs} +5 -5
- package/dist/{contract-emit-D-4jrNve.mjs.map → contract-emit-FetLZ3jn.mjs.map} +1 -1
- package/dist/{contract-infer-D8uEbJuu.mjs → contract-infer-3wtOsS_H.mjs} +3 -3
- package/dist/{contract-infer-D8uEbJuu.mjs.map → contract-infer-3wtOsS_H.mjs.map} +1 -1
- package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs → contract-space-aggregate-loader-BdRPfM3Q.mjs} +63 -5
- package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs.map → contract-space-aggregate-loader-BdRPfM3Q.mjs.map} +1 -1
- package/dist/{db-verify-v_vUKXTU.mjs → db-verify-BisylXFZ.mjs} +4 -4
- package/dist/{db-verify-v_vUKXTU.mjs.map → db-verify-BisylXFZ.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +2 -2
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +2 -2
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{framework-components-fYXjz_in.mjs → framework-components-Be4inY3I.mjs} +2 -2
- package/dist/{framework-components-fYXjz_in.mjs.map → framework-components-Be4inY3I.mjs.map} +1 -1
- package/dist/{global-flags-DEHjV8_s.d.mts → global-flags-DG4uY5tV.d.mts} +1 -1
- package/dist/{global-flags-DEHjV8_s.d.mts.map → global-flags-DG4uY5tV.d.mts.map} +1 -1
- package/dist/{init-Cv9UzWL5.mjs → init-BTE2U7lG.mjs} +5 -58
- package/dist/init-BTE2U7lG.mjs.map +1 -0
- package/dist/{inspect-live-schema-C6ohV_oQ.mjs → inspect-live-schema-Cy9Y4wsL.mjs} +3 -3
- package/dist/{inspect-live-schema-C6ohV_oQ.mjs.map → inspect-live-schema-Cy9Y4wsL.mjs.map} +1 -1
- package/dist/{migration-check-BiBJoYYW.mjs → migration-check-CUavU7U9.mjs} +236 -88
- package/dist/migration-check-CUavU7U9.mjs.map +1 -0
- package/dist/{migration-command-scaffold-CjvwO6at.mjs → migration-command-scaffold-BxOxtyJ6.mjs} +3 -3
- package/dist/{migration-command-scaffold-CjvwO6at.mjs.map → migration-command-scaffold-BxOxtyJ6.mjs.map} +1 -1
- package/dist/migration-graph-space-render-ByJ83gxp.mjs +1966 -0
- package/dist/migration-graph-space-render-ByJ83gxp.mjs.map +1 -0
- package/dist/migration-list-jK6QeczE.mjs +228 -0
- package/dist/migration-list-jK6QeczE.mjs.map +1 -0
- package/dist/migration-list-types-DS63IdFd.d.mts +23 -0
- package/dist/migration-list-types-DS63IdFd.d.mts.map +1 -0
- package/dist/migration-log-DWI6dZyi.mjs +215 -0
- package/dist/migration-log-DWI6dZyi.mjs.map +1 -0
- package/dist/migration-path-target-DqcrbOis.mjs +24 -0
- package/dist/migration-path-target-DqcrbOis.mjs.map +1 -0
- package/dist/{migration-plan-9DJ7q7_z.mjs → migration-plan-NHdlUwPG.mjs} +5 -6
- package/dist/{migration-plan-9DJ7q7_z.mjs.map → migration-plan-NHdlUwPG.mjs.map} +1 -1
- package/dist/migration-status-DI6Ldjbo.mjs +439 -0
- package/dist/migration-status-DI6Ldjbo.mjs.map +1 -0
- package/dist/{output-B60Gw5fu.mjs → output-CF_hqzI-.mjs} +1 -1
- package/dist/{output-B60Gw5fu.mjs.map → output-CF_hqzI-.mjs.map} +1 -1
- package/dist/{ref-advancement-DUZqsue6.mjs → ref-advancement-CJY9zOv7.mjs} +1 -1
- package/dist/{ref-advancement-DUZqsue6.mjs.map → ref-advancement-CJY9zOv7.mjs.map} +1 -1
- package/dist/telemetry-DQP0BvKv.mjs +122 -0
- package/dist/telemetry-DQP0BvKv.mjs.map +1 -0
- package/dist/{types-Dt_SfqFm.d.mts → types-Cculk5KV.d.mts} +44 -31
- package/dist/types-Cculk5KV.d.mts.map +1 -0
- package/dist/{verify-DCA9Sldu.mjs → verify-tvHRBBVP.mjs} +2 -2
- package/dist/{verify-DCA9Sldu.mjs.map → verify-tvHRBBVP.mjs.map} +1 -1
- package/package.json +11 -12
- package/dist/client-KgJorIvG.mjs.map +0 -1
- package/dist/command-helpers-Bbw1GbwL.mjs.map +0 -1
- package/dist/commands/migration-list.mjs.map +0 -1
- package/dist/commands/migration-log.mjs.map +0 -1
- package/dist/commands/migration-status.mjs.map +0 -1
- package/dist/extension-pack-inputs-IDvjRCi3.mjs +0 -62
- package/dist/extension-pack-inputs-IDvjRCi3.mjs.map +0 -1
- package/dist/graph-render-rFAqZujX.mjs +0 -1081
- package/dist/graph-render-rFAqZujX.mjs.map +0 -1
- package/dist/init-Cv9UzWL5.mjs.map +0 -1
- package/dist/migration-check-BiBJoYYW.mjs.map +0 -1
- package/dist/migration-graph-D7DVUElV.mjs +0 -1232
- package/dist/migration-graph-D7DVUElV.mjs.map +0 -1
- package/dist/migration-list-styler-BRwF4-gy.mjs +0 -399
- package/dist/migration-list-styler-BRwF4-gy.mjs.map +0 -1
- package/dist/migration-types-D2FW63pr.d.mts +0 -15
- package/dist/migration-types-D2FW63pr.d.mts.map +0 -1
- package/dist/migrations-Cv2jxNNK.mjs +0 -228
- package/dist/migrations-Cv2jxNNK.mjs.map +0 -1
- package/dist/types-Dt_SfqFm.d.mts.map +0 -1
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { t as loadConfig } from "./config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { A as formatStyledHeader, G as errorInvalidSpaceId, _ as createTerminalUI, b as formatErrorJson, d as setCommandSeeAlso, g as parseGlobalFlagsOrExit, it as errorSpaceNotFound, l as setCommandDescriptions, lt as mapRefResolutionError, o as resolveContractPath, s as resolveMigrationPaths, t as addGlobalOptions, u as setCommandExamples, x as formatErrorOutput } from "./command-helpers-xvg9oq4T.mjs";
|
|
3
|
+
import { n as buildReadAggregate, s as toDeclaredExtensionsFromRaw } from "./contract-space-aggregate-loader-BdRPfM3Q.mjs";
|
|
4
|
+
import { n as looksLikePath, r as resolveAppTargetPath, t as findPackageByDirPath } from "./migration-path-target-DqcrbOis.mjs";
|
|
4
5
|
import { Command } from "commander";
|
|
6
|
+
import { notOk, ok } from "@prisma-next/utils/result";
|
|
5
7
|
import { join, relative } from "pathe";
|
|
6
8
|
import { readFile } from "node:fs/promises";
|
|
7
9
|
import { createControlStack } from "@prisma-next/framework-components/control";
|
|
10
|
+
import { RESERVED_SPACE_SUBDIR_NAMES, isValidSpaceId, listContractSpaceDirectories, spaceMigrationDirectory, spaceRefsDirectory } from "@prisma-next/migration-tools/spaces";
|
|
8
11
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
9
12
|
import { loadContractSpaceAggregate } from "@prisma-next/migration-tools/aggregate";
|
|
10
13
|
import { reconstructGraph } from "@prisma-next/migration-tools/migration-graph";
|
|
@@ -146,6 +149,116 @@ function checkSnapshotConsistency(pkg) {
|
|
|
146
149
|
}
|
|
147
150
|
return null;
|
|
148
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Project the loaded {@link ContractSpaceAggregate} into the
|
|
154
|
+
* {@link CheckSpace} rows the multi-space check iterates — one per on-disk
|
|
155
|
+
* contract-space directory, in the aggregate's `app`-first ordering. Mirrors
|
|
156
|
+
* `migration list`'s `migrationSpaceListEntriesFromAggregate`: space
|
|
157
|
+
* membership matches the on-disk directories, package / ref / graph data come
|
|
158
|
+
* from `aggregate.space(id)`.
|
|
159
|
+
*/
|
|
160
|
+
async function enumerateCheckSpaces(aggregate, projectMigrationsDir) {
|
|
161
|
+
const candidateDirs = await listContractSpaceDirectories(projectMigrationsDir);
|
|
162
|
+
const onDiskSpaceIds = new Set(candidateDirs.filter((name) => !RESERVED_SPACE_SUBDIR_NAMES.has(name)).filter(isValidSpaceId));
|
|
163
|
+
const spaces = [];
|
|
164
|
+
for (const member of aggregate.spaces()) {
|
|
165
|
+
const spaceId = member.spaceId;
|
|
166
|
+
if (!isValidSpaceId(spaceId)) continue;
|
|
167
|
+
if (!onDiskSpaceIds.has(spaceId)) continue;
|
|
168
|
+
const migrationsDir = spaceMigrationDirectory(projectMigrationsDir, spaceId);
|
|
169
|
+
spaces.push({
|
|
170
|
+
spaceId,
|
|
171
|
+
packages: member.packages,
|
|
172
|
+
refs: member.refs,
|
|
173
|
+
graph: member.graph(),
|
|
174
|
+
migrationsDir,
|
|
175
|
+
refsDir: spaceRefsDirectory(migrationsDir)
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return spaces;
|
|
179
|
+
}
|
|
180
|
+
function checkManifestFilesPresent(space) {
|
|
181
|
+
if (!existsSync(space.migrationsDir)) return [];
|
|
182
|
+
const loadedDirNames = new Set(space.packages.map((p) => p.dirName));
|
|
183
|
+
const failures = [];
|
|
184
|
+
let entries;
|
|
185
|
+
try {
|
|
186
|
+
entries = readdirSync(space.migrationsDir);
|
|
187
|
+
} catch {
|
|
188
|
+
return failures;
|
|
189
|
+
}
|
|
190
|
+
for (const entry of entries) {
|
|
191
|
+
if (entry.startsWith(".") || entry.startsWith("_") || entry === "refs") continue;
|
|
192
|
+
const entryPath = join(space.migrationsDir, entry);
|
|
193
|
+
try {
|
|
194
|
+
if (!statSync(entryPath).isDirectory()) continue;
|
|
195
|
+
} catch {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (!loadedDirNames.has(entry)) for (const f of ["migration.json", "ops.json"]) {
|
|
199
|
+
const fail = checkFileExists(entryPath, entry, f);
|
|
200
|
+
if (fail) failures.push(fail);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return failures;
|
|
204
|
+
}
|
|
205
|
+
function checkReachability(space) {
|
|
206
|
+
const allToHashes = new Set(space.packages.map((p) => p.metadata.to));
|
|
207
|
+
const failures = [];
|
|
208
|
+
for (const pkg of space.packages) if (!(pkg.metadata.from === null || allToHashes.has(pkg.metadata.from) || pkg.metadata.from === "sha256:empty")) failures.push({
|
|
209
|
+
pnCode: "PN-MIG-CHECK-003",
|
|
210
|
+
where: migrationPathRelative(pkg.dirPath),
|
|
211
|
+
why: `Migration "${pkg.dirName}" starts from ${pkg.metadata.from} which no other migration produces`,
|
|
212
|
+
fix: "This migration is unreachable in the graph. Delete it or re-emit a connecting migration."
|
|
213
|
+
});
|
|
214
|
+
return failures;
|
|
215
|
+
}
|
|
216
|
+
function checkDanglingRefs(space) {
|
|
217
|
+
const failures = [];
|
|
218
|
+
for (const [name, entry] of Object.entries(space.refs)) if (!space.graph.nodes.has(entry.hash)) failures.push({
|
|
219
|
+
pnCode: "PN-MIG-CHECK-004",
|
|
220
|
+
where: relative(process.cwd(), join(space.refsDir, `${name}.json`)),
|
|
221
|
+
why: `Ref "${name}" points at ${entry.hash} which does not exist in the migration graph`,
|
|
222
|
+
fix: `Update the ref with \`prisma-next ref set ${name} <valid-hash>\` or delete it.`
|
|
223
|
+
});
|
|
224
|
+
return failures;
|
|
225
|
+
}
|
|
226
|
+
function checkSpace(space) {
|
|
227
|
+
return [
|
|
228
|
+
...checkManifestFilesPresent(space),
|
|
229
|
+
...space.packages.map(checkSnapshotConsistency).filter((f) => f !== null),
|
|
230
|
+
...checkReachability(space),
|
|
231
|
+
...checkDanglingRefs(space)
|
|
232
|
+
];
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Policy core of the holistic `migration check`: validates `--space`,
|
|
236
|
+
* narrows the pre-enumerated spaces, and runs the per-space explicit graph
|
|
237
|
+
* checks (file-existence, snapshot consistency, reachability, dangling
|
|
238
|
+
* refs), aggregating every failure into one {@link MigrationCheckResult}.
|
|
239
|
+
*
|
|
240
|
+
* `--space` validation mirrors `migration list`: an invalid id →
|
|
241
|
+
* {@link errorInvalidSpaceId}; an id with no on-disk space →
|
|
242
|
+
* {@link errorSpaceNotFound}. Both map to exit `PRECONDITION` at the shell.
|
|
243
|
+
* Aggregate-integrity violations (which already span every space) are folded
|
|
244
|
+
* in by the caller, not here.
|
|
245
|
+
*/
|
|
246
|
+
function runMigrationCheck(inputs) {
|
|
247
|
+
const { spaces, spaceFilter } = inputs;
|
|
248
|
+
if (spaceFilter !== void 0 && !isValidSpaceId(spaceFilter)) return notOk(errorInvalidSpaceId(spaceFilter));
|
|
249
|
+
if (spaceFilter !== void 0 && !spaces.some((s) => s.spaceId === spaceFilter)) return notOk(errorSpaceNotFound(spaceFilter, spaces.map((s) => s.spaceId).sort()));
|
|
250
|
+
const failures = (spaceFilter !== void 0 ? spaces.filter((s) => s.spaceId === spaceFilter) : spaces).flatMap(checkSpace);
|
|
251
|
+
if (failures.length === 0) return ok({
|
|
252
|
+
ok: true,
|
|
253
|
+
failures: [],
|
|
254
|
+
summary: "All checks passed"
|
|
255
|
+
});
|
|
256
|
+
return ok({
|
|
257
|
+
ok: false,
|
|
258
|
+
failures,
|
|
259
|
+
summary: `${failures.length} integrity failure(s)`
|
|
260
|
+
});
|
|
261
|
+
}
|
|
149
262
|
async function loadAggregateIntegrityViolations(config, migrationsDir) {
|
|
150
263
|
try {
|
|
151
264
|
const contractJsonContent = await readFile(resolveContractPath(config), "utf-8");
|
|
@@ -187,86 +300,104 @@ async function executeMigrationCheckCommand(target, options, flags, ui) {
|
|
|
187
300
|
});
|
|
188
301
|
ui.stderr(header);
|
|
189
302
|
}
|
|
190
|
-
|
|
303
|
+
if (target) return await checkSingleTarget(target, {
|
|
304
|
+
appMigrationsDir,
|
|
305
|
+
appMigrationsRelative,
|
|
306
|
+
refsDir
|
|
307
|
+
});
|
|
308
|
+
const loadedAggregate = await buildReadAggregate(config, { migrationsDir });
|
|
309
|
+
if (!loadedAggregate.ok) return {
|
|
310
|
+
error: loadedAggregate.failure,
|
|
311
|
+
exitCode: 2
|
|
312
|
+
};
|
|
313
|
+
const checkResult = runMigrationCheck({
|
|
314
|
+
spaces: await enumerateCheckSpaces(loadedAggregate.value.aggregate, migrationsDir),
|
|
315
|
+
...options.space !== void 0 ? { spaceFilter: options.space } : {}
|
|
316
|
+
});
|
|
317
|
+
if (!checkResult.ok) return {
|
|
318
|
+
error: checkResult.failure,
|
|
319
|
+
exitCode: 2
|
|
320
|
+
};
|
|
321
|
+
const failures = [...checkResult.value.failures];
|
|
322
|
+
const allViolations = await loadAggregateIntegrityViolations(config, migrationsDir);
|
|
323
|
+
const scopedViolations = options.space === void 0 ? allViolations : allViolations.filter((v) => v.kind !== "disjointness" && v.spaceId === options.space);
|
|
324
|
+
for (const violation of scopedViolations) failures.push(integrityViolationToCheckFailure(violation, migrationsDir));
|
|
325
|
+
if (failures.length === 0) return {
|
|
326
|
+
result: {
|
|
327
|
+
ok: true,
|
|
328
|
+
failures: [],
|
|
329
|
+
summary: "All checks passed"
|
|
330
|
+
},
|
|
331
|
+
exitCode: 0
|
|
332
|
+
};
|
|
333
|
+
return {
|
|
334
|
+
result: {
|
|
335
|
+
ok: false,
|
|
336
|
+
failures,
|
|
337
|
+
summary: `${failures.length} integrity failure(s)`
|
|
338
|
+
},
|
|
339
|
+
exitCode: 4
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Single-target (`check <ref/path>`) mode — app-space only by design (the
|
|
344
|
+
* migration's space is pinned by the reference; multi-space single-target
|
|
345
|
+
* resolution is a deliberate follow-up, see the slice spec § Out of scope).
|
|
346
|
+
* Resolves the one referenced package and verifies its hash / manifest /
|
|
347
|
+
* snapshot, plus the app-space orphan-manifest check the prior behaviour ran.
|
|
348
|
+
*/
|
|
349
|
+
async function checkSingleTarget(target, paths) {
|
|
350
|
+
const { appMigrationsDir, appMigrationsRelative, refsDir } = paths;
|
|
191
351
|
const bundles = (await readMigrationsDir(appMigrationsDir)).packages;
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
} catch {}
|
|
211
|
-
}
|
|
212
|
-
if (target) {
|
|
352
|
+
const appSpace = {
|
|
353
|
+
spaceId: "app",
|
|
354
|
+
packages: bundles,
|
|
355
|
+
refs: await readRefs(refsDir),
|
|
356
|
+
graph: reconstructGraph(bundles),
|
|
357
|
+
migrationsDir: appMigrationsDir,
|
|
358
|
+
refsDir
|
|
359
|
+
};
|
|
360
|
+
const failures = [...checkManifestFilesPresent(appSpace)];
|
|
361
|
+
let matchedPkg;
|
|
362
|
+
if (looksLikePath(target)) {
|
|
363
|
+
const resolved = resolveAppTargetPath(target, appMigrationsDir, appMigrationsRelative);
|
|
364
|
+
if (!resolved.ok) return {
|
|
365
|
+
error: resolved.failure,
|
|
366
|
+
exitCode: 2
|
|
367
|
+
};
|
|
368
|
+
matchedPkg = findPackageByDirPath(bundles, resolved.value);
|
|
369
|
+
} else {
|
|
213
370
|
const migResult = parseMigrationRef(target, {
|
|
214
|
-
graph,
|
|
215
|
-
refs:
|
|
371
|
+
graph: appSpace.graph,
|
|
372
|
+
refs: appSpace.refs
|
|
216
373
|
});
|
|
217
374
|
if (!migResult.ok) return {
|
|
218
|
-
|
|
219
|
-
ok: false,
|
|
220
|
-
failures: [],
|
|
221
|
-
summary: migResult.failure.kind === "not-found" ? `Migration "${target}" does not exist` : migResult.failure.kind === "wrong-grammar" ? migResult.failure.message : `Invalid migration reference: "${target}"`
|
|
222
|
-
},
|
|
375
|
+
error: mapRefResolutionError(migResult.failure),
|
|
223
376
|
exitCode: 2
|
|
224
377
|
};
|
|
225
|
-
|
|
226
|
-
if (!matchedPkg) return {
|
|
227
|
-
result: {
|
|
228
|
-
ok: false,
|
|
229
|
-
failures: [],
|
|
230
|
-
summary: `Migration package for "${target}" not found on disk`
|
|
231
|
-
},
|
|
232
|
-
exitCode: 2
|
|
233
|
-
};
|
|
234
|
-
for (const f of ["migration.json", "ops.json"]) {
|
|
235
|
-
const fail = checkFileExists(matchedPkg.dirPath, matchedPkg.dirName, f);
|
|
236
|
-
if (fail) failures.push(fail);
|
|
237
|
-
}
|
|
238
|
-
const verification = verifyMigrationHash(matchedPkg);
|
|
239
|
-
if (!verification.ok) failures.push({
|
|
240
|
-
pnCode: "PN-MIG-CHECK-001",
|
|
241
|
-
where: migrationFileRelative(matchedPkg.dirPath, "migration.json"),
|
|
242
|
-
why: `Stored hash ${verification.storedHash} does not match recomputed hash ${verification.computedHash}`,
|
|
243
|
-
fix: "Re-emit the migration package or restore from version control."
|
|
244
|
-
});
|
|
245
|
-
const snapshotFailure = checkSnapshotConsistency(matchedPkg);
|
|
246
|
-
if (snapshotFailure) failures.push(snapshotFailure);
|
|
247
|
-
} else {
|
|
248
|
-
for (const pkg of bundles) {
|
|
249
|
-
const snapshotFailure = checkSnapshotConsistency(pkg);
|
|
250
|
-
if (snapshotFailure) failures.push(snapshotFailure);
|
|
251
|
-
}
|
|
252
|
-
const allToHashes = new Set(bundles.map((p) => p.metadata.to));
|
|
253
|
-
for (const pkg of bundles) if (!(pkg.metadata.from === null || allToHashes.has(pkg.metadata.from) || pkg.metadata.from === "sha256:empty")) failures.push({
|
|
254
|
-
pnCode: "PN-MIG-CHECK-003",
|
|
255
|
-
where: migrationPathRelative(pkg.dirPath),
|
|
256
|
-
why: `Migration "${pkg.dirName}" starts from ${pkg.metadata.from} which no other migration produces`,
|
|
257
|
-
fix: "This migration is unreachable in the graph. Delete it or re-emit a connecting migration."
|
|
258
|
-
});
|
|
259
|
-
try {
|
|
260
|
-
const refs = await readRefs(refsDir);
|
|
261
|
-
for (const [name, entry] of Object.entries(refs)) if (!graph.nodes.has(entry.hash)) failures.push({
|
|
262
|
-
pnCode: "PN-MIG-CHECK-004",
|
|
263
|
-
where: relative(process.cwd(), join(refsDir, `${name}.json`)),
|
|
264
|
-
why: `Ref "${name}" points at ${entry.hash} which does not exist in the migration graph`,
|
|
265
|
-
fix: `Update the ref with \`prisma-next ref set ${name} <valid-hash>\` or delete it.`
|
|
266
|
-
});
|
|
267
|
-
} catch {}
|
|
268
|
-
for (const violation of await loadAggregateIntegrityViolations(config, migrationsDir)) failures.push(integrityViolationToCheckFailure(violation, migrationsDir));
|
|
378
|
+
matchedPkg = bundles.find((p) => p.metadata.migrationHash === migResult.value.migrationHash);
|
|
269
379
|
}
|
|
380
|
+
if (!matchedPkg) return {
|
|
381
|
+
result: {
|
|
382
|
+
ok: false,
|
|
383
|
+
failures: [],
|
|
384
|
+
summary: `Migration package for "${target}" not found on disk`
|
|
385
|
+
},
|
|
386
|
+
exitCode: 2
|
|
387
|
+
};
|
|
388
|
+
for (const f of ["migration.json", "ops.json"]) {
|
|
389
|
+
const fail = checkFileExists(matchedPkg.dirPath, matchedPkg.dirName, f);
|
|
390
|
+
if (fail) failures.push(fail);
|
|
391
|
+
}
|
|
392
|
+
const verification = verifyMigrationHash(matchedPkg);
|
|
393
|
+
if (!verification.ok) failures.push({
|
|
394
|
+
pnCode: "PN-MIG-CHECK-001",
|
|
395
|
+
where: migrationFileRelative(matchedPkg.dirPath, "migration.json"),
|
|
396
|
+
why: `Stored hash ${verification.storedHash} does not match recomputed hash ${verification.computedHash}`,
|
|
397
|
+
fix: "Re-emit the migration package or restore from version control."
|
|
398
|
+
});
|
|
399
|
+
const snapshotFailure = checkSnapshotConsistency(matchedPkg);
|
|
400
|
+
if (snapshotFailure) failures.push(snapshotFailure);
|
|
270
401
|
if (failures.length === 0) return {
|
|
271
402
|
result: {
|
|
272
403
|
ok: true,
|
|
@@ -286,9 +417,10 @@ async function executeMigrationCheckCommand(target, options, flags, ui) {
|
|
|
286
417
|
}
|
|
287
418
|
function createMigrationCheckCommand() {
|
|
288
419
|
const command = new Command("check");
|
|
289
|
-
setCommandDescriptions(command, "Verify artifact and graph integrity", "Validates that on-disk migration packages are internally consistent\n(hashes match, manifests are complete) and that the graph is well-formed\n(edges connect, refs point at valid nodes).
|
|
420
|
+
setCommandDescriptions(command, "Verify artifact and graph integrity", "Validates that on-disk migration packages are internally consistent\n(hashes match, manifests are complete) and that the graph is well-formed\n(edges connect, refs point at valid nodes). The whole-graph check spans\nevery contract space by default; pass --space <id> to narrow to one, or\na migration reference to check a single app-space package.\nOffline — does not consult the database.\nExit codes: 0 = all checks passed, 2 = precondition failed\n(unresolved target or unknown --space), 4 = integrity failure(s) found.");
|
|
290
421
|
setCommandExamples(command, [
|
|
291
422
|
"prisma-next migration check",
|
|
423
|
+
"prisma-next migration check --space app",
|
|
292
424
|
"prisma-next migration check 20260101-add-users",
|
|
293
425
|
"prisma-next migration check --json"
|
|
294
426
|
]);
|
|
@@ -304,24 +436,40 @@ function createMigrationCheckCommand() {
|
|
|
304
436
|
{
|
|
305
437
|
verb: "migration graph",
|
|
306
438
|
oneLiner: "Show the migration graph topology"
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
verb: "migration show",
|
|
442
|
+
oneLiner: "Display migration package contents"
|
|
307
443
|
}
|
|
308
444
|
]);
|
|
309
445
|
command.exitOverride();
|
|
310
|
-
addGlobalOptions(command).argument("[
|
|
446
|
+
addGlobalOptions(command).argument("[target]", "Migration reference: directory name, hash/prefix, ref, or path").option("--config <path>", "Path to prisma-next.config.ts").option("--space <id>", "Narrow output to a single contract space").action(async (target, options) => {
|
|
311
447
|
const flags = parseGlobalFlagsOrExit(options);
|
|
312
448
|
const ui = createTerminalUI(flags);
|
|
313
|
-
let
|
|
314
|
-
let exitCode;
|
|
449
|
+
let outcome;
|
|
315
450
|
try {
|
|
316
|
-
|
|
451
|
+
outcome = await executeMigrationCheckCommand(target, options, flags, ui);
|
|
317
452
|
} catch (error) {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
453
|
+
outcome = {
|
|
454
|
+
result: {
|
|
455
|
+
ok: false,
|
|
456
|
+
failures: [],
|
|
457
|
+
summary: error instanceof Error ? error.message : String(error)
|
|
458
|
+
},
|
|
459
|
+
exitCode: 2
|
|
322
460
|
};
|
|
323
|
-
exitCode = 2;
|
|
324
461
|
}
|
|
462
|
+
if (outcome.error) {
|
|
463
|
+
const envelope = outcome.error.toEnvelope();
|
|
464
|
+
if (flags.json) ui.output(formatErrorJson(envelope));
|
|
465
|
+
else if (!flags.quiet) ui.error(formatErrorOutput(envelope, flags));
|
|
466
|
+
process.exit(outcome.exitCode);
|
|
467
|
+
}
|
|
468
|
+
const result = outcome.result ?? {
|
|
469
|
+
ok: false,
|
|
470
|
+
failures: [],
|
|
471
|
+
summary: "No check result produced"
|
|
472
|
+
};
|
|
325
473
|
if (flags.json) ui.output(JSON.stringify(result, null, 2));
|
|
326
474
|
else if (!flags.quiet) if (result.ok) ui.log(`✔ ${result.summary}`);
|
|
327
475
|
else {
|
|
@@ -331,11 +479,11 @@ function createMigrationCheckCommand() {
|
|
|
331
479
|
}
|
|
332
480
|
ui.log(`\n${result.summary}`);
|
|
333
481
|
}
|
|
334
|
-
process.exit(exitCode);
|
|
482
|
+
process.exit(outcome.exitCode);
|
|
335
483
|
});
|
|
336
484
|
return command;
|
|
337
485
|
}
|
|
338
486
|
//#endregion
|
|
339
|
-
export { createMigrationCheckCommand as t };
|
|
487
|
+
export { enumerateCheckSpaces as n, runMigrationCheck as r, createMigrationCheckCommand as t };
|
|
340
488
|
|
|
341
|
-
//# sourceMappingURL=migration-check-
|
|
489
|
+
//# sourceMappingURL=migration-check-CUavU7U9.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-check-CUavU7U9.mjs","names":["migrationPathRelative","migrationFileRelative"],"sources":["../src/utils/integrity-violation-to-check-failure.ts","../src/commands/migration-check.ts"],"sourcesContent":["import type { IntegrityViolation } from '@prisma-next/migration-tools/aggregate';\nimport { join, relative } from 'pathe';\n\nexport interface CheckFailure {\n readonly pnCode: string;\n readonly where: string;\n readonly why: string;\n readonly fix: string;\n}\n\nfunction migrationPathRelative(dirPath: string): string {\n return relative(process.cwd(), dirPath);\n}\n\nfunction migrationFileRelative(dirPath: string, fileName: string): string {\n return join(migrationPathRelative(dirPath), fileName);\n}\n\n/**\n * Map one {@link IntegrityViolation} onto a `migration check` failure row.\n * Sole catalogue mapping from integrity violations to `PN-MIG-CHECK-*`.\n */\nexport function integrityViolationToCheckFailure(\n violation: IntegrityViolation,\n migrationsDir: string,\n): CheckFailure {\n const spaceRelative = (spaceId: string): string =>\n migrationPathRelative(join(migrationsDir, spaceId));\n const packageRelative = (spaceId: string, dirName: string): string =>\n migrationPathRelative(join(migrationsDir, spaceId, dirName));\n const refRelative = (spaceId: string, refName: string): string =>\n migrationPathRelative(join(migrationsDir, spaceId, 'refs', `${refName}.json`));\n\n switch (violation.kind) {\n case 'hashMismatch':\n return {\n pnCode: 'PN-MIG-CHECK-001',\n where: migrationFileRelative(\n join(migrationsDir, violation.spaceId, violation.dirName),\n 'migration.json',\n ),\n why: `Stored hash ${violation.stored} does not match recomputed hash ${violation.computed}`,\n fix: 'Re-emit the migration package or restore from version control.',\n };\n case 'providedInvariantsMismatch':\n return {\n pnCode: 'PN-MIG-CHECK-002',\n where: packageRelative(violation.spaceId, violation.dirName),\n why: `Migration \"${violation.dirName}\" providedInvariants in migration.json disagrees with ops.json.`,\n fix: 'Re-emit the migration package so migration.json and ops.json agree.',\n };\n case 'packageUnloadable':\n return {\n pnCode: 'PN-MIG-CHECK-002',\n where: packageRelative(violation.spaceId, violation.dirName),\n why: `Migration \"${violation.dirName}\" could not be loaded: ${violation.detail}`,\n fix: 'Re-emit the migration package or restore from version control.',\n };\n case 'sameSourceAndTarget':\n return {\n pnCode: 'PN-MIG-CHECK-007',\n where: packageRelative(violation.spaceId, violation.dirName),\n why: `Migration \"${violation.dirName}\" in space \"${violation.spaceId}\" has source equal to target (${violation.hash}) with no data invariant — a true no-op self-edge.`,\n fix: 'Add a data operation if this self-edge was meant to carry a data invariant, or delete the migration if it is a true no-op.',\n };\n case 'orphanSpaceDir':\n return {\n pnCode: 'PN-MIG-CHECK-008',\n where: spaceRelative(violation.spaceId),\n why: `Contract-space directory \"${violation.spaceId}\" exists on disk but no extension declares it.`,\n fix: 'Remove the orphan directory, or declare the extension in `extensionPacks`.',\n };\n case 'declaredButUnmigrated':\n return {\n pnCode: 'PN-MIG-CHECK-009',\n where: spaceRelative(violation.spaceId),\n why: `Extension \"${violation.spaceId}\" is declared in \\`extensionPacks\\` but has no on-disk migrations directory.`,\n fix: 'Re-emit the extension contract-space artefacts with `prisma-next contract emit` and migration planning, or remove the extension from `extensionPacks` if it is unused.',\n };\n case 'headRefMissing':\n return {\n pnCode: 'PN-MIG-CHECK-010',\n where: refRelative(violation.spaceId, 'head'),\n why: `Head ref \\`refs/head.json\\` is missing for contract space \"${violation.spaceId}\".`,\n fix: 'Re-emit the contract-space migrations and head ref artefacts, or restore `refs/head.json` from version control.',\n };\n case 'headRefNotInGraph':\n return {\n pnCode: 'PN-MIG-CHECK-011',\n where: refRelative(violation.spaceId, 'head'),\n why: `Head ref ${violation.hash} for contract space \"${violation.spaceId}\" is not present in its migration graph.`,\n fix: 'Re-emit the contract space migrations, or restore the missing migration package.',\n };\n case 'refUnreadable':\n return {\n pnCode: 'PN-MIG-CHECK-012',\n where: refRelative(violation.spaceId, violation.refName),\n why: `Ref \"${violation.refName}\" for contract space \"${violation.spaceId}\" is unreadable: ${violation.detail}`,\n fix: 'Repair or remove the corrupt ref file.',\n };\n case 'targetMismatch':\n return {\n pnCode: 'PN-MIG-CHECK-013',\n where: spaceRelative(violation.spaceId),\n why: `Contract space \"${violation.spaceId}\" targets \"${violation.actual}\" but the project targets \"${violation.expected}\".`,\n fix: 'Update the extension to target the configured database, or change the project target.',\n };\n case 'disjointness':\n return {\n pnCode: 'PN-MIG-CHECK-014',\n where: migrationPathRelative(migrationsDir),\n why: `Storage element \"${violation.element}\" is claimed by multiple contract spaces: ${violation.claimedBy.join(', ')}.`,\n fix: 'Update the contracts so each storage element is owned by exactly one contract space.',\n };\n case 'contractUnreadable':\n return {\n pnCode: 'PN-MIG-CHECK-015',\n where: migrationFileRelative(join(migrationsDir, violation.spaceId), 'contract.json'),\n why: `Contract for space \"${violation.spaceId}\" is unreadable: ${violation.detail}`,\n fix: 'Re-emit the extension contract artefacts, or fix the descriptor producing the invalid contract.',\n };\n case 'duplicateMigrationHash':\n return {\n pnCode: 'PN-MIG-CHECK-016',\n where: spaceRelative(violation.spaceId),\n why: `Multiple migrations in space \"${violation.spaceId}\" share migrationHash \"${violation.migrationHash}\" (${violation.dirNames.join(', ')}).`,\n fix: 'Re-emit one of the conflicting packages so each migrationHash is unique.',\n };\n }\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { createControlStack } from '@prisma-next/framework-components/control';\nimport type {\n ContractSpaceAggregate,\n IntegrityViolation,\n} from '@prisma-next/migration-tools/aggregate';\nimport { loadContractSpaceAggregate } from '@prisma-next/migration-tools/aggregate';\nimport type { MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport { verifyMigrationHash } from '@prisma-next/migration-tools/hash';\nimport { readMigrationsDir } from '@prisma-next/migration-tools/io';\nimport { reconstructGraph } from '@prisma-next/migration-tools/migration-graph';\nimport type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';\nimport { parseMigrationRef } from '@prisma-next/migration-tools/ref-resolution';\nimport type { Refs } from '@prisma-next/migration-tools/refs';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport {\n isValidSpaceId,\n listContractSpaceDirectories,\n RESERVED_SPACE_SUBDIR_NAMES,\n spaceMigrationDirectory,\n spaceRefsDirectory,\n} from '@prisma-next/migration-tools/spaces';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join, relative } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliStructuredError,\n errorInvalidSpaceId,\n errorSpaceNotFound,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport { toDeclaredExtensionsFromRaw } from '../utils/extension-pack-inputs';\nimport { formatErrorJson, formatErrorOutput } from '../utils/formatters/errors';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport {\n type CheckFailure,\n integrityViolationToCheckFailure,\n} from '../utils/integrity-violation-to-check-failure';\nimport {\n findPackageByDirPath,\n looksLikePath,\n resolveAppTargetPath,\n} from '../utils/migration-path-target';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\nimport { INTEGRITY_FAILED, OK, PRECONDITION } from './migration-check/exit-codes';\n\ninterface MigrationCheckOptions extends CommonCommandOptions {\n readonly config?: string;\n readonly space?: string;\n}\n\nexport type { CheckFailure } from '../utils/integrity-violation-to-check-failure';\n\nexport interface MigrationCheckResult {\n readonly ok: boolean;\n readonly failures: readonly CheckFailure[];\n readonly summary: string;\n}\n\nfunction migrationPathRelative(dirPath: string): string {\n return relative(process.cwd(), dirPath);\n}\n\nfunction migrationFileRelative(dirPath: string, fileName: string): string {\n return join(migrationPathRelative(dirPath), fileName);\n}\n\nfunction checkFileExists(dirPath: string, dirName: string, fileName: string): CheckFailure | null {\n if (!existsSync(join(dirPath, fileName))) {\n return {\n pnCode: 'PN-MIG-CHECK-002',\n where: migrationFileRelative(dirPath, fileName),\n why: `${fileName} is missing from ${dirName}`,\n fix: 'Re-emit the migration package or restore from version control.',\n };\n }\n return null;\n}\n\nfunction checkSnapshotConsistency(pkg: OnDiskMigrationPackage): CheckFailure | null {\n const endContractPath = join(pkg.dirPath, 'end-contract.json');\n if (!existsSync(endContractPath)) return null;\n try {\n const raw = JSON.parse(readFileSync(endContractPath, 'utf-8')) as Record<string, unknown>;\n const storage = raw['storage'] as Record<string, unknown> | undefined;\n const snapshotHash = storage?.['storageHash'];\n if (typeof snapshotHash === 'string' && snapshotHash !== pkg.metadata.to) {\n return {\n pnCode: 'PN-MIG-CHECK-005',\n where: migrationPathRelative(pkg.dirPath),\n why: `Migration \"${pkg.dirName}\" declares to=${pkg.metadata.to} but end-contract.json has storageHash=${snapshotHash}`,\n fix: 'Re-emit the migration package so migration.json and end-contract.json agree.',\n };\n }\n } catch {\n return {\n pnCode: 'PN-MIG-CHECK-006',\n where: migrationPathRelative(pkg.dirPath),\n why: `Migration \"${pkg.dirName}\" has an unparseable end-contract.json.`,\n fix: 'Re-emit the migration package to repair the snapshot file.',\n };\n }\n return null;\n}\n\n/**\n * One contract space's on-disk state, resolved for the explicit graph\n * checks `runMigrationCheck` runs per space: the space's migration\n * packages, its user-authored refs, its induced graph, and the absolute\n * `migrations/<space>/` + `migrations/<space>/refs/` directories the\n * file-existence and dangling-ref `where` paths are derived from.\n */\nexport interface CheckSpace {\n readonly spaceId: string;\n readonly packages: readonly OnDiskMigrationPackage[];\n readonly refs: Refs;\n readonly graph: MigrationGraph;\n readonly migrationsDir: string;\n readonly refsDir: string;\n}\n\n/**\n * Project the loaded {@link ContractSpaceAggregate} into the\n * {@link CheckSpace} rows the multi-space check iterates — one per on-disk\n * contract-space directory, in the aggregate's `app`-first ordering. Mirrors\n * `migration list`'s `migrationSpaceListEntriesFromAggregate`: space\n * membership matches the on-disk directories, package / ref / graph data come\n * from `aggregate.space(id)`.\n */\nexport async function enumerateCheckSpaces(\n aggregate: ContractSpaceAggregate,\n projectMigrationsDir: string,\n): Promise<readonly CheckSpace[]> {\n const candidateDirs = await listContractSpaceDirectories(projectMigrationsDir);\n const onDiskSpaceIds = new Set(\n candidateDirs.filter((name) => !RESERVED_SPACE_SUBDIR_NAMES.has(name)).filter(isValidSpaceId),\n );\n const spaces: CheckSpace[] = [];\n for (const member of aggregate.spaces()) {\n const spaceId = member.spaceId;\n if (!isValidSpaceId(spaceId)) continue;\n if (!onDiskSpaceIds.has(spaceId)) continue;\n const migrationsDir = spaceMigrationDirectory(projectMigrationsDir, spaceId);\n spaces.push({\n spaceId,\n packages: member.packages,\n refs: member.refs,\n graph: member.graph(),\n migrationsDir,\n refsDir: spaceRefsDirectory(migrationsDir),\n });\n }\n return spaces;\n}\n\nfunction checkManifestFilesPresent(space: CheckSpace): readonly CheckFailure[] {\n if (!existsSync(space.migrationsDir)) return [];\n const loadedDirNames = new Set(space.packages.map((p) => p.dirName));\n const failures: CheckFailure[] = [];\n let entries: string[];\n try {\n entries = readdirSync(space.migrationsDir);\n } catch {\n return failures;\n }\n for (const entry of entries) {\n if (entry.startsWith('.') || entry.startsWith('_') || entry === 'refs') continue;\n const entryPath = join(space.migrationsDir, entry);\n try {\n if (!statSync(entryPath).isDirectory()) continue;\n } catch {\n continue;\n }\n if (!loadedDirNames.has(entry)) {\n for (const f of ['migration.json', 'ops.json']) {\n const fail = checkFileExists(entryPath, entry, f);\n if (fail) failures.push(fail);\n }\n }\n }\n return failures;\n}\n\nfunction checkReachability(space: CheckSpace): readonly CheckFailure[] {\n const allToHashes = new Set(space.packages.map((p) => p.metadata.to));\n const failures: CheckFailure[] = [];\n for (const pkg of space.packages) {\n const isReachable =\n pkg.metadata.from === null ||\n allToHashes.has(pkg.metadata.from) ||\n pkg.metadata.from === 'sha256:empty';\n if (!isReachable) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-003',\n where: migrationPathRelative(pkg.dirPath),\n why: `Migration \"${pkg.dirName}\" starts from ${pkg.metadata.from} which no other migration produces`,\n fix: 'This migration is unreachable in the graph. Delete it or re-emit a connecting migration.',\n });\n }\n }\n return failures;\n}\n\nfunction checkDanglingRefs(space: CheckSpace): readonly CheckFailure[] {\n const failures: CheckFailure[] = [];\n for (const [name, entry] of Object.entries(space.refs)) {\n if (!space.graph.nodes.has(entry.hash)) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-004',\n where: relative(process.cwd(), join(space.refsDir, `${name}.json`)),\n why: `Ref \"${name}\" points at ${entry.hash} which does not exist in the migration graph`,\n fix: `Update the ref with \\`prisma-next ref set ${name} <valid-hash>\\` or delete it.`,\n });\n }\n }\n return failures;\n}\n\nfunction checkSpace(space: CheckSpace): readonly CheckFailure[] {\n return [\n ...checkManifestFilesPresent(space),\n ...space.packages.map(checkSnapshotConsistency).filter((f): f is CheckFailure => f !== null),\n ...checkReachability(space),\n ...checkDanglingRefs(space),\n ];\n}\n\n/**\n * Inputs for {@link runMigrationCheck} — the multi-space policy core of\n * the holistic (no-arg) `migration check`. Enumeration is supplied by the\n * caller (the CLI shell builds it from {@link enumerateCheckSpaces}); the\n * core does not touch config, flags, or streams.\n */\nexport interface RunMigrationCheckInputs {\n readonly spaces: readonly CheckSpace[];\n readonly spaceFilter?: string;\n}\n\n/**\n * Policy core of the holistic `migration check`: validates `--space`,\n * narrows the pre-enumerated spaces, and runs the per-space explicit graph\n * checks (file-existence, snapshot consistency, reachability, dangling\n * refs), aggregating every failure into one {@link MigrationCheckResult}.\n *\n * `--space` validation mirrors `migration list`: an invalid id →\n * {@link errorInvalidSpaceId}; an id with no on-disk space →\n * {@link errorSpaceNotFound}. Both map to exit `PRECONDITION` at the shell.\n * Aggregate-integrity violations (which already span every space) are folded\n * in by the caller, not here.\n */\nexport function runMigrationCheck(\n inputs: RunMigrationCheckInputs,\n): Result<MigrationCheckResult, CliStructuredError> {\n const { spaces, spaceFilter } = inputs;\n\n if (spaceFilter !== undefined && !isValidSpaceId(spaceFilter)) {\n return notOk(errorInvalidSpaceId(spaceFilter));\n }\n if (spaceFilter !== undefined && !spaces.some((s) => s.spaceId === spaceFilter)) {\n return notOk(errorSpaceNotFound(spaceFilter, spaces.map((s) => s.spaceId).sort()));\n }\n\n const scopedSpaces =\n spaceFilter !== undefined ? spaces.filter((s) => s.spaceId === spaceFilter) : spaces;\n\n const failures = scopedSpaces.flatMap(checkSpace);\n if (failures.length === 0) {\n return ok({ ok: true, failures: [], summary: 'All checks passed' });\n }\n return ok({ ok: false, failures, summary: `${failures.length} integrity failure(s)` });\n}\n\nasync function loadAggregateIntegrityViolations(\n config: Awaited<ReturnType<typeof loadConfig>>,\n migrationsDir: string,\n): Promise<readonly IntegrityViolation[]> {\n try {\n const contractJsonContent = await readFile(resolveContractPath(config), 'utf-8');\n const familyInstance = config.family.create(createControlStack(config));\n const declaredExtensions = toDeclaredExtensionsFromRaw(config.extensionPacks ?? []);\n\n const parsedAppContract: unknown = JSON.parse(contractJsonContent);\n const aggregate = await loadContractSpaceAggregate({\n migrationsDir,\n deserializeContract: (json: unknown) => familyInstance.deserializeContract(json),\n appContract: familyInstance.deserializeContract(parsedAppContract),\n });\n return aggregate.checkIntegrity({ declaredExtensions, checkContracts: true });\n } catch {\n return [];\n }\n}\n\ninterface MigrationCheckOutcome {\n readonly result?: MigrationCheckResult;\n readonly error?: CliStructuredError;\n readonly exitCode: number;\n}\n\nasync function executeMigrationCheckCommand(\n target: string | undefined,\n options: MigrationCheckOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<MigrationCheckOutcome> {\n const config = await loadConfig(options.config);\n const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative, refsDir } =\n resolveMigrationPaths(options.config, config);\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ];\n if (target) {\n details.push({ label: 'target', value: target });\n }\n const header = formatStyledHeader({\n command: 'migration check',\n description: 'Verify artifact and graph integrity',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n if (target) {\n return await checkSingleTarget(target, {\n appMigrationsDir,\n appMigrationsRelative,\n refsDir,\n });\n }\n\n const loadedAggregate = await buildReadAggregate(config, { migrationsDir });\n if (!loadedAggregate.ok) {\n return { error: loadedAggregate.failure, exitCode: PRECONDITION };\n }\n\n const spaces = await enumerateCheckSpaces(loadedAggregate.value.aggregate, migrationsDir);\n const checkResult = runMigrationCheck({\n spaces,\n ...(options.space !== undefined ? { spaceFilter: options.space } : {}),\n });\n if (!checkResult.ok) {\n return { error: checkResult.failure, exitCode: PRECONDITION };\n }\n\n const failures: CheckFailure[] = [...checkResult.value.failures];\n const allViolations = await loadAggregateIntegrityViolations(config, migrationsDir);\n const scopedViolations =\n options.space === undefined\n ? allViolations\n : allViolations.filter((v) => v.kind !== 'disjointness' && v.spaceId === options.space);\n for (const violation of scopedViolations) {\n failures.push(integrityViolationToCheckFailure(violation, migrationsDir));\n }\n\n if (failures.length === 0) {\n return {\n result: { ok: true, failures: [], summary: 'All checks passed' },\n exitCode: OK,\n };\n }\n\n return {\n result: { ok: false, failures, summary: `${failures.length} integrity failure(s)` },\n exitCode: INTEGRITY_FAILED,\n };\n}\n\ninterface SingleTargetPaths {\n readonly appMigrationsDir: string;\n readonly appMigrationsRelative: string;\n readonly refsDir: string;\n}\n\n/**\n * Single-target (`check <ref/path>`) mode — app-space only by design (the\n * migration's space is pinned by the reference; multi-space single-target\n * resolution is a deliberate follow-up, see the slice spec § Out of scope).\n * Resolves the one referenced package and verifies its hash / manifest /\n * snapshot, plus the app-space orphan-manifest check the prior behaviour ran.\n */\nasync function checkSingleTarget(\n target: string,\n paths: SingleTargetPaths,\n): Promise<MigrationCheckOutcome> {\n const { appMigrationsDir, appMigrationsRelative, refsDir } = paths;\n const loaded = await readMigrationsDir(appMigrationsDir);\n const bundles: readonly OnDiskMigrationPackage[] = loaded.packages;\n const appSpace: CheckSpace = {\n spaceId: 'app',\n packages: bundles,\n refs: await readRefs(refsDir),\n graph: reconstructGraph(bundles),\n migrationsDir: appMigrationsDir,\n refsDir,\n };\n\n const failures: CheckFailure[] = [...checkManifestFilesPresent(appSpace)];\n\n let matchedPkg: OnDiskMigrationPackage | undefined;\n if (looksLikePath(target)) {\n const resolved = resolveAppTargetPath(target, appMigrationsDir, appMigrationsRelative);\n if (!resolved.ok) {\n return { error: resolved.failure, exitCode: PRECONDITION };\n }\n matchedPkg = findPackageByDirPath(bundles, resolved.value);\n } else {\n const migResult = parseMigrationRef(target, { graph: appSpace.graph, refs: appSpace.refs });\n if (!migResult.ok) {\n return { error: mapRefResolutionError(migResult.failure), exitCode: PRECONDITION };\n }\n matchedPkg = bundles.find((p) => p.metadata.migrationHash === migResult.value.migrationHash);\n }\n\n if (!matchedPkg) {\n return {\n result: {\n ok: false,\n failures: [],\n summary: `Migration package for \"${target}\" not found on disk`,\n },\n exitCode: PRECONDITION,\n };\n }\n\n for (const f of ['migration.json', 'ops.json']) {\n const fail = checkFileExists(matchedPkg.dirPath, matchedPkg.dirName, f);\n if (fail) failures.push(fail);\n }\n\n const verification = verifyMigrationHash(matchedPkg);\n if (!verification.ok) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-001',\n where: migrationFileRelative(matchedPkg.dirPath, 'migration.json'),\n why: `Stored hash ${verification.storedHash} does not match recomputed hash ${verification.computedHash}`,\n fix: 'Re-emit the migration package or restore from version control.',\n });\n }\n\n const snapshotFailure = checkSnapshotConsistency(matchedPkg);\n if (snapshotFailure) failures.push(snapshotFailure);\n\n if (failures.length === 0) {\n return {\n result: { ok: true, failures: [], summary: 'All checks passed' },\n exitCode: OK,\n };\n }\n return {\n result: { ok: false, failures, summary: `${failures.length} integrity failure(s)` },\n exitCode: INTEGRITY_FAILED,\n };\n}\n\nexport function createMigrationCheckCommand(): Command {\n const command = new Command('check');\n setCommandDescriptions(\n command,\n 'Verify artifact and graph integrity',\n 'Validates that on-disk migration packages are internally consistent\\n' +\n '(hashes match, manifests are complete) and that the graph is well-formed\\n' +\n '(edges connect, refs point at valid nodes). The whole-graph check spans\\n' +\n 'every contract space by default; pass --space <id> to narrow to one, or\\n' +\n 'a migration reference to check a single app-space package.\\n' +\n 'Offline — does not consult the database.\\n' +\n 'Exit codes: 0 = all checks passed, 2 = precondition failed\\n' +\n '(unresolved target or unknown --space), 4 = integrity failure(s) found.',\n );\n setCommandExamples(command, [\n 'prisma-next migration check',\n 'prisma-next migration check --space app',\n 'prisma-next migration check 20260101-add-users',\n 'prisma-next migration check --json',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n command.exitOverride();\n addGlobalOptions(command)\n .argument('[target]', 'Migration reference: directory name, hash/prefix, ref, or path')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--space <id>', 'Narrow output to a single contract space')\n .action(async (target: string | undefined, options: MigrationCheckOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n\n let outcome: MigrationCheckOutcome;\n try {\n outcome = await executeMigrationCheckCommand(target, options, flags, ui);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n outcome = {\n result: { ok: false, failures: [], summary: msg },\n exitCode: PRECONDITION,\n };\n }\n\n if (outcome.error) {\n const envelope = outcome.error.toEnvelope();\n if (flags.json) {\n ui.output(formatErrorJson(envelope));\n } else if (!flags.quiet) {\n ui.error(formatErrorOutput(envelope, flags));\n }\n process.exit(outcome.exitCode);\n }\n\n const result = outcome.result ?? {\n ok: false,\n failures: [],\n summary: 'No check result produced',\n };\n\n if (flags.json) {\n ui.output(JSON.stringify(result, null, 2));\n } else if (!flags.quiet) {\n if (result.ok) {\n ui.log(`✔ ${result.summary}`);\n } else {\n for (const f of result.failures) {\n ui.log(`✗ [${f.pnCode}] ${f.where}: ${f.why}`);\n ui.log(` fix: ${f.fix}`);\n }\n ui.log(`\\n${result.summary}`);\n }\n }\n\n process.exit(outcome.exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
package/dist/{migration-command-scaffold-CjvwO6at.mjs → migration-command-scaffold-BxOxtyJ6.mjs}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as loadConfig } from "./config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { A as formatStyledHeader, B as errorDatabaseConnectionRequired, H as errorDriverRequired, U as errorFileNotFound, at as errorTargetMigrationNotSupported, i as maskConnectionUrl, o as resolveContractPath, st as errorUnexpected, t as addGlobalOptions, z as errorContractValidationFailed } from "./command-helpers-xvg9oq4T.mjs";
|
|
3
3
|
import { t as createProgressAdapter } from "./progress-adapter-C644QK8l.mjs";
|
|
4
|
-
import { t as createControlClient } from "./client-
|
|
4
|
+
import { t as createControlClient } from "./client-Dk-zRFuT.mjs";
|
|
5
5
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
6
6
|
import { readFile } from "node:fs/promises";
|
|
7
7
|
import { hasMigrations } from "@prisma-next/framework-components/control";
|
|
@@ -100,4 +100,4 @@ function addMigrationCommandOptions(command) {
|
|
|
100
100
|
//#endregion
|
|
101
101
|
export { prepareMigrationContext as n, addMigrationCommandOptions as t };
|
|
102
102
|
|
|
103
|
-
//# sourceMappingURL=migration-command-scaffold-
|
|
103
|
+
//# sourceMappingURL=migration-command-scaffold-BxOxtyJ6.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-command-scaffold-
|
|
1
|
+
{"version":3,"file":"migration-command-scaffold-BxOxtyJ6.mjs","names":[],"sources":["../src/utils/migration-command-scaffold.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { relative, resolve } from 'node:path';\nimport { hasMigrations } from '@prisma-next/framework-components/control';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport type { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type { ControlClient } from '../control-api/types';\nimport {\n type CliStructuredError,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n} from './cli-errors';\nimport { addGlobalOptions, maskConnectionUrl, resolveContractPath } from './command-helpers';\nimport { formatStyledHeader } from './formatters/styled';\nimport type { GlobalFlags } from './global-flags';\nimport { createProgressAdapter } from './progress-adapter';\nimport type { TerminalUI } from './terminal-ui';\n\n/**\n * Resolved context for a migration command.\n * Contains everything needed to invoke a control-api operation.\n */\nexport interface MigrationContext {\n readonly client: ControlClient;\n readonly contractJson: Record<string, unknown>;\n readonly dbConnection: unknown;\n readonly onProgress: ReturnType<typeof createProgressAdapter>;\n readonly configPath: string;\n readonly contractPath: string;\n readonly contractPathAbsolute: string;\n readonly config: Awaited<ReturnType<typeof loadConfig>>;\n}\n\n/**\n * Command-specific configuration for the shared scaffold.\n */\nexport interface MigrationCommandDescriptor {\n readonly commandName: string;\n readonly description: string;\n readonly url: string;\n}\n\n/**\n * Prepares the shared context for migration commands (db init, db update).\n *\n * Handles: config loading, contract file reading, JSON parsing, connection resolution,\n * driver/migration-support validation, client creation, and header output.\n *\n * Returns a Result with either the resolved context or a structured error.\n */\nexport async function prepareMigrationContext(\n options: { readonly db?: string; readonly config?: string; readonly dryRun?: boolean },\n flags: GlobalFlags,\n ui: TerminalUI,\n descriptor: MigrationCommandDescriptor,\n): Promise<Result<MigrationContext, CliStructuredError>> {\n // Load config\n const config = await loadConfig(options.config);\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n const contractPathAbsolute = resolveContractPath(config);\n const contractPath = relative(process.cwd(), contractPathAbsolute);\n\n // Output header to stderr (decoration)\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n ];\n if (options.db) {\n details.push({ label: 'database', value: maskConnectionUrl(options.db) });\n }\n if (options.dryRun) {\n details.push({ label: 'mode', value: 'dry run' });\n }\n const header = formatStyledHeader({\n command: descriptor.commandName,\n description: descriptor.description,\n url: descriptor.url,\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n // Load contract file\n let contractJsonContent: string;\n try {\n contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: `Run \\`prisma-next contract emit\\` to generate ${contractPath}, or update \\`config.contract.output\\` in ${configPath}`,\n }),\n );\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n // Parse contract JSON\n let contractJson: Record<string, unknown>;\n try {\n contractJson = JSON.parse(contractJsonContent) as Record<string, unknown>;\n } catch (error) {\n return notOk(\n errorContractValidationFailed(\n `Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\n\n // Resolve database connection (--db flag or config.db.connection)\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for ${descriptor.commandName} (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: descriptor.commandName,\n }),\n );\n }\n\n // Check for driver\n if (!config.driver) {\n return notOk(\n errorDriverRequired({ why: `Config.driver is required for ${descriptor.commandName}` }),\n );\n }\n\n if (!hasMigrations(config.target)) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n // Create control client\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n // Create progress adapter\n const onProgress = createProgressAdapter({ ui, flags });\n\n return ok({\n client,\n contractJson,\n dbConnection,\n onProgress,\n configPath,\n contractPath,\n contractPathAbsolute,\n config,\n });\n}\n\n/**\n * Registers the shared CLI options for migration commands (db init, db update).\n */\nexport function addMigrationCommandOptions(command: Command): Command {\n addGlobalOptions(command);\n return command\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--dry-run', 'Preview planned operations without applying', false);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAuDA,eAAsB,wBACpB,SACA,OACA,IACA,YACuD;CAEvD,MAAM,SAAS,MAAM,WAAW,QAAQ,MAAM;CAC9C,MAAM,aAAa,QAAQ,SACvB,SAAS,QAAQ,IAAI,GAAG,QAAQ,QAAQ,MAAM,CAAC,IAC/C;CACJ,MAAM,uBAAuB,oBAAoB,MAAM;CACvD,MAAM,eAAe,SAAS,QAAQ,IAAI,GAAG,oBAAoB;CAGjE,IAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EAC/B,MAAM,UAAmD,CACvD;GAAE,OAAO;GAAU,OAAO;EAAW,GACrC;GAAE,OAAO;GAAY,OAAO;EAAa,CAC3C;EACA,IAAI,QAAQ,IACV,QAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,QAAQ,EAAE;EAAE,CAAC;EAE1E,IAAI,QAAQ,QACV,QAAQ,KAAK;GAAE,OAAO;GAAQ,OAAO;EAAU,CAAC;EAElD,MAAM,SAAS,mBAAmB;GAChC,SAAS,WAAW;GACpB,aAAa,WAAW;GACxB,KAAK,WAAW;GAChB;GACA;EACF,CAAC;EACD,GAAG,OAAO,MAAM;CAClB;CAGA,IAAI;CACJ,IAAI;EACF,sBAAsB,MAAM,SAAS,sBAAsB,OAAO;CACpE,SAAS,OAAO;EACd,IAAI,iBAAiB,SAAU,MAA4B,SAAS,UAClE,OAAO,MACL,kBAAkB,sBAAsB;GACtC,KAAK,8BAA8B;GACnC,KAAK,iDAAiD,aAAa,4CAA4C;EACjH,CAAC,CACH;EAEF,OAAO,MACL,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,EACtE,KAAK,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,IAC7F,CAAC,CACH;CACF;CAGA,IAAI;CACJ,IAAI;EACF,eAAe,KAAK,MAAM,mBAAmB;CAC/C,SAAS,OAAO;EACd,OAAO,MACL,8BACE,6BAA6B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,KAClF,EAAE,OAAO,EAAE,MAAM,qBAAqB,EAAE,CAC1C,CACF;CACF;CAGA,MAAM,eAAe,QAAQ,MAAM,OAAO,IAAI;CAC9C,IAAI,CAAC,cACH,OAAO,MACL,gCAAgC;EAC9B,KAAK,uCAAuC,WAAW,YAAY,yBAAyB,WAAW;EACvG,aAAa,WAAW;CAC1B,CAAC,CACH;CAIF,IAAI,CAAC,OAAO,QACV,OAAO,MACL,oBAAoB,EAAE,KAAK,iCAAiC,WAAW,cAAc,CAAC,CACxF;CAGF,IAAI,CAAC,cAAc,OAAO,MAAM,GAC9B,OAAO,MACL,iCAAiC,EAC/B,KAAK,WAAW,OAAO,OAAO,GAAG,+BACnC,CAAC,CACH;CAIF,MAAM,SAAS,oBAAoB;EACjC,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,QAAQ,OAAO;EACf,gBAAgB,OAAO,kBAAkB,CAAC;CAC5C,CAAC;CAGD,MAAM,aAAa,sBAAsB;EAAE;EAAI;CAAM,CAAC;CAEtD,OAAO,GAAG;EACR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;AACH;;;;AAKA,SAAgB,2BAA2B,SAA2B;CACpE,iBAAiB,OAAO;CACxB,OAAO,QACJ,OAAO,cAAc,4BAA4B,EACjD,OAAO,mBAAmB,+BAA+B,EACzD,OAAO,aAAa,+CAA+C,KAAK;AAC7E"}
|