@prisma-next/migration-tools 0.5.0-dev.67 → 0.5.0-dev.69
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/{errors-5KVuWV_5.mjs → errors-EPL_9p9f.mjs} +12 -6
- package/dist/errors-EPL_9p9f.mjs.map +1 -0
- package/dist/exports/aggregate.d.mts +534 -0
- package/dist/exports/aggregate.d.mts.map +1 -0
- package/dist/exports/aggregate.mjs +598 -0
- package/dist/exports/aggregate.mjs.map +1 -0
- package/dist/exports/errors.d.mts +6 -1
- package/dist/exports/errors.d.mts.map +1 -1
- package/dist/exports/errors.mjs +2 -2
- package/dist/exports/graph.d.mts +1 -1
- package/dist/exports/hash.d.mts +1 -1
- package/dist/exports/invariants.d.mts +13 -2
- package/dist/exports/invariants.d.mts.map +1 -1
- package/dist/exports/invariants.mjs +1 -1
- package/dist/exports/io.d.mts +25 -1
- package/dist/exports/io.d.mts.map +1 -1
- package/dist/exports/io.mjs +2 -2
- package/dist/exports/metadata.d.mts +1 -1
- package/dist/exports/migration-graph.d.mts +1 -1
- package/dist/exports/migration-graph.mjs +1 -522
- package/dist/exports/migration.d.mts +1 -1
- package/dist/exports/migration.mjs +2 -2
- package/dist/exports/refs.mjs +1 -1
- package/dist/exports/spaces.d.mts +341 -237
- package/dist/exports/spaces.d.mts.map +1 -1
- package/dist/exports/spaces.mjs +137 -339
- package/dist/exports/spaces.mjs.map +1 -1
- package/dist/{graph-4dIUm90i.d.mts → graph-HMWAldoR.d.mts} +1 -1
- package/dist/{graph-4dIUm90i.d.mts.map → graph-HMWAldoR.d.mts.map} +1 -1
- package/dist/{invariants-CkLSBcMu.mjs → invariants-Duc8f9NM.mjs} +16 -5
- package/dist/invariants-Duc8f9NM.mjs.map +1 -0
- package/dist/{io-TX8RPDeh.mjs → io-D13dLvUh.mjs} +38 -4
- package/dist/io-D13dLvUh.mjs.map +1 -0
- package/dist/migration-graph-DGNnKDY5.mjs +523 -0
- package/dist/{exports/migration-graph.mjs.map → migration-graph-DGNnKDY5.mjs.map} +1 -1
- package/dist/read-contract-space-contract-C3-1eyaI.mjs +298 -0
- package/dist/read-contract-space-contract-C3-1eyaI.mjs.map +1 -0
- package/package.json +10 -6
- package/src/aggregate/loader.ts +409 -0
- package/src/aggregate/marker-types.ts +16 -0
- package/src/aggregate/planner-types.ts +137 -0
- package/src/aggregate/planner.ts +158 -0
- package/src/aggregate/project-schema-to-space.ts +64 -0
- package/src/aggregate/strategies/graph-walk.ts +92 -0
- package/src/aggregate/strategies/synth.ts +122 -0
- package/src/aggregate/types.ts +89 -0
- package/src/aggregate/verifier.ts +230 -0
- package/src/assert-descriptor-self-consistency.ts +70 -0
- package/src/compute-extension-space-apply-path.ts +152 -0
- package/src/concatenate-space-apply-inputs.ts +2 -2
- package/src/detect-space-contract-drift.ts +22 -26
- package/src/{emit-pinned-space-artefacts.ts → emit-contract-space-artefacts.ts} +14 -33
- package/src/errors.ts +11 -5
- package/src/exports/aggregate.ts +37 -0
- package/src/exports/errors.ts +1 -0
- package/src/exports/io.ts +1 -0
- package/src/exports/spaces.ts +23 -10
- package/src/gather-disk-contract-space-state.ts +62 -0
- package/src/invariants.ts +14 -3
- package/src/io.ts +42 -0
- package/src/plan-all-spaces.ts +3 -7
- package/src/read-contract-space-contract.ts +44 -0
- package/src/read-contract-space-head-ref.ts +63 -0
- package/src/space-layout.ts +4 -11
- package/src/verify-contract-spaces.ts +45 -49
- package/dist/errors-5KVuWV_5.mjs.map +0 -1
- package/dist/invariants-CkLSBcMu.mjs.map +0 -1
- package/dist/io-TX8RPDeh.mjs.map +0 -1
- package/src/read-pinned-contract-hash.ts +0 -77
- /package/dist/{metadata-th_MvOTT.d.mts → metadata-BnLFiI6B.d.mts} +0 -0
|
@@ -131,10 +131,16 @@ function errorInvalidSpaceId(spaceId) {
|
|
|
131
131
|
details: { spaceId }
|
|
132
132
|
});
|
|
133
133
|
}
|
|
134
|
-
function
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
function errorDescriptorHeadHashMismatch(args) {
|
|
135
|
+
const { extensionId, recomputedHash, headRefHash } = args;
|
|
136
|
+
return new MigrationToolsError("MIGRATION.DESCRIPTOR_HEAD_HASH_MISMATCH", "Extension descriptor's headRef.hash does not match its contractJson", {
|
|
137
|
+
why: `Extension "${extensionId}" publishes a \`contractSpace\` whose \`headRef.hash\` (${headRefHash}) does not match the canonical hash recomputed from \`contractSpace.contractJson\` (${recomputedHash}). This means the extension descriptor was published with stale \`headRef.hash\` — typically because the contract was bumped without rerunning the extension's emit pipeline.`,
|
|
138
|
+
fix: "Re-run the extension authoring pipeline so `contractJson.storage.storageHash` and `headRef.hash` agree, then republish the extension. If you are the extension author and you intentionally bumped `contractJson`, recompute and update `headRef.hash` (and refresh any on-disk migration metadata that derives from it).",
|
|
139
|
+
details: {
|
|
140
|
+
extensionId,
|
|
141
|
+
recomputedHash,
|
|
142
|
+
headRefHash
|
|
143
|
+
}
|
|
138
144
|
});
|
|
139
145
|
}
|
|
140
146
|
function errorDuplicateSpaceId(spaceId) {
|
|
@@ -286,6 +292,6 @@ function errorMigrationHashMismatch(dir, storedHash, computedHash) {
|
|
|
286
292
|
});
|
|
287
293
|
}
|
|
288
294
|
//#endregion
|
|
289
|
-
export { errorProvidedInvariantsMismatch as C, errorUnknownInvariant as E,
|
|
295
|
+
export { errorProvidedInvariantsMismatch as C, errorUnknownInvariant as E, errorNoTarget as S, errorStaleContractBookends as T, errorInvalidSpaceId as _, errorDuplicateInvariantInEdge as a, errorNoInitialMigration as b, errorInvalidDestName as c, errorInvalidManifest as d, errorInvalidOperationEntry as f, errorInvalidSlug as g, errorInvalidRefValue as h, errorDirectoryExists as i, errorInvalidInvariantId as l, errorInvalidRefName as m, errorAmbiguousTarget as n, errorDuplicateMigrationHash as o, errorInvalidRefFile as p, errorDescriptorHeadHashMismatch as r, errorDuplicateSpaceId as s, MigrationToolsError as t, errorInvalidJson as u, errorMigrationHashMismatch as v, errorSameSourceAndTarget as w, errorNoInvariantPath as x, errorMissingFile as y };
|
|
290
296
|
|
|
291
|
-
//# sourceMappingURL=errors-
|
|
297
|
+
//# sourceMappingURL=errors-EPL_9p9f.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors-EPL_9p9f.mjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import { ifDefined } from '@prisma-next/utils/defined';\nimport { basename, dirname, relative } from 'pathe';\n\n/**\n * Build the canonical \"re-emit this package\" remediation hint.\n *\n * Every on-disk migration package ships its own `migration.ts` author-time\n * file. Running it regenerates `migration.json` and `ops.json` with the\n * correct hash + metadata, so it is the right primitive whenever a single\n * package's on-disk artifacts are missing, malformed, or otherwise corrupt.\n * Pointing users at `migration plan` would emit a *new* package rather than\n * heal the broken one.\n */\nfunction reemitHint(dir: string, fallback?: string): string {\n const relativeDir = relative(process.cwd(), dir);\n const reemit = `Re-emit the package by running \\`node \"${relativeDir}/migration.ts\"\\``;\n return fallback ? `${reemit}, ${fallback}` : `${reemit}.`;\n}\n\n/**\n * Structured error for migration tooling operations.\n *\n * Follows the NAMESPACE.SUBCODE convention from ADR 027. All codes live under\n * the MIGRATION namespace. These are tooling-time errors (file I/O, hash\n * verification, migration history reconstruction), distinct from the runtime\n * MIGRATION.* codes for apply-time failures (PRECHECK_FAILED, POSTCHECK_FAILED,\n * etc.).\n *\n * Fields:\n * - code: Stable machine-readable code (MIGRATION.SUBCODE)\n * - category: Always 'MIGRATION'\n * - why: Explains the cause in plain language\n * - fix: Actionable remediation step\n * - details: Machine-readable structured data for agents\n */\nexport class MigrationToolsError extends Error {\n readonly code: string;\n readonly category = 'MIGRATION' as const;\n readonly why: string;\n readonly fix: string;\n readonly details: Record<string, unknown> | undefined;\n\n constructor(\n code: string,\n summary: string,\n options: {\n readonly why: string;\n readonly fix: string;\n readonly details?: Record<string, unknown>;\n },\n ) {\n super(summary);\n this.name = 'MigrationToolsError';\n this.code = code;\n this.why = options.why;\n this.fix = options.fix;\n this.details = options.details;\n }\n\n static is(error: unknown): error is MigrationToolsError {\n if (!(error instanceof Error)) return false;\n const candidate = error as MigrationToolsError;\n return candidate.name === 'MigrationToolsError' && typeof candidate.code === 'string';\n }\n}\n\nexport function errorDirectoryExists(dir: string): MigrationToolsError {\n return new MigrationToolsError('MIGRATION.DIR_EXISTS', 'Migration directory already exists', {\n why: `The directory \"${dir}\" already exists. Each migration must have a unique directory.`,\n fix: 'Use --name to pick a different name, or delete the existing directory and re-run.',\n details: { dir },\n });\n}\n\nexport function errorMissingFile(file: string, dir: string): MigrationToolsError {\n return new MigrationToolsError('MIGRATION.FILE_MISSING', `Missing ${file}`, {\n why: `Expected \"${file}\" in \"${dir}\" but the file does not exist.`,\n fix: reemitHint(\n dir,\n 'or delete the directory if the migration is unwanted and the source TypeScript is gone.',\n ),\n details: { file, dir },\n });\n}\n\nexport function errorInvalidJson(filePath: string, parseError: string): MigrationToolsError {\n return new MigrationToolsError('MIGRATION.INVALID_JSON', 'Invalid JSON in migration file', {\n why: `Failed to parse \"${filePath}\": ${parseError}`,\n fix: reemitHint(dirname(filePath), 'or restore the directory from version control.'),\n details: { filePath, parseError },\n });\n}\n\nexport function errorInvalidManifest(filePath: string, reason: string): MigrationToolsError {\n return new MigrationToolsError('MIGRATION.INVALID_MANIFEST', 'Invalid migration manifest', {\n why: `Migration manifest at \"${filePath}\" is invalid: ${reason}`,\n fix: reemitHint(dirname(filePath), 'or restore the directory from version control.'),\n details: { filePath, reason },\n });\n}\n\nexport function errorInvalidOperationEntry(index: number, reason: string): MigrationToolsError {\n return new MigrationToolsError(\n 'MIGRATION.INVALID_OPERATION_ENTRY',\n 'Migration operation entry is malformed',\n {\n why: `Operation at index ${index} returned by the migration class failed schema validation: ${reason}.`,\n fix: \"Update the migration class so each entry of `operations` carries `id` (string), `label` (string), and `operationClass` (one of 'additive' | 'widening' | 'destructive' | 'data').\",\n details: { index, reason },\n },\n );\n}\n\nexport function errorStaleContractBookends(args: {\n readonly side: 'from' | 'to';\n readonly metaHash: string | null;\n readonly contractHash: string;\n}): MigrationToolsError {\n const { side, metaHash, contractHash } = args;\n // `meta.from` is `string | null` (null = baseline). Render `null` as a\n // human-readable token in the diagnostic so the message stays clear when\n // the mismatch is a baseline-vs-non-baseline disagreement.\n const renderedMetaHash = metaHash === null ? 'null (baseline)' : `\"${metaHash}\"`;\n return new MigrationToolsError(\n 'MIGRATION.STALE_CONTRACT_BOOKENDS',\n 'Migration manifest contract bookends disagree with describe()',\n {\n why: `migration.json stores ${side}Contract.storage.storageHash \"${contractHash}\", but describe() returned meta.${side} = ${renderedMetaHash}. The bookend is stale — most likely the migration's describe() was edited after the package was scaffolded by \\`migration plan\\`.`,\n fix: 'Re-run `migration plan` to regenerate the package with fresh contract bookends, or restore the directory from version control.',\n details: { side, metaHash, contractHash },\n },\n );\n}\n\nexport function errorInvalidSlug(slug: string): MigrationToolsError {\n return new MigrationToolsError('MIGRATION.INVALID_NAME', 'Invalid migration name', {\n why: `The slug \"${slug}\" contains no valid characters after sanitization (only a-z, 0-9 are kept).`,\n fix: 'Provide a name with at least one alphanumeric character, e.g. --name add_users.',\n details: { slug },\n });\n}\n\nexport function errorInvalidDestName(destName: string): MigrationToolsError {\n return new MigrationToolsError('MIGRATION.INVALID_DEST_NAME', 'Invalid copy destination name', {\n why: `The destination name \"${destName}\" must be a single path segment (no \"..\" or directory separators).`,\n fix: 'Use a simple file name such as \"contract.json\" for each destination in the copy list.',\n details: { destName },\n });\n}\n\nexport function errorInvalidSpaceId(spaceId: string): MigrationToolsError {\n return new MigrationToolsError(\n 'MIGRATION.INVALID_SPACE_ID',\n 'Invalid contract space identifier',\n {\n why: `The space id \"${spaceId}\" does not match the required pattern /^[a-z][a-z0-9_-]{0,63}$/. Space ids are used as filesystem directory names under \\`migrations/\\`, so the pattern is conservative on purpose.`,\n fix: 'Pick a lowercase identifier that begins with a letter and contains only lowercase letters, digits, hyphens, or underscores; max 64 characters total.',\n details: { spaceId },\n },\n );\n}\n\nexport function errorDescriptorHeadHashMismatch(args: {\n readonly extensionId: string;\n readonly recomputedHash: string;\n readonly headRefHash: string;\n}): MigrationToolsError {\n const { extensionId, recomputedHash, headRefHash } = args;\n return new MigrationToolsError(\n 'MIGRATION.DESCRIPTOR_HEAD_HASH_MISMATCH',\n \"Extension descriptor's headRef.hash does not match its contractJson\",\n {\n why: `Extension \"${extensionId}\" publishes a \\`contractSpace\\` whose \\`headRef.hash\\` (${headRefHash}) does not match the canonical hash recomputed from \\`contractSpace.contractJson\\` (${recomputedHash}). This means the extension descriptor was published with stale \\`headRef.hash\\` — typically because the contract was bumped without rerunning the extension's emit pipeline.`,\n fix: 'Re-run the extension authoring pipeline so `contractJson.storage.storageHash` and `headRef.hash` agree, then republish the extension. If you are the extension author and you intentionally bumped `contractJson`, recompute and update `headRef.hash` (and refresh any on-disk migration metadata that derives from it).',\n details: { extensionId, recomputedHash, headRefHash },\n },\n );\n}\n\nexport function errorDuplicateSpaceId(spaceId: string): MigrationToolsError {\n return new MigrationToolsError(\n 'MIGRATION.DUPLICATE_SPACE_ID',\n 'Duplicate contract space identifier',\n {\n why: `The space id \"${spaceId}\" appears more than once in the per-space planner input. Each space id must be unique across the inputs (the per-space planner emits one output entry per id).`,\n fix: 'Deduplicate the inputs before passing them to `planAllSpaces` — typically by checking your `extensionPacks` declaration for repeated entries.',\n details: { spaceId },\n },\n );\n}\n\nexport function errorSameSourceAndTarget(dir: string, hash: string): MigrationToolsError {\n const dirName = basename(dir);\n return new MigrationToolsError(\n 'MIGRATION.SAME_SOURCE_AND_TARGET',\n 'Migration without data-transform operations has same source and target',\n {\n why: `Migration \"${dirName}\" has from === to === \"${hash}\" and declares no data-transform operations. Self-edges are only allowed when the migration runs at least one dataTransform — otherwise the migration is a no-op.`,\n fix: reemitHint(\n dir,\n 'and either change the contract so from ≠ to, add a dataTransform op, or delete the directory if the migration is unwanted.',\n ),\n details: { dirName, hash },\n },\n );\n}\n\nexport function errorAmbiguousTarget(\n branchTips: readonly string[],\n context?: {\n divergencePoint: string;\n branches: readonly {\n tip: string;\n edges: readonly { dirName: string; from: string; to: string }[];\n }[];\n },\n): MigrationToolsError {\n const divergenceInfo = context\n ? `\\nDivergence point: ${context.divergencePoint}\\nBranches:\\n${context.branches.map((b) => ` → ${b.tip} (${b.edges.length} edge(s): ${b.edges.map((e) => e.dirName).join(' → ') || 'direct'})`).join('\\n')}`\n : '';\n return new MigrationToolsError('MIGRATION.AMBIGUOUS_TARGET', 'Ambiguous migration target', {\n why: `The migration history has diverged into multiple branches: ${branchTips.join(', ')}. This typically happens when two developers plan migrations from the same starting point.${divergenceInfo}`,\n fix: 'Use `migration ref set <name> <hash>` to target a specific branch, delete one of the conflicting migration directories and re-run `migration plan`, or use --from <hash> to explicitly select a starting point.',\n details: {\n branchTips,\n ...(context ? { divergencePoint: context.divergencePoint, branches: context.branches } : {}),\n },\n });\n}\n\nexport function errorNoInitialMigration(nodes: readonly string[]): MigrationToolsError {\n return new MigrationToolsError('MIGRATION.NO_INITIAL_MIGRATION', 'No initial migration found', {\n why: `No migration starts from the empty contract state (known hashes: ${nodes.join(', ')}). At least one migration must originate from the empty state.`,\n fix: 'Inspect the migrations directory for corrupted migration.json files. At least one migration must start from the empty contract hash.',\n details: { nodes },\n });\n}\n\nexport function errorInvalidRefs(refsPath: string, reason: string): MigrationToolsError {\n return new MigrationToolsError('MIGRATION.INVALID_REFS', 'Invalid refs.json', {\n why: `refs.json at \"${refsPath}\" is invalid: ${reason}`,\n fix: 'Ensure refs.json is a flat object mapping valid ref names to contract hash strings.',\n details: { path: refsPath, reason },\n });\n}\n\nexport function errorInvalidRefFile(filePath: string, reason: string): MigrationToolsError {\n return new MigrationToolsError('MIGRATION.INVALID_REF_FILE', 'Invalid ref file', {\n why: `Ref file at \"${filePath}\" is invalid: ${reason}`,\n fix: 'Ensure the ref file contains valid JSON with { \"hash\": \"sha256:<64 hex chars>\", \"invariants\": [\"...\"] }.',\n details: { path: filePath, reason },\n });\n}\n\nexport function errorInvalidRefName(refName: string): MigrationToolsError {\n return new MigrationToolsError('MIGRATION.INVALID_REF_NAME', 'Invalid ref name', {\n why: `Ref name \"${refName}\" is invalid. Names must be lowercase alphanumeric with hyphens or forward slashes (no \".\" or \"..\" segments).`,\n fix: `Use a valid ref name (e.g., \"staging\", \"envs/production\").`,\n details: { refName },\n });\n}\n\nexport function errorNoTarget(reachableHashes: readonly string[]): MigrationToolsError {\n return new MigrationToolsError('MIGRATION.NO_TARGET', 'No migration target could be resolved', {\n why: `The migration history contains cycles and no target can be resolved automatically (reachable hashes: ${reachableHashes.join(', ')}). This typically happens after rollback migrations (e.g., C1→C2→C1).`,\n fix: 'Use --from <hash> to specify the planning origin explicitly.',\n details: { reachableHashes },\n });\n}\n\nexport function errorInvalidRefValue(value: string): MigrationToolsError {\n return new MigrationToolsError('MIGRATION.INVALID_REF_VALUE', 'Invalid ref value', {\n why: `Ref value \"${value}\" is not a valid contract hash. Values must be in the format \"sha256:<64 hex chars>\" or \"sha256:empty\".`,\n fix: 'Use a valid storage hash from `prisma-next contract emit` output or an existing migration.',\n details: { value },\n });\n}\n\nexport function errorDuplicateMigrationHash(migrationHash: string): MigrationToolsError {\n return new MigrationToolsError(\n 'MIGRATION.DUPLICATE_MIGRATION_HASH',\n 'Duplicate migrationHash in migration graph',\n {\n why: `Multiple migrations share migrationHash \"${migrationHash}\". Each migration must have a unique content-addressed identity.`,\n fix: 'Regenerate one of the conflicting migrations so each migrationHash is unique, then re-run migration commands.',\n details: { migrationHash },\n },\n );\n}\n\nexport function errorInvalidInvariantId(invariantId: string): MigrationToolsError {\n return new MigrationToolsError('MIGRATION.INVALID_INVARIANT_ID', 'Invalid invariantId', {\n why: `invariantId ${JSON.stringify(invariantId)} is invalid. Ids must be non-empty and contain no whitespace or control characters (including Unicode whitespace like NBSP); other content (kebab-case, camelCase, namespaced, Unicode letters) is allowed.`,\n fix: 'Pick an invariantId without spaces, tabs, newlines, or control characters — e.g. \"backfill-user-phone\", \"users/backfill-phone\", or \"BackfillUserPhone\".',\n details: { invariantId },\n });\n}\n\nexport function errorDuplicateInvariantInEdge(invariantId: string): MigrationToolsError {\n return new MigrationToolsError(\n 'MIGRATION.DUPLICATE_INVARIANT_IN_EDGE',\n 'Duplicate invariantId on a single migration',\n {\n why: `invariantId \"${invariantId}\" is declared by more than one dataTransform on the same migration. The marker stores invariants as a set and the routing layer treats them as edge-level, so two ops cannot share a routing identity.`,\n fix: 'Rename one of the conflicting dataTransform invariantIds, or drop invariantId on the op that does not need to be routing-visible.',\n details: { invariantId },\n },\n );\n}\n\nexport function errorProvidedInvariantsMismatch(\n filePath: string,\n stored: readonly string[],\n derived: readonly string[],\n): MigrationToolsError {\n const storedSet = new Set(stored);\n const derivedSet = new Set(derived);\n const missing = [...derivedSet].filter((id) => !storedSet.has(id));\n const extra = [...storedSet].filter((id) => !derivedSet.has(id));\n // When sets agree but arrays don't, the only difference is ordering — call\n // it out so the reader doesn't stare at two visually-identical arrays.\n // Canonical providedInvariants is sorted ascending; a manifest with the\n // same ids in a different order is still a mismatch (the hash check would\n // also fail), but the human-readable diagnostic is otherwise unhelpful.\n const orderingOnly = missing.length === 0 && extra.length === 0;\n const why = orderingOnly\n ? `migration.json at \"${filePath}\" stores providedInvariants ${JSON.stringify(stored)}, but the canonical value derived from ops.json is ${JSON.stringify(derived)} — same ids, different order. Canonical providedInvariants is sorted ascending.`\n : `migration.json at \"${filePath}\" stores providedInvariants ${JSON.stringify(stored)}, but the value derived from ops.json is ${JSON.stringify(derived)}. The manifest copy was likely hand-edited without re-emitting.`;\n return new MigrationToolsError(\n 'MIGRATION.PROVIDED_INVARIANTS_MISMATCH',\n 'providedInvariants on migration.json disagrees with ops.json',\n {\n why,\n fix: reemitHint(dirname(filePath), 'or restore the directory from version control.'),\n details: { filePath, stored, derived, difference: { missing, extra } },\n },\n );\n}\n\n/**\n * Wire-shape edge surfaced through the JSON envelope's\n * `meta.structuralPath` of `MIGRATION.NO_INVARIANT_PATH`. Slim by design —\n * authoring metadata (`createdAt`, `labels`) lives on `MigrationEdge` but\n * is intentionally dropped here so the envelope stays stable across\n * graph-internal refactors.\n *\n * Stability: any field added here is part of the public CLI JSON contract.\n * Callers (CLI consumers, agents) must be able to treat\n * `(dirName, migrationHash, from, to, invariants)` as the canonical shape.\n */\nexport interface NoInvariantPathStructuralEdge {\n readonly dirName: string;\n readonly migrationHash: string;\n readonly from: string;\n readonly to: string;\n readonly invariants: readonly string[];\n}\n\nexport function errorNoInvariantPath(args: {\n readonly refName?: string;\n readonly required: readonly string[];\n readonly missing: readonly string[];\n readonly structuralPath: readonly NoInvariantPathStructuralEdge[];\n}): MigrationToolsError {\n const { refName, required, missing, structuralPath } = args;\n const refClause = refName ? `Ref \"${refName}\"` : 'Target';\n const missingList = missing.map((id) => JSON.stringify(id)).join(', ');\n const requiredList = required.map((id) => JSON.stringify(id)).join(', ');\n return new MigrationToolsError(\n 'MIGRATION.NO_INVARIANT_PATH',\n 'No path covers the required invariants',\n {\n why: `${refClause} requires invariants the reachable path doesn't cover. required=[${requiredList}], missing=[${missingList}].`,\n fix: 'Add a migration on the path that runs `dataTransform({ invariantId: \"<id>\", … })` for each missing invariant, or retarget the ref to a hash whose path already provides them.',\n details: {\n required,\n missing,\n structuralPath,\n ...ifDefined('refName', refName),\n },\n },\n );\n}\n\nexport function errorUnknownInvariant(args: {\n readonly refName?: string;\n readonly unknown: readonly string[];\n readonly declared: readonly string[];\n}): MigrationToolsError {\n const { refName, unknown, declared } = args;\n const refClause = refName ? `Ref \"${refName}\" declares` : 'Declares';\n const unknownList = unknown.map((id) => JSON.stringify(id)).join(', ');\n return new MigrationToolsError(\n 'MIGRATION.UNKNOWN_INVARIANT',\n 'Ref declares invariants no migration in the graph provides',\n {\n why: `${refClause} invariants no migration in the graph provides. unknown=[${unknownList}].`,\n fix: 'Either the ref has a typo, or the declaring migration has not been authored/attested yet. Re-check the ref file and the migrations directory.',\n details: {\n unknown,\n declared,\n ...ifDefined('refName', refName),\n },\n },\n );\n}\n\nexport function errorMigrationHashMismatch(\n dir: string,\n storedHash: string,\n computedHash: string,\n): MigrationToolsError {\n // Render a cwd-relative path in the human-readable diagnostic so users\n // running CLI commands from the project root see a familiar short path.\n // Keep the absolute path in `details.dir` for machine consumers.\n const relativeDir = relative(process.cwd(), dir);\n return new MigrationToolsError('MIGRATION.HASH_MISMATCH', 'Migration package is corrupt', {\n why: `Stored migrationHash \"${storedHash}\" does not match the recomputed hash \"${computedHash}\" for \"${relativeDir}\". The migration.json or ops.json has been edited or partially written since emit.`,\n fix: reemitHint(dir, 'or restore the directory from version control.'),\n details: { dir, storedHash, computedHash },\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
import { n as OnDiskMigrationPackage } from "../package-BjiZ7KDy.mjs";
|
|
2
|
+
import { n as MigrationGraph } from "../graph-HMWAldoR.mjs";
|
|
3
|
+
import { ControlFamilyInstance, MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlannerConflict, TargetMigrationsCapability } from "@prisma-next/framework-components/control";
|
|
4
|
+
import { Result } from "@prisma-next/utils/result";
|
|
5
|
+
import { Contract } from "@prisma-next/contract/types";
|
|
6
|
+
import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components";
|
|
7
|
+
|
|
8
|
+
//#region src/aggregate/types.d.ts
|
|
9
|
+
/**
|
|
10
|
+
* Hydrated migration graph for a single contract space.
|
|
11
|
+
*
|
|
12
|
+
* `graph` is the structural shortest-path graph (forward / reverse chain,
|
|
13
|
+
* deterministic tie-break order) reconstructed from a set of on-disk
|
|
14
|
+
* migration packages. `packagesByMigrationHash` is the lookup table the
|
|
15
|
+
* graph-walk strategy uses to resolve a path's edge sequence back to the
|
|
16
|
+
* concrete `OnDiskMigrationPackage` (and therefore the operation list) for
|
|
17
|
+
* apply.
|
|
18
|
+
*
|
|
19
|
+
* Eagerly hydrated by the loader. Once a `ContractSpaceAggregate` exists,
|
|
20
|
+
* downstream consumers do **not** touch the filesystem to walk graphs or
|
|
21
|
+
* resolve packages — the aggregate is the boundary.
|
|
22
|
+
*/
|
|
23
|
+
interface HydratedMigrationGraph {
|
|
24
|
+
readonly graph: MigrationGraph;
|
|
25
|
+
readonly packagesByMigrationHash: ReadonlyMap<string, OnDiskMigrationPackage>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* One contract space — app or extension — as a member of a
|
|
29
|
+
* {@link ContractSpaceAggregate}. Every member has the same shape.
|
|
30
|
+
*
|
|
31
|
+
* - `spaceId`: `'app'` for the application, otherwise the extension's
|
|
32
|
+
* id (validated against `[a-z][a-z0-9_-]{0,63}`).
|
|
33
|
+
* - `contract`: the validated contract value for this member. For the
|
|
34
|
+
* app, the user's authored contract; for an extension, the on-disk
|
|
35
|
+
* `migrations/<spaceId>/contract.json`. Both have already passed the
|
|
36
|
+
* family's `validateContract` at the loader boundary.
|
|
37
|
+
* - `headRef.hash`: the storage hash this member is targeting. For the
|
|
38
|
+
* app, equals `contract.storage.storageHash`. For extensions, the
|
|
39
|
+
* on-disk `refs/head.json.hash`.
|
|
40
|
+
* - `headRef.invariants`: alphabetically sorted, deduplicated invariant
|
|
41
|
+
* ids declared on the head ref. Empty for the app member (the app's
|
|
42
|
+
* plan is synthesised from the contract IR, no invariants required).
|
|
43
|
+
* - `migrations`: the hydrated migration graph for this space. Possibly
|
|
44
|
+
* empty (an extension whose on-disk head ref points at the
|
|
45
|
+
* empty-contract sentinel and ships no migrations yet, or the app
|
|
46
|
+
* when the user hasn't authored any).
|
|
47
|
+
*/
|
|
48
|
+
interface ContractSpaceMember {
|
|
49
|
+
readonly spaceId: string;
|
|
50
|
+
readonly contract: Contract;
|
|
51
|
+
readonly headRef: {
|
|
52
|
+
readonly hash: string;
|
|
53
|
+
readonly invariants: readonly string[];
|
|
54
|
+
};
|
|
55
|
+
readonly migrations: HydratedMigrationGraph;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Typed value carrying the user's app contract plus every loaded
|
|
59
|
+
* extension contract space, fully hydrated and internally consistent.
|
|
60
|
+
*
|
|
61
|
+
* Produced once per CLI invocation by `loadContractSpaceAggregate`.
|
|
62
|
+
* Every downstream component (planner, verifier, runner adapter)
|
|
63
|
+
* consumes this value rather than rebuilding state from disk.
|
|
64
|
+
*
|
|
65
|
+
* Invariants the loader enforces at construction:
|
|
66
|
+
*
|
|
67
|
+
* 1. `targetId` is consistent across every member (`contract.target`
|
|
68
|
+
* matches `aggregate.targetId`). The aggregate's `targetId` is the
|
|
69
|
+
* `Config.adapter.targetId` value the loader was told to use.
|
|
70
|
+
* 2. `aggregate.extensions` is sorted alphabetically by `spaceId`.
|
|
71
|
+
* Mirrors {@link import('../concatenate-space-apply-inputs').concatenateSpaceApplyInputs}'s
|
|
72
|
+
* extension ordering convention so downstream apply order matches
|
|
73
|
+
* today's behaviour byte-for-byte.
|
|
74
|
+
* 3. No two members claim the same storage element (table / type / etc.).
|
|
75
|
+
* 4. For each extension member: `member.headRef.hash` is reachable from
|
|
76
|
+
* the empty-contract sentinel in `member.migrations.graph` (or the
|
|
77
|
+
* graph is empty and `member.headRef.hash === EMPTY_CONTRACT_HASH`).
|
|
78
|
+
* 5. For the app member: `member.headRef.hash` equals
|
|
79
|
+
* `member.contract.storage.storageHash`. The app's `migrations`
|
|
80
|
+
* is hydrated from the user's authored `migrations/` (or empty if
|
|
81
|
+
* none).
|
|
82
|
+
*
|
|
83
|
+
* The aggregate is **type-uniform** post-construction: app/extension
|
|
84
|
+
* distinguishability survives only at the caller-policy layer
|
|
85
|
+
* (`ignoreGraphFor: new Set([appSpaceId])`), not on member shape.
|
|
86
|
+
*/
|
|
87
|
+
interface ContractSpaceAggregate {
|
|
88
|
+
readonly targetId: string;
|
|
89
|
+
readonly app: ContractSpaceMember;
|
|
90
|
+
readonly extensions: readonly ContractSpaceMember[];
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/aggregate/loader.d.ts
|
|
94
|
+
/**
|
|
95
|
+
* Hash function used by drift detection. Defaults to a canonical-JSON +
|
|
96
|
+
* SHA-256 pipeline that mirrors the framework's contract-hash convention,
|
|
97
|
+
* but the loader accepts a callback so SQL-family callers can pass their
|
|
98
|
+
* `coreHash` / `storageHash` derivation through unchanged.
|
|
99
|
+
*
|
|
100
|
+
* The contract value passed in is the framework-neutral `unknown` form;
|
|
101
|
+
* callers that have already validated typed contracts can simply hand
|
|
102
|
+
* the validated value back through.
|
|
103
|
+
*/
|
|
104
|
+
type AggregateContractHasher = (contract: unknown) => string;
|
|
105
|
+
/**
|
|
106
|
+
* Single declared extension entry the loader needs from `Config.extensionPacks`.
|
|
107
|
+
*
|
|
108
|
+
* Only the subset of fields the loader operates on:
|
|
109
|
+
*
|
|
110
|
+
* - `id` — the space id (also the directory name under `migrations/`).
|
|
111
|
+
* - `targetId` — the configured `Config.adapter.targetId` value the
|
|
112
|
+
* declaring extension declared. The loader rejects mismatches against
|
|
113
|
+
* the aggregate's `targetId` with `targetMismatch`.
|
|
114
|
+
* - `contractSpace` — present iff the descriptor declares a contract
|
|
115
|
+
* space (extensions can ship without one and remain runtime-only /
|
|
116
|
+
* codec-only). Drift detection compares the descriptor's
|
|
117
|
+
* `contractJson` hash against the on-disk on-disk head hash; the loader
|
|
118
|
+
* rejects drift fatally.
|
|
119
|
+
*
|
|
120
|
+
* Typed structurally so the migration-tools layer stays framework-neutral.
|
|
121
|
+
*/
|
|
122
|
+
interface DeclaredExtensionEntry {
|
|
123
|
+
readonly id: string;
|
|
124
|
+
readonly targetId: string;
|
|
125
|
+
readonly contractSpace?: {
|
|
126
|
+
readonly contractJson: unknown;
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Inputs for {@link loadContractSpaceAggregate}.
|
|
131
|
+
*
|
|
132
|
+
* The loader is the **sole** descriptor-import boundary in the M2.5
|
|
133
|
+
* pipeline: callers gather the descriptor data (already-validated app
|
|
134
|
+
* contract, declared extension entries) and pass it through. Once the
|
|
135
|
+
* loader returns, no descriptor module is imported again for this
|
|
136
|
+
* aggregate's lifetime.
|
|
137
|
+
*/
|
|
138
|
+
interface LoadAggregateInput {
|
|
139
|
+
readonly targetId: string;
|
|
140
|
+
readonly migrationsDir: string;
|
|
141
|
+
readonly appContract: Contract;
|
|
142
|
+
readonly declaredExtensions: ReadonlyArray<DeclaredExtensionEntry>;
|
|
143
|
+
readonly validateContract: (contractJson: unknown) => Contract;
|
|
144
|
+
readonly hashContract: AggregateContractHasher;
|
|
145
|
+
/**
|
|
146
|
+
* Hydrated migration graph for the **app member**.
|
|
147
|
+
*
|
|
148
|
+
* The framework-neutral migration-tools layer doesn't know how to read
|
|
149
|
+
* the user's authored `migrations/` directory (the app member's
|
|
150
|
+
* migration-package layout is family-aware: ops.json shape, manifest
|
|
151
|
+
* keys, etc.). Callers — the SQL family today — read the user's
|
|
152
|
+
* `migrations/` and hand the resulting `OnDiskMigrationPackage[]` through.
|
|
153
|
+
*
|
|
154
|
+
* Passing `[]` is valid (greenfield project, no authored migrations).
|
|
155
|
+
* Equivalent to `migrations/` not existing or being empty.
|
|
156
|
+
*/
|
|
157
|
+
readonly appMigrationPackages: ReadonlyArray<OnDiskMigrationPackage>;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Discriminated failure variants the loader emits.
|
|
161
|
+
*
|
|
162
|
+
* Every variant short-circuits at first hit; the loader does not keep
|
|
163
|
+
* collecting after the first violation in any phase except for layout
|
|
164
|
+
* (where every layout offence is bundled into one `layoutViolation`).
|
|
165
|
+
*/
|
|
166
|
+
type LoadAggregateError = {
|
|
167
|
+
readonly kind: 'layoutViolation';
|
|
168
|
+
readonly violations: readonly LayoutViolation[];
|
|
169
|
+
} | {
|
|
170
|
+
readonly kind: 'integrityFailure';
|
|
171
|
+
readonly spaceId: string;
|
|
172
|
+
readonly detail: string;
|
|
173
|
+
} | {
|
|
174
|
+
readonly kind: 'validationFailure';
|
|
175
|
+
readonly spaceId: string;
|
|
176
|
+
readonly detail: string;
|
|
177
|
+
} | {
|
|
178
|
+
readonly kind: 'driftViolation';
|
|
179
|
+
readonly spaceId: string;
|
|
180
|
+
readonly priorHeadHash: string;
|
|
181
|
+
readonly liveHash: string;
|
|
182
|
+
} | {
|
|
183
|
+
readonly kind: 'disjointnessViolation';
|
|
184
|
+
readonly element: string;
|
|
185
|
+
readonly claimedBy: readonly string[];
|
|
186
|
+
} | {
|
|
187
|
+
readonly kind: 'targetMismatch';
|
|
188
|
+
readonly spaceId: string;
|
|
189
|
+
readonly expected: string;
|
|
190
|
+
readonly actual: string;
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* Single layout violation; bundled into a `layoutViolation` error so
|
|
194
|
+
* users see every layout offence at once rather than fixing them one
|
|
195
|
+
* at a time across re-runs.
|
|
196
|
+
*
|
|
197
|
+
* - `declaredButUnmigrated`: extension declared in `extensionPacks` with
|
|
198
|
+
* a `contractSpace` but no contract-space dir on disk. Remediation:
|
|
199
|
+
* `prisma-next migrate`.
|
|
200
|
+
* - `orphanSpaceDir`: contract-space dir under `migrations/` for an extension
|
|
201
|
+
* not in `extensionPacks`. Remediation: remove the directory, or
|
|
202
|
+
* re-add the extension to `extensionPacks`.
|
|
203
|
+
*/
|
|
204
|
+
type LayoutViolation = {
|
|
205
|
+
readonly kind: 'declaredButUnmigrated';
|
|
206
|
+
readonly spaceId: string;
|
|
207
|
+
} | {
|
|
208
|
+
readonly kind: 'orphanSpaceDir';
|
|
209
|
+
readonly spaceId: string;
|
|
210
|
+
};
|
|
211
|
+
type LoadAggregateOutput = Result<{
|
|
212
|
+
readonly aggregate: ContractSpaceAggregate;
|
|
213
|
+
}, LoadAggregateError>;
|
|
214
|
+
/**
|
|
215
|
+
* Hydrate a {@link ContractSpaceAggregate} from on-disk state and
|
|
216
|
+
* caller-provided descriptor data.
|
|
217
|
+
*
|
|
218
|
+
* This is the **only** descriptor-import boundary in the post-M2.5
|
|
219
|
+
* pipeline: callers read `extensionPacks` from `Config`, validate the
|
|
220
|
+
* app contract, and pass everything through. The loader composes
|
|
221
|
+
* existing migration-tools primitives — layout precheck (via
|
|
222
|
+
* {@link listContractSpaceDirectories}), integrity checks (via
|
|
223
|
+
* {@link readMigrationsDir} / {@link readContractSpaceHeadRef} /
|
|
224
|
+
* {@link readContractSpaceContract} / `validateContract`), drift detection
|
|
225
|
+
* (via {@link detectSpaceContractDrift}), and disjointness — into a
|
|
226
|
+
* single typed value.
|
|
227
|
+
*
|
|
228
|
+
* Failure semantics: every failure variant in {@link LoadAggregateError}
|
|
229
|
+
* short-circuits the load. Drift is fatal (M2.5 spec § Loader, step 5).
|
|
230
|
+
*/
|
|
231
|
+
declare function loadContractSpaceAggregate(input: LoadAggregateInput): Promise<LoadAggregateOutput>;
|
|
232
|
+
//#endregion
|
|
233
|
+
//#region src/aggregate/marker-types.d.ts
|
|
234
|
+
/**
|
|
235
|
+
* Structural shape the aggregate planner / verifier accept for marker
|
|
236
|
+
* rows. Mirrors `family.readAllMarkers(...)` outputs across SQL and
|
|
237
|
+
* Mongo families: a `(storageHash, invariants)` pair plus an optional
|
|
238
|
+
* `profileHash` the verifier uses to align the marker with the
|
|
239
|
+
* destination contract's profile envelope.
|
|
240
|
+
*
|
|
241
|
+
* Typed structurally so `migration-tools` stays framework-neutral; SQL
|
|
242
|
+
* and Mongo families pass their typed `ContractMarkerRecord` through
|
|
243
|
+
* unchanged.
|
|
244
|
+
*/
|
|
245
|
+
interface ContractMarkerRecordLike {
|
|
246
|
+
readonly storageHash: string;
|
|
247
|
+
readonly invariants: readonly string[];
|
|
248
|
+
readonly profileHash?: string;
|
|
249
|
+
}
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/aggregate/planner-types.d.ts
|
|
252
|
+
/**
|
|
253
|
+
* Caller-provided policy for {@link planAggregate}. Today this carries
|
|
254
|
+
* just one knob:
|
|
255
|
+
*
|
|
256
|
+
* - `ignoreGraphFor`: `Set<spaceId>`. For listed members, the planner
|
|
257
|
+
* forces the **synth** strategy (synthesise a plan from the contract
|
|
258
|
+
* IR via `familyInstance.createPlanner(...).plan(...)`) regardless of
|
|
259
|
+
* whether a graph is available. The CLI's daily-driver `db init` /
|
|
260
|
+
* `db update` pipelines pass `new Set([aggregate.app.spaceId])` to
|
|
261
|
+
* keep today's app-space behaviour: the user's authored
|
|
262
|
+
* `migrations/` directory is **not** walked for the app member, the
|
|
263
|
+
* plan is synthesised on the fly. Extension members are walked.
|
|
264
|
+
*
|
|
265
|
+
* Listing a member here whose `headRef.invariants` is non-empty is
|
|
266
|
+
* a `policyConflict` — synth cannot satisfy authored invariants.
|
|
267
|
+
*/
|
|
268
|
+
interface CallerPolicy {
|
|
269
|
+
readonly ignoreGraphFor: ReadonlySet<string>;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Snapshot of the live database state the planner needs to drive
|
|
273
|
+
* strategy selection.
|
|
274
|
+
*
|
|
275
|
+
* - `markersBySpaceId`: per-space marker rows. Absent entry = no
|
|
276
|
+
* marker yet (greenfield space). The planner treats the marker's
|
|
277
|
+
* `storageHash` as the graph-walk's `from` node, falling back to
|
|
278
|
+
* {@link import('../constants').EMPTY_CONTRACT_HASH} when absent.
|
|
279
|
+
* - `schemaIntrospection`: the family's full live schema IR. Fed into
|
|
280
|
+
* the synth strategy after per-space pre-projection via
|
|
281
|
+
* {@link import('./project-schema-to-space').projectSchemaToSpace}.
|
|
282
|
+
*
|
|
283
|
+
* Callers (CLI commands) gather this via the family's
|
|
284
|
+
* `readAllMarkers` + `introspect` calls before invoking the planner.
|
|
285
|
+
* The planner itself does not touch the database.
|
|
286
|
+
*/
|
|
287
|
+
interface AggregateCurrentDBState {
|
|
288
|
+
readonly markersBySpaceId: ReadonlyMap<string, ContractMarkerRecordLike | null>;
|
|
289
|
+
readonly schemaIntrospection: unknown;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Inputs to {@link planAggregate}.
|
|
293
|
+
*
|
|
294
|
+
* The planner is target-agnostic but family-aware: per-member synth
|
|
295
|
+
* delegates to the family's `createPlanner(familyInstance).plan(...)`,
|
|
296
|
+
* which is why `familyInstance`, `migrations` (the
|
|
297
|
+
* `TargetMigrationsCapability`), and `frameworkComponents` are all
|
|
298
|
+
* threaded through. (`frameworkComponents` is passed verbatim into
|
|
299
|
+
* `planner.plan(...)` per ADR 212; the planner does not interpret it.)
|
|
300
|
+
*
|
|
301
|
+
* The aggregate planner does **not** receive a `targetId` separately —
|
|
302
|
+
* it reads `aggregate.targetId` and stamps it onto every emitted
|
|
303
|
+
* `MigrationPlan` from construction. No placeholder, no patch step.
|
|
304
|
+
*/
|
|
305
|
+
interface AggregatePlannerInput<TFamilyId extends string, TTargetId extends string> {
|
|
306
|
+
readonly aggregate: ContractSpaceAggregate;
|
|
307
|
+
readonly currentDBState: AggregateCurrentDBState;
|
|
308
|
+
readonly familyInstance: ControlFamilyInstance<TFamilyId, unknown>;
|
|
309
|
+
readonly migrations: TargetMigrationsCapability<TFamilyId, TTargetId, ControlFamilyInstance<TFamilyId, unknown>>;
|
|
310
|
+
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;
|
|
311
|
+
readonly callerPolicy: CallerPolicy;
|
|
312
|
+
readonly operationPolicy: MigrationOperationPolicy;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Per-member output of the aggregate planner. The runner ingests this
|
|
316
|
+
* shape directly via a thin `toRunnerInput` adapter at the CLI.
|
|
317
|
+
*
|
|
318
|
+
* - `plan`: ready-to-execute `MigrationPlan` with `targetId` already
|
|
319
|
+
* set from `aggregate.targetId`.
|
|
320
|
+
* - `displayOps`: same operation list, surfaced separately so plan-mode
|
|
321
|
+
* output can render without touching the runner-bound `plan`.
|
|
322
|
+
* - `destinationContract`: the typed contract value the runner uses
|
|
323
|
+
* for post-apply verification. For the app member, the user's
|
|
324
|
+
* contract; for extension members, the on-disk `contract.json`.
|
|
325
|
+
* - `strategy`: which strategy produced this plan (`'graph-walk'` or
|
|
326
|
+
* `'synth'`). Surfaced for diagnostics; not consumed by the runner.
|
|
327
|
+
*/
|
|
328
|
+
interface AggregatePerSpacePlan {
|
|
329
|
+
readonly plan: MigrationPlan;
|
|
330
|
+
readonly displayOps: readonly MigrationPlanOperation[];
|
|
331
|
+
readonly destinationContract: Contract;
|
|
332
|
+
readonly strategy: 'graph-walk' | 'synth';
|
|
333
|
+
}
|
|
334
|
+
interface AggregatePlannerSuccess {
|
|
335
|
+
readonly perSpace: ReadonlyMap<string, AggregatePerSpacePlan>;
|
|
336
|
+
/**
|
|
337
|
+
* `applyOrder` is the order the runner must walk per-space inputs.
|
|
338
|
+
* Mirrors the existing `concatenateSpaceApplyInputs` convention:
|
|
339
|
+
* extensions alphabetically by `spaceId`, then the app. Tests assert
|
|
340
|
+
* on `MultiSpaceRunnerFailure.failingSpace`, which is positional in
|
|
341
|
+
* the runner's input array — preserving the literal ordering keeps
|
|
342
|
+
* `failingSpace` attribution byte-for-byte.
|
|
343
|
+
*/
|
|
344
|
+
readonly applyOrder: readonly string[];
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Discriminated failure variants for {@link planAggregate}. Each
|
|
348
|
+
* variant short-circuits the plan; per-member errors carry the
|
|
349
|
+
* `spaceId` so the CLI can surface a precise envelope.
|
|
350
|
+
*/
|
|
351
|
+
type AggregatePlannerError = {
|
|
352
|
+
readonly kind: 'extensionPathUnreachable';
|
|
353
|
+
readonly spaceId: string;
|
|
354
|
+
readonly target: string;
|
|
355
|
+
} | {
|
|
356
|
+
readonly kind: 'extensionPathUnsatisfiable';
|
|
357
|
+
readonly spaceId: string;
|
|
358
|
+
readonly missingInvariants: readonly string[];
|
|
359
|
+
} | {
|
|
360
|
+
readonly kind: 'appSynthFailure';
|
|
361
|
+
readonly spaceId: string;
|
|
362
|
+
readonly conflicts: readonly MigrationPlannerConflict[];
|
|
363
|
+
} | {
|
|
364
|
+
readonly kind: 'policyConflict';
|
|
365
|
+
readonly spaceId: string;
|
|
366
|
+
readonly detail: string;
|
|
367
|
+
};
|
|
368
|
+
type AggregatePlannerOutput = Result<AggregatePlannerSuccess, AggregatePlannerError>;
|
|
369
|
+
//#endregion
|
|
370
|
+
//#region src/aggregate/planner.d.ts
|
|
371
|
+
/**
|
|
372
|
+
* Plan a migration across every member of a {@link ContractSpaceAggregate}.
|
|
373
|
+
*
|
|
374
|
+
* Strategy selection per member, in order; first match wins:
|
|
375
|
+
*
|
|
376
|
+
* 1. If `callerPolicy.ignoreGraphFor.has(member.spaceId)`:
|
|
377
|
+
* - If `member.headRef.invariants` is empty → synth.
|
|
378
|
+
* - Else → `policyConflict` (synth cannot satisfy authored invariants).
|
|
379
|
+
* 2. Else if `member.migrations.graph` is non-empty AND graph-walk
|
|
380
|
+
* succeeds → graph-walk.
|
|
381
|
+
* 3. Else if `member.headRef.invariants` is empty → synth.
|
|
382
|
+
* 4. Else → graph-walk failure → `extensionPathUnreachable` /
|
|
383
|
+
* `extensionPathUnsatisfiable`.
|
|
384
|
+
*
|
|
385
|
+
* Output `applyOrder` is `[...aggregate.extensions.map(spaceId), aggregate.app.spaceId]`
|
|
386
|
+
* — extensions alphabetical, then app — matching today's
|
|
387
|
+
* `concatenateSpaceApplyInputs` ordering. This preserves
|
|
388
|
+
* `MultiSpaceRunnerFailure.failingSpace` attribution byte-for-byte.
|
|
389
|
+
*
|
|
390
|
+
* Every emitted `MigrationPlan` has `targetId = aggregate.targetId`.
|
|
391
|
+
* No placeholder cast; no patch step.
|
|
392
|
+
*/
|
|
393
|
+
declare function planAggregate<TFamilyId extends string, TTargetId extends string>(input: AggregatePlannerInput<TFamilyId, TTargetId>): Promise<AggregatePlannerOutput>;
|
|
394
|
+
//#endregion
|
|
395
|
+
//#region src/aggregate/project-schema-to-space.d.ts
|
|
396
|
+
/**
|
|
397
|
+
* Project the introspected live schema to the slice claimed by a single
|
|
398
|
+
* contract-space member.
|
|
399
|
+
*
|
|
400
|
+
* Returns the same `schema` value with every top-level table claimed by
|
|
401
|
+
* **other** members of the aggregate removed. Tables not claimed by any
|
|
402
|
+
* member flow through unchanged — the planner / verifier sees them as
|
|
403
|
+
* orphans (extras in strict mode).
|
|
404
|
+
*
|
|
405
|
+
* Used by:
|
|
406
|
+
*
|
|
407
|
+
* - The aggregate planner's **synth strategy**: when synthesising a
|
|
408
|
+
* plan against a member's contract, the live schema must be projected
|
|
409
|
+
* to that member's slice so the planner doesn't treat tables claimed
|
|
410
|
+
* by other members as "extras" and emit destructive ops to drop
|
|
411
|
+
* them.
|
|
412
|
+
* - The aggregate verifier's **schemaCheck**: projects per member so the
|
|
413
|
+
* single-contract `verifySqlSchema` only sees the slice claimed by
|
|
414
|
+
* the member it is checking. Closes the F23 architectural concern
|
|
415
|
+
* (multi-member deployments where each member's tables look like
|
|
416
|
+
* extras to every other member's verify pass).
|
|
417
|
+
*
|
|
418
|
+
* **Duck-typing semantics**: the helper operates on `unknown` for the
|
|
419
|
+
* schema and falls through structurally if the shape doesn't match.
|
|
420
|
+
* Every family today exposes `storage.tables: Record<string, ...>` and
|
|
421
|
+
* the introspected schema mirrors the same shape; a future family with
|
|
422
|
+
* a different storage shape gets the schema returned unchanged rather
|
|
423
|
+
* than blowing up the aggregate planner.
|
|
424
|
+
*/
|
|
425
|
+
declare function projectSchemaToSpace(schema: unknown, member: ContractSpaceMember, otherMembers: ReadonlyArray<ContractSpaceMember>): unknown;
|
|
426
|
+
//#endregion
|
|
427
|
+
//#region src/aggregate/verifier.d.ts
|
|
428
|
+
/**
|
|
429
|
+
* Caller policy for the aggregate verifier. Today's only knob is
|
|
430
|
+
* `mode`: `strict` treats orphan elements (live tables not claimed by
|
|
431
|
+
* any aggregate member) as errors; `lenient` treats them as
|
|
432
|
+
* informational. Maps directly to `db verify --strict`.
|
|
433
|
+
*/
|
|
434
|
+
interface AggregateVerifierInput<TSchemaResult> {
|
|
435
|
+
readonly aggregate: ContractSpaceAggregate;
|
|
436
|
+
readonly markersBySpaceId: ReadonlyMap<string, ContractMarkerRecordLike | null>;
|
|
437
|
+
readonly schemaIntrospection: unknown;
|
|
438
|
+
readonly mode: 'strict' | 'lenient';
|
|
439
|
+
/**
|
|
440
|
+
* Caller-supplied per-space schema verifier. The CLI wires this to
|
|
441
|
+
* the family's `verifySqlSchema` (SQL) / equivalent (other
|
|
442
|
+
* families). The aggregate verifier projects the schema to the
|
|
443
|
+
* member's slice via {@link projectSchemaToSpace} before invoking
|
|
444
|
+
* the callback, so single-contract semantics are preserved.
|
|
445
|
+
*
|
|
446
|
+
* Typed structurally with a generic `TSchemaResult` so the
|
|
447
|
+
* migration-tools layer doesn't depend on the SQL family's
|
|
448
|
+
* `VerifySqlSchemaResult`. CLI callers pass the family's type
|
|
449
|
+
* through unchanged.
|
|
450
|
+
*/
|
|
451
|
+
readonly verifySchemaForMember: (projectedSchema: unknown, member: ContractSpaceMember, mode: 'strict' | 'lenient') => TSchemaResult;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Marker-check result per member. Mirrors the four cases the
|
|
455
|
+
* `verifyContractSpaces` primitive surfaces today, plus an `'absent'`
|
|
456
|
+
* case for greenfield spaces (no marker row written yet — `db init`
|
|
457
|
+
* not run).
|
|
458
|
+
*/
|
|
459
|
+
type MarkerCheckResult = {
|
|
460
|
+
readonly kind: 'ok';
|
|
461
|
+
} | {
|
|
462
|
+
readonly kind: 'absent';
|
|
463
|
+
} | {
|
|
464
|
+
readonly kind: 'hashMismatch';
|
|
465
|
+
readonly markerHash: string;
|
|
466
|
+
readonly expected: string;
|
|
467
|
+
} | {
|
|
468
|
+
readonly kind: 'missingInvariants';
|
|
469
|
+
readonly missing: readonly string[];
|
|
470
|
+
};
|
|
471
|
+
interface MarkerCheckSection {
|
|
472
|
+
readonly perSpace: ReadonlyMap<string, MarkerCheckResult>;
|
|
473
|
+
readonly orphanMarkers: readonly {
|
|
474
|
+
readonly spaceId: string;
|
|
475
|
+
readonly row: ContractMarkerRecordLike;
|
|
476
|
+
}[];
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* A live storage element (today: a top-level table) not claimed by any
|
|
480
|
+
* member of the aggregate. The aggregate verifier always reports these;
|
|
481
|
+
* the caller decides what to do — `db verify --strict` treats them as
|
|
482
|
+
* errors, the lenient default treats them as informational.
|
|
483
|
+
*
|
|
484
|
+
* Today only `kind: 'table'` exists. The discriminated shape leaves
|
|
485
|
+
* room for orphan columns / indexes / sequences in the future without
|
|
486
|
+
* breaking the type contract.
|
|
487
|
+
*/
|
|
488
|
+
type OrphanElement = {
|
|
489
|
+
readonly kind: 'table';
|
|
490
|
+
readonly name: string;
|
|
491
|
+
};
|
|
492
|
+
interface SchemaCheckSection<TSchemaResult> {
|
|
493
|
+
readonly perSpace: ReadonlyMap<string, TSchemaResult>;
|
|
494
|
+
/**
|
|
495
|
+
* Live elements present in the introspected schema that are not
|
|
496
|
+
* claimed by **any** aggregate member. Sorted alphabetically by name.
|
|
497
|
+
*/
|
|
498
|
+
readonly orphanElements: readonly OrphanElement[];
|
|
499
|
+
}
|
|
500
|
+
interface AggregateVerifierSuccess<TSchemaResult> {
|
|
501
|
+
readonly markerCheck: MarkerCheckSection;
|
|
502
|
+
readonly schemaCheck: SchemaCheckSection<TSchemaResult>;
|
|
503
|
+
}
|
|
504
|
+
type AggregateVerifierError = {
|
|
505
|
+
readonly kind: 'introspectionFailure';
|
|
506
|
+
readonly detail: string;
|
|
507
|
+
};
|
|
508
|
+
type AggregateVerifierOutput<TSchemaResult> = Result<AggregateVerifierSuccess<TSchemaResult>, AggregateVerifierError>;
|
|
509
|
+
/**
|
|
510
|
+
* Verify a {@link ContractSpaceAggregate} against the live database
|
|
511
|
+
* state. Bundles two checks:
|
|
512
|
+
*
|
|
513
|
+
* - `markerCheck` per member: compare the live marker row against the
|
|
514
|
+
* member's `headRef.hash` + `headRef.invariants`. Absence is a
|
|
515
|
+
* distinct kind, not an error (callers — `db verify` strict vs
|
|
516
|
+
* `db init` precondition — choose how to interpret it).
|
|
517
|
+
* - `schemaCheck` per member: project the live schema to the slice
|
|
518
|
+
* the member claims via {@link projectSchemaToSpace}, then delegate
|
|
519
|
+
* to the caller-supplied `verifySchemaForMember`. The pre-projection
|
|
520
|
+
* means the family's single-contract verifier no longer sees other
|
|
521
|
+
* members' tables as `extras`, so a multi-member deployment never
|
|
522
|
+
* surfaces cross-member tables as orphaned schema elements.
|
|
523
|
+
*
|
|
524
|
+
* `markerCheck.orphanMarkers` lists every marker row whose `space` is
|
|
525
|
+
* not a member of the aggregate. `db verify` callers reject orphans;
|
|
526
|
+
* future tooling may not.
|
|
527
|
+
*
|
|
528
|
+
* Pure synchronous function; no I/O. The caller (CLI) gathers
|
|
529
|
+
* `markersBySpaceId` and `schemaIntrospection` ahead of the call.
|
|
530
|
+
*/
|
|
531
|
+
declare function verifyAggregate<TSchemaResult>(input: AggregateVerifierInput<TSchemaResult>): AggregateVerifierOutput<TSchemaResult>;
|
|
532
|
+
//#endregion
|
|
533
|
+
export { type AggregateContractHasher, type AggregateCurrentDBState, type AggregatePerSpacePlan, type AggregatePlannerError, type AggregatePlannerInput, type AggregatePlannerOutput, type AggregatePlannerSuccess, type AggregateVerifierError, type AggregateVerifierInput, type AggregateVerifierOutput, type AggregateVerifierSuccess, type CallerPolicy, type ContractMarkerRecordLike, type ContractSpaceAggregate, type ContractSpaceMember, type DeclaredExtensionEntry, type HydratedMigrationGraph, type LayoutViolation, type LoadAggregateError, type LoadAggregateInput, type LoadAggregateOutput, type MarkerCheckResult, type MarkerCheckSection, type OrphanElement, type SchemaCheckSection, loadContractSpaceAggregate, planAggregate, projectSchemaToSpace, verifyAggregate };
|
|
534
|
+
//# sourceMappingURL=aggregate.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate.d.mts","names":[],"sources":["../../src/aggregate/types.ts","../../src/aggregate/loader.ts","../../src/aggregate/marker-types.ts","../../src/aggregate/planner-types.ts","../../src/aggregate/planner.ts","../../src/aggregate/project-schema-to-space.ts","../../src/aggregate/verifier.ts"],"mappings":";;;;;;;;;;;;;AAkBA;;;;;;;;;UAAiB,sBAAA;EAAA,SACN,KAAA,EAAO,cAAA;EAAA,SACP,uBAAA,EAAyB,WAAA,SAAoB,sBAAA;AAAA;;;AAwBxD;;;;;;;;;;;;;;AAwCA;;;;;UAxCiB,mBAAA;EAAA,SACN,OAAA;EAAA,SACA,QAAA,EAAU,QAAA;EAAA,SACV,OAAA;IAAA,SACE,IAAA;IAAA,SACA,UAAA;EAAA;EAAA,SAEF,UAAA,EAAY,sBAAA;AAAA;AC5BvB;;;;;AAmBA;;;;;;;;;;AAiBA;;;;;;;;;;;;;;;AApCA,UD6DiB,sBAAA;EAAA,SACN,QAAA;EAAA,SACA,GAAA,EAAK,mBAAA;EAAA,SACL,UAAA,WAAqB,mBAAA;AAAA;;;;;;;AArEhC;;;;;;KCKY,uBAAA,IAA2B,QAAA;;;;;;;;;ADqBvC;;;;;;;;;UCFiB,sBAAA;EAAA,SACN,EAAA;EAAA,SACA,QAAA;EAAA,SACA,aAAA;IAAA,SACE,YAAA;EAAA;AAAA;;;;;;;;;;UAaI,kBAAA;EAAA,SACN,QAAA;EAAA,SACA,aAAA;EAAA,SACA,WAAA,EAAa,QAAA;EAAA,SACb,kBAAA,EAAoB,aAAA,CAAc,sBAAA;EAAA,SAClC,gBAAA,GAAmB,YAAA,cAA0B,QAAA;EAAA,SAC7C,YAAA,EAAc,uBAAA;EA1C+B;AAmBxD;;;;;;;;;;AAiBA;EApCwD,SAuD7C,oBAAA,EAAsB,aAAA,CAAc,sBAAA;AAAA;;;;;;;;KAUnC,kBAAA;EAAA,SACG,IAAA;EAAA,SAAkC,UAAA,WAAqB,eAAA;AAAA;EAAA,SACvD,IAAA;EAAA,SAAmC,OAAA;EAAA,SAA0B,MAAA;AAAA;EAAA,SAC7D,IAAA;EAAA,SAAoC,OAAA;EAAA,SAA0B,MAAA;AAAA;EAAA,SAE9D,IAAA;EAAA,SACA,OAAA;EAAA,SACA,aAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,OAAA;EAAA,SACA,SAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,OAAA;EAAA,SACA,QAAA;EAAA,SACA,MAAA;AAAA;;;;;;;;;;;;;KAeH,eAAA;EAAA,SACG,IAAA;EAAA,SAAwC,OAAA;AAAA;EAAA,SACxC,IAAA;EAAA,SAAiC,OAAA;AAAA;AAAA,KAEpC,mBAAA,GAAsB,MAAA;EAAA,SACrB,SAAA,EAAW,sBAAA;AAAA,GACtB,kBAAA;;;;;;;;AAFF;;;;;;;;;;iBA8BsB,0BAAA,CACpB,KAAA,EAAO,kBAAA,GACN,OAAA,CAAQ,mBAAA;;;;;;;;;;;AD5IX;;;UEPiB,wBAAA;EAAA,SACN,WAAA;EAAA,SACA,UAAA;EAAA,SACA,WAAA;AAAA;;;;;AFIX;;;;;;;;;;;;;;UGYiB,YAAA;EAAA,SACN,cAAA,EAAgB,WAAA;AAAA;;;;;;;;;;;;;AHqD3B;;;;UGlCiB,uBAAA;EAAA,SACN,gBAAA,EAAkB,WAAA,SAAoB,wBAAA;EAAA,SACtC,mBAAA;AAAA;;;;;;;AF7BX;;;;;AAmBA;;;UE2BiB,qBAAA;EAAA,SACN,SAAA,EAAW,sBAAA;EAAA,SACX,cAAA,EAAgB,uBAAA;EAAA,SAChB,cAAA,EAAgB,qBAAA,CAAsB,SAAA;EAAA,SACtC,UAAA,EAAY,0BAAA,CACnB,SAAA,EACA,SAAA,EACA,qBAAA,CAAsB,SAAA;EAAA,SAEf,mBAAA,EAAqB,aAAA,CAAc,8BAAA,CAA+B,SAAA,EAAW,SAAA;EAAA,SAC7E,YAAA,EAAc,YAAA;EAAA,SACd,eAAA,EAAiB,wBAAA;AAAA;;;;;;;;;;;;;;;UAiBX,qBAAA;EAAA,SACN,IAAA,EAAM,aAAA;EAAA,SACN,UAAA,WAAqB,sBAAA;EAAA,SACrB,mBAAA,EAAqB,QAAA;EAAA,SACrB,QAAA;AAAA;AAAA,UAGM,uBAAA;EAAA,SACN,QAAA,EAAU,WAAA,SAAoB,qBAAA;EF3B9B;;;;;AAUX;;;EAVW,SEoCA,UAAA;AAAA;;;;;;KAQC,qBAAA;EAAA,SACG,IAAA;EAAA,SAA2C,OAAA;EAAA,SAA0B,MAAA;AAAA;EAAA,SAErE,IAAA;EAAA,SACA,OAAA;EAAA,SACA,iBAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,OAAA;EAAA,SACA,SAAA,WAAoB,wBAAA;AAAA;EAAA,SAEpB,IAAA;EAAA,SAAiC,OAAA;EAAA,SAA0B,MAAA;AAAA;AAAA,KAE9D,sBAAA,GAAyB,MAAA,CAAO,uBAAA,EAAyB,qBAAA;;;;;;;;;AHtHrE;;;;;;;;;;;;;;;AA0BA;iBIDsB,aAAA,oDAAA,CACpB,KAAA,EAAO,qBAAA,CAAsB,SAAA,EAAW,SAAA,IACvC,OAAA,CAAQ,sBAAA;;;;;;;;;;AJ3BX;;;;;;;;;;;;;;;AA0BA;;;;;;;iBKbgB,oBAAA,CACd,MAAA,WACA,MAAA,EAAQ,mBAAA,EACR,YAAA,EAAc,aAAA,CAAc,mBAAA;;;;;;;;ALhB9B;UMNiB,sBAAA;EAAA,SACN,SAAA,EAAW,sBAAA;EAAA,SACX,gBAAA,EAAkB,WAAA,SAAoB,wBAAA;EAAA,SACtC,mBAAA;EAAA,SACA,IAAA;ENIoC;;;;;;;;;AAwB/C;;;EAxB+C,SMSpC,qBAAA,GACP,eAAA,WACA,MAAA,EAAQ,mBAAA,EACR,IAAA,2BACG,aAAA;AAAA;;;;;;;KASK,iBAAA;EAAA,SACG,IAAA;AAAA;EAAA,SACA,IAAA;AAAA;EAAA,SAEA,IAAA;EAAA,SACA,UAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAEA,IAAA;EAAA,SAAoC,OAAA;AAAA;AAAA,UAElC,kBAAA;EAAA,SACN,QAAA,EAAU,WAAA,SAAoB,iBAAA;EAAA,SAC9B,aAAA;IAAA,SACE,OAAA;IAAA,SACA,GAAA,EAAK,wBAAA;EAAA;AAAA;;;;ALdlB;;;;;;;KK4BY,aAAA;EAAA,SAA2B,IAAA;EAAA,SAAwB,IAAA;AAAA;AAAA,UAE9C,kBAAA;EAAA,SACN,QAAA,EAAU,WAAA,SAAoB,aAAA;ELXjB;;;;EAAA,SKgBb,cAAA,WAAyB,aAAA;AAAA;AAAA,UAGnB,wBAAA;EAAA,SACN,WAAA,EAAa,kBAAA;EAAA,SACb,WAAA,EAAa,kBAAA,CAAmB,aAAA;AAAA;AAAA,KAG/B,sBAAA;EAAA,SACD,IAAA;EAAA,SACA,MAAA;AAAA;AAAA,KAGC,uBAAA,kBAAyC,MAAA,CACnD,wBAAA,CAAyB,aAAA,GACzB,sBAAA;;;;;;;;;;;;ALLF;;;;;;;;;;;iBK8BgB,eAAA,eAAA,CACd,KAAA,EAAO,sBAAA,CAAuB,aAAA,IAC7B,uBAAA,CAAwB,aAAA"}
|