@prisma-next/migration-tools 0.3.0 → 0.4.0-dev.1

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.
@@ -7,4 +7,4 @@ const EMPTY_CONTRACT_HASH = "sha256:empty";
7
7
 
8
8
  //#endregion
9
9
  export { EMPTY_CONTRACT_HASH as t };
10
- //# sourceMappingURL=constants-9f-bCq8Y.mjs.map
10
+ //# sourceMappingURL=constants-DARNL_LD.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants-9f-bCq8Y.mjs","names":[],"sources":["../src/constants.ts"],"sourcesContent":["/**\n * Sentinel value representing the absence of a contract (empty/new project).\n * This is a human-readable marker, not a real SHA-256 hash.\n */\nexport const EMPTY_CONTRACT_HASH = 'sha256:empty' as const;\n"],"mappings":";;;;;AAIA,MAAa,sBAAsB"}
1
+ {"version":3,"file":"constants-DARNL_LD.mjs","names":[],"sources":["../src/constants.ts"],"sourcesContent":["/**\n * Sentinel value representing the absence of a contract (empty/new project).\n * This is a human-readable marker, not a real SHA-256 hash.\n */\nexport const EMPTY_CONTRACT_HASH = 'sha256:empty' as const;\n"],"mappings":";;;;;AAIA,MAAa,sBAAsB"}
@@ -150,4 +150,4 @@ function errorDuplicateMigrationId(migrationId) {
150
150
 
151
151
  //#endregion
152
152
  export { errorInvalidJson as a, errorInvalidRefValue as c, errorMissingFile as d, errorNoInitialMigration as f, errorDuplicateMigrationId as i, errorInvalidRefs as l, errorSameSourceAndTarget as m, errorAmbiguousTarget as n, errorInvalidManifest as o, errorNoTarget as p, errorDirectoryExists as r, errorInvalidRefName as s, MigrationToolsError as t, errorInvalidSlug as u };
153
- //# sourceMappingURL=errors-CSAAto11.mjs.map
153
+ //# sourceMappingURL=errors-C_XuSbX7.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors-CSAAto11.mjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\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, attestation,\n * migration history reconstruction), distinct from the runtime MIGRATION.* codes for apply-time\n * failures (PRECHECK_FAILED, POSTCHECK_FAILED, 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: 'Ensure the migration directory contains both migration.json and ops.json. If the directory is corrupt, delete it and re-run migration plan.',\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: 'Fix the JSON syntax error, or delete the migration directory and re-run migration plan.',\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: `Manifest at \"${filePath}\" is invalid: ${reason}`,\n fix: 'Ensure the manifest has all required fields (from, to, kind, toContract). If corrupt, delete and re-plan.',\n details: { filePath, reason },\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 errorSameSourceAndTarget(dirName: string, hash: string): MigrationToolsError {\n return new MigrationToolsError(\n 'MIGRATION.SAME_SOURCE_AND_TARGET',\n 'Migration has same source and target',\n {\n why: `Migration \"${dirName}\" has from === to === \"${hash}\". A migration must transition between two different contract states.`,\n fix: 'Delete the invalid migration directory and re-run migration plan.',\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 errorDuplicateMigrationId(migrationId: string): MigrationToolsError {\n return new MigrationToolsError(\n 'MIGRATION.DUPLICATE_MIGRATION_ID',\n 'Duplicate migrationId in migration graph',\n {\n why: `Multiple migrations share migrationId \"${migrationId}\". Each migration must have a unique content-addressed identity.`,\n fix: 'Regenerate one of the conflicting migrations so each migrationId is unique, then re-run migration commands.',\n details: { migrationId },\n },\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,IAAa,sBAAb,cAAyC,MAAM;CAC7C,AAAS;CACT,AAAS,WAAW;CACpB,AAAS;CACT,AAAS;CACT,AAAS;CAET,YACE,MACA,SACA,SAKA;AACA,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,OAAO;AACZ,OAAK,MAAM,QAAQ;AACnB,OAAK,MAAM,QAAQ;AACnB,OAAK,UAAU,QAAQ;;CAGzB,OAAO,GAAG,OAA8C;AACtD,MAAI,EAAE,iBAAiB,OAAQ,QAAO;EACtC,MAAM,YAAY;AAClB,SAAO,UAAU,SAAS,yBAAyB,OAAO,UAAU,SAAS;;;AAIjF,SAAgB,qBAAqB,KAAkC;AACrE,QAAO,IAAI,oBAAoB,wBAAwB,sCAAsC;EAC3F,KAAK,kBAAkB,IAAI;EAC3B,KAAK;EACL,SAAS,EAAE,KAAK;EACjB,CAAC;;AAGJ,SAAgB,iBAAiB,MAAc,KAAkC;AAC/E,QAAO,IAAI,oBAAoB,0BAA0B,WAAW,QAAQ;EAC1E,KAAK,aAAa,KAAK,QAAQ,IAAI;EACnC,KAAK;EACL,SAAS;GAAE;GAAM;GAAK;EACvB,CAAC;;AAGJ,SAAgB,iBAAiB,UAAkB,YAAyC;AAC1F,QAAO,IAAI,oBAAoB,0BAA0B,kCAAkC;EACzF,KAAK,oBAAoB,SAAS,KAAK;EACvC,KAAK;EACL,SAAS;GAAE;GAAU;GAAY;EAClC,CAAC;;AAGJ,SAAgB,qBAAqB,UAAkB,QAAqC;AAC1F,QAAO,IAAI,oBAAoB,8BAA8B,8BAA8B;EACzF,KAAK,gBAAgB,SAAS,gBAAgB;EAC9C,KAAK;EACL,SAAS;GAAE;GAAU;GAAQ;EAC9B,CAAC;;AAGJ,SAAgB,iBAAiB,MAAmC;AAClE,QAAO,IAAI,oBAAoB,0BAA0B,0BAA0B;EACjF,KAAK,aAAa,KAAK;EACvB,KAAK;EACL,SAAS,EAAE,MAAM;EAClB,CAAC;;AAGJ,SAAgB,yBAAyB,SAAiB,MAAmC;AAC3F,QAAO,IAAI,oBACT,oCACA,wCACA;EACE,KAAK,cAAc,QAAQ,yBAAyB,KAAK;EACzD,KAAK;EACL,SAAS;GAAE;GAAS;GAAM;EAC3B,CACF;;AAGH,SAAgB,qBACd,YACA,SAOqB;CACrB,MAAM,iBAAiB,UACnB,uBAAuB,QAAQ,gBAAgB,eAAe,QAAQ,SAAS,KAAK,MAAM,OAAO,EAAE,IAAI,IAAI,EAAE,MAAM,OAAO,YAAY,EAAE,MAAM,KAAK,MAAM,EAAE,QAAQ,CAAC,KAAK,MAAM,IAAI,SAAS,GAAG,CAAC,KAAK,KAAK,KAC1M;AACJ,QAAO,IAAI,oBAAoB,8BAA8B,8BAA8B;EACzF,KAAK,8DAA8D,WAAW,KAAK,KAAK,CAAC,4FAA4F;EACrL,KAAK;EACL,SAAS;GACP;GACA,GAAI,UAAU;IAAE,iBAAiB,QAAQ;IAAiB,UAAU,QAAQ;IAAU,GAAG,EAAE;GAC5F;EACF,CAAC;;AAGJ,SAAgB,wBAAwB,OAA+C;AACrF,QAAO,IAAI,oBAAoB,kCAAkC,8BAA8B;EAC7F,KAAK,oEAAoE,MAAM,KAAK,KAAK,CAAC;EAC1F,KAAK;EACL,SAAS,EAAE,OAAO;EACnB,CAAC;;AAGJ,SAAgB,iBAAiB,UAAkB,QAAqC;AACtF,QAAO,IAAI,oBAAoB,0BAA0B,qBAAqB;EAC5E,KAAK,iBAAiB,SAAS,gBAAgB;EAC/C,KAAK;EACL,SAAS;GAAE,MAAM;GAAU;GAAQ;EACpC,CAAC;;AAWJ,SAAgB,oBAAoB,SAAsC;AACxE,QAAO,IAAI,oBAAoB,8BAA8B,oBAAoB;EAC/E,KAAK,aAAa,QAAQ;EAC1B,KAAK;EACL,SAAS,EAAE,SAAS;EACrB,CAAC;;AAGJ,SAAgB,cAAc,iBAAyD;AACrF,QAAO,IAAI,oBAAoB,uBAAuB,yCAAyC;EAC7F,KAAK,wGAAwG,gBAAgB,KAAK,KAAK,CAAC;EACxI,KAAK;EACL,SAAS,EAAE,iBAAiB;EAC7B,CAAC;;AAGJ,SAAgB,qBAAqB,OAAoC;AACvE,QAAO,IAAI,oBAAoB,+BAA+B,qBAAqB;EACjF,KAAK,cAAc,MAAM;EACzB,KAAK;EACL,SAAS,EAAE,OAAO;EACnB,CAAC;;AAGJ,SAAgB,0BAA0B,aAA0C;AAClF,QAAO,IAAI,oBACT,oCACA,4CACA;EACE,KAAK,0CAA0C,YAAY;EAC3D,KAAK;EACL,SAAS,EAAE,aAAa;EACzB,CACF"}
1
+ {"version":3,"file":"errors-C_XuSbX7.mjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\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, attestation,\n * migration history reconstruction), distinct from the runtime MIGRATION.* codes for apply-time\n * failures (PRECHECK_FAILED, POSTCHECK_FAILED, 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: 'Ensure the migration directory contains both migration.json and ops.json. If the directory is corrupt, delete it and re-run migration plan.',\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: 'Fix the JSON syntax error, or delete the migration directory and re-run migration plan.',\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: `Manifest at \"${filePath}\" is invalid: ${reason}`,\n fix: 'Ensure the manifest has all required fields (from, to, kind, toContract). If corrupt, delete and re-plan.',\n details: { filePath, reason },\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 errorSameSourceAndTarget(dirName: string, hash: string): MigrationToolsError {\n return new MigrationToolsError(\n 'MIGRATION.SAME_SOURCE_AND_TARGET',\n 'Migration has same source and target',\n {\n why: `Migration \"${dirName}\" has from === to === \"${hash}\". A migration must transition between two different contract states.`,\n fix: 'Delete the invalid migration directory and re-run migration plan.',\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 errorDuplicateMigrationId(migrationId: string): MigrationToolsError {\n return new MigrationToolsError(\n 'MIGRATION.DUPLICATE_MIGRATION_ID',\n 'Duplicate migrationId in migration graph',\n {\n why: `Multiple migrations share migrationId \"${migrationId}\". Each migration must have a unique content-addressed identity.`,\n fix: 'Regenerate one of the conflicting migrations so each migrationId is unique, then re-run migration commands.',\n details: { migrationId },\n },\n );\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { l as MigrationManifest, u as MigrationOps } from "../types-BW_pJEe8.mjs";
1
+ import { l as MigrationManifest, u as MigrationOps } from "../types-DXjq7Fum.mjs";
2
2
 
3
3
  //#region src/attestation.d.ts
4
4
  interface VerifyResult {
@@ -1,4 +1,4 @@
1
- import { i as writeMigrationManifest, n as readMigrationPackage } from "../io-LsuurzNb.mjs";
1
+ import { i as writeMigrationManifest, n as readMigrationPackage } from "../io-BO18-Evu.mjs";
2
2
  import { createHash } from "node:crypto";
3
3
  import { canonicalizeContract } from "@prisma-next/contract/hashing";
4
4
 
@@ -1,3 +1,3 @@
1
- import { t as EMPTY_CONTRACT_HASH } from "../constants-9f-bCq8Y.mjs";
1
+ import { t as EMPTY_CONTRACT_HASH } from "../constants-DARNL_LD.mjs";
2
2
 
3
3
  export { EMPTY_CONTRACT_HASH };
@@ -1,4 +1,4 @@
1
- import { o as MigrationChainEntry, s as MigrationGraph, t as AttestedMigrationBundle } from "../types-BW_pJEe8.mjs";
1
+ import { o as MigrationChainEntry, s as MigrationGraph, t as AttestedMigrationBundle } from "../types-DXjq7Fum.mjs";
2
2
 
3
3
  //#region src/dag.d.ts
4
4
  declare function reconstructGraph(packages: readonly AttestedMigrationBundle[]): MigrationGraph;
@@ -1,5 +1,5 @@
1
- import { f as errorNoInitialMigration, i as errorDuplicateMigrationId, m as errorSameSourceAndTarget, n as errorAmbiguousTarget, p as errorNoTarget } from "../errors-CSAAto11.mjs";
2
- import { t as EMPTY_CONTRACT_HASH } from "../constants-9f-bCq8Y.mjs";
1
+ import { f as errorNoInitialMigration, i as errorDuplicateMigrationId, m as errorSameSourceAndTarget, n as errorAmbiguousTarget, p as errorNoTarget } from "../errors-C_XuSbX7.mjs";
2
+ import { t as EMPTY_CONTRACT_HASH } from "../constants-DARNL_LD.mjs";
3
3
  import { ifDefined } from "@prisma-next/utils/defined";
4
4
 
5
5
  //#region src/dag.ts
@@ -1,4 +1,4 @@
1
- import { l as MigrationManifest, r as BaseMigrationBundle, u as MigrationOps } from "../types-BW_pJEe8.mjs";
1
+ import { l as MigrationManifest, r as BaseMigrationBundle, u as MigrationOps } from "../types-DXjq7Fum.mjs";
2
2
 
3
3
  //#region src/io.d.ts
4
4
  declare function writeMigrationPackage(dir: string, manifest: MigrationManifest, ops: MigrationOps): Promise<void>;
@@ -1,3 +1,3 @@
1
- import { a as writeMigrationOps, i as writeMigrationManifest, n as readMigrationPackage, o as writeMigrationPackage, r as readMigrationsDir, t as formatMigrationDirName } from "../io-LsuurzNb.mjs";
1
+ import { a as writeMigrationOps, i as writeMigrationManifest, n as readMigrationPackage, o as writeMigrationPackage, r as readMigrationsDir, t as formatMigrationDirName } from "../io-BO18-Evu.mjs";
2
2
 
3
3
  export { formatMigrationDirName, readMigrationPackage, readMigrationsDir, writeMigrationManifest, writeMigrationOps, writeMigrationPackage };
@@ -0,0 +1,28 @@
1
+ //#region src/migration-base.d.ts
2
+ interface MigrationMeta {
3
+ readonly from: string;
4
+ readonly to: string;
5
+ readonly kind?: 'regular' | 'baseline';
6
+ readonly labels?: readonly string[];
7
+ }
8
+ declare abstract class Migration<TOperation = unknown> {
9
+ abstract plan(): TOperation[];
10
+ describe(): MigrationMeta | undefined;
11
+ /**
12
+ * Entrypoint guard for migration files. When called at module scope,
13
+ * detects whether the file is being run directly (e.g. `tsx migration.ts`)
14
+ * and if so, serializes the migration plan to `ops.json` (and optionally
15
+ * `migration.json`) in the same directory. When the file is imported by
16
+ * another module, this is a no-op.
17
+ *
18
+ * Usage (at module scope, after the class definition):
19
+ *
20
+ * class MyMigration extends Migration { ... }
21
+ * export default MyMigration;
22
+ * Migration.run(import.meta.url, MyMigration);
23
+ */
24
+ static run(importMetaUrl: string, MigrationClass: new () => Migration): void;
25
+ }
26
+ //#endregion
27
+ export { Migration, type MigrationMeta };
28
+ //# sourceMappingURL=migration.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration.d.mts","names":[],"sources":["../../src/migration-base.ts"],"sourcesContent":[],"mappings":";UAKiB,aAAA;EAAA,SAAA,IAAA,EAAA,MAAa;EAcR,SAAA,EAAA,EAAS,MAAA;EACZ,SAAA,IAAA,CAAA,EAAA,SAAA,GAAA,UAAA;EAEL,SAAA,MAAA,CAAA,EAAA,SAAA,MAAA,EAAA;;AAiByD,uBApBjD,SAoBiD,CAAA,aAAA,OAAA,CAAA,CAAA;mBAnBpD;cAEL;;;;;;;;;;;;;;8DAiBgD"}
@@ -0,0 +1,105 @@
1
+ import { type } from "arktype";
2
+ import { dirname, join } from "pathe";
3
+ import { realpathSync, writeFileSync } from "node:fs";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ //#region src/migration-base.ts
7
+ const MigrationMetaSchema = type({
8
+ from: "string",
9
+ to: "string",
10
+ "kind?": "'regular' | 'baseline'",
11
+ "labels?": "string[]"
12
+ });
13
+ var Migration = class {
14
+ describe() {}
15
+ /**
16
+ * Entrypoint guard for migration files. When called at module scope,
17
+ * detects whether the file is being run directly (e.g. `tsx migration.ts`)
18
+ * and if so, serializes the migration plan to `ops.json` (and optionally
19
+ * `migration.json`) in the same directory. When the file is imported by
20
+ * another module, this is a no-op.
21
+ *
22
+ * Usage (at module scope, after the class definition):
23
+ *
24
+ * class MyMigration extends Migration { ... }
25
+ * export default MyMigration;
26
+ * Migration.run(import.meta.url, MyMigration);
27
+ */
28
+ static run(importMetaUrl, MigrationClass) {
29
+ if (!importMetaUrl) return;
30
+ const metaFilename = fileURLToPath(importMetaUrl);
31
+ const argv1 = process.argv[1];
32
+ if (!argv1) return;
33
+ let isEntrypoint;
34
+ try {
35
+ isEntrypoint = realpathSync(metaFilename) === realpathSync(argv1);
36
+ } catch {
37
+ return;
38
+ }
39
+ if (!isEntrypoint) return;
40
+ const args = process.argv.slice(2);
41
+ if (args.includes("--help")) {
42
+ printHelp();
43
+ return;
44
+ }
45
+ const dryRun = args.includes("--dry-run");
46
+ const migrationDir = dirname(metaFilename);
47
+ try {
48
+ serializeMigration(MigrationClass, migrationDir, dryRun);
49
+ } catch (err) {
50
+ process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
51
+ process.exitCode = 1;
52
+ }
53
+ }
54
+ };
55
+ function printHelp() {
56
+ process.stdout.write([
57
+ "Usage: tsx <migration-file> [options]",
58
+ "",
59
+ "Options:",
60
+ " --dry-run Print operations to stdout without writing files",
61
+ " --help Show this help message",
62
+ ""
63
+ ].join("\n"));
64
+ }
65
+ function buildManifest(meta) {
66
+ return {
67
+ migrationId: null,
68
+ from: meta.from,
69
+ to: meta.to,
70
+ kind: meta.kind ?? "regular",
71
+ labels: meta.labels ?? [],
72
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
73
+ };
74
+ }
75
+ function serializeMigration(MigrationClass, migrationDir, dryRun) {
76
+ const instance = new MigrationClass();
77
+ const ops = instance.plan();
78
+ if (!Array.isArray(ops)) throw new Error("plan() must return an array of operations");
79
+ const serializedOps = JSON.stringify(ops, null, 2);
80
+ let manifest;
81
+ if (typeof instance.describe === "function") {
82
+ const rawMeta = instance.describe();
83
+ if (rawMeta !== void 0) {
84
+ const parsed = MigrationMetaSchema(rawMeta);
85
+ if (parsed instanceof type.errors) throw new Error(`describe() returned invalid metadata: ${parsed.summary}`);
86
+ manifest = buildManifest(parsed);
87
+ }
88
+ }
89
+ if (dryRun) {
90
+ if (manifest) {
91
+ process.stdout.write(`--- migration.json ---\n${JSON.stringify(manifest, null, 2)}\n`);
92
+ process.stdout.write("--- ops.json ---\n");
93
+ }
94
+ process.stdout.write(`${serializedOps}\n`);
95
+ return;
96
+ }
97
+ writeFileSync(join(migrationDir, "ops.json"), serializedOps);
98
+ if (manifest) writeFileSync(join(migrationDir, "migration.json"), JSON.stringify(manifest, null, 2));
99
+ const files = manifest ? "ops.json + migration.json" : "ops.json";
100
+ process.stdout.write(`Wrote ${files} to ${migrationDir}\n`);
101
+ }
102
+
103
+ //#endregion
104
+ export { Migration };
105
+ //# sourceMappingURL=migration.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration.mjs","names":["isEntrypoint: boolean","manifest: Record<string, unknown> | undefined","rawMeta: unknown"],"sources":["../../src/migration-base.ts"],"sourcesContent":["import { realpathSync, writeFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { type } from 'arktype';\nimport { dirname, join } from 'pathe';\n\nexport interface MigrationMeta {\n readonly from: string;\n readonly to: string;\n readonly kind?: 'regular' | 'baseline';\n readonly labels?: readonly string[];\n}\n\nconst MigrationMetaSchema = type({\n from: 'string',\n to: 'string',\n 'kind?': \"'regular' | 'baseline'\",\n 'labels?': 'string[]',\n});\n\nexport abstract class Migration<TOperation = unknown> {\n abstract plan(): TOperation[];\n\n describe(): MigrationMeta | undefined {\n return undefined;\n }\n\n /**\n * Entrypoint guard for migration files. When called at module scope,\n * detects whether the file is being run directly (e.g. `tsx migration.ts`)\n * and if so, serializes the migration plan to `ops.json` (and optionally\n * `migration.json`) in the same directory. When the file is imported by\n * another module, this is a no-op.\n *\n * Usage (at module scope, after the class definition):\n *\n * class MyMigration extends Migration { ... }\n * export default MyMigration;\n * Migration.run(import.meta.url, MyMigration);\n */\n static run(importMetaUrl: string, MigrationClass: new () => Migration): void {\n if (!importMetaUrl) return;\n\n const metaFilename = fileURLToPath(importMetaUrl);\n const argv1 = process.argv[1];\n if (!argv1) return;\n\n let isEntrypoint: boolean;\n try {\n isEntrypoint = realpathSync(metaFilename) === realpathSync(argv1);\n } catch {\n return;\n }\n if (!isEntrypoint) return;\n\n const args = process.argv.slice(2);\n\n if (args.includes('--help')) {\n printHelp();\n return;\n }\n\n const dryRun = args.includes('--dry-run');\n const migrationDir = dirname(metaFilename);\n\n try {\n serializeMigration(MigrationClass, migrationDir, dryRun);\n } catch (err) {\n process.stderr.write(`${err instanceof Error ? err.message : String(err)}\\n`);\n process.exitCode = 1;\n }\n }\n}\n\nfunction printHelp(): void {\n process.stdout.write(\n [\n 'Usage: tsx <migration-file> [options]',\n '',\n 'Options:',\n ' --dry-run Print operations to stdout without writing files',\n ' --help Show this help message',\n '',\n ].join('\\n'),\n );\n}\n\nfunction buildManifest(meta: MigrationMeta): Record<string, unknown> {\n return {\n migrationId: null,\n from: meta.from,\n to: meta.to,\n kind: meta.kind ?? 'regular',\n labels: meta.labels ?? [],\n createdAt: new Date().toISOString(),\n };\n}\n\nfunction serializeMigration(\n MigrationClass: new () => Migration,\n migrationDir: string,\n dryRun: boolean,\n): void {\n const instance = new MigrationClass();\n\n const ops = instance.plan();\n\n if (!Array.isArray(ops)) {\n throw new Error('plan() must return an array of operations');\n }\n\n const serializedOps = JSON.stringify(ops, null, 2);\n\n let manifest: Record<string, unknown> | undefined;\n if (typeof instance.describe === 'function') {\n const rawMeta: unknown = instance.describe();\n if (rawMeta !== undefined) {\n const parsed = MigrationMetaSchema(rawMeta);\n if (parsed instanceof type.errors) {\n throw new Error(`describe() returned invalid metadata: ${parsed.summary}`);\n }\n manifest = buildManifest(parsed);\n }\n }\n\n if (dryRun) {\n if (manifest) {\n process.stdout.write(`--- migration.json ---\\n${JSON.stringify(manifest, null, 2)}\\n`);\n process.stdout.write('--- ops.json ---\\n');\n }\n process.stdout.write(`${serializedOps}\\n`);\n return;\n }\n\n writeFileSync(join(migrationDir, 'ops.json'), serializedOps);\n if (manifest) {\n writeFileSync(join(migrationDir, 'migration.json'), JSON.stringify(manifest, null, 2));\n }\n\n const files = manifest ? 'ops.json + migration.json' : 'ops.json';\n process.stdout.write(`Wrote ${files} to ${migrationDir}\\n`);\n}\n"],"mappings":";;;;;;AAYA,MAAM,sBAAsB,KAAK;CAC/B,MAAM;CACN,IAAI;CACJ,SAAS;CACT,WAAW;CACZ,CAAC;AAEF,IAAsB,YAAtB,MAAsD;CAGpD,WAAsC;;;;;;;;;;;;;;CAiBtC,OAAO,IAAI,eAAuB,gBAA2C;AAC3E,MAAI,CAAC,cAAe;EAEpB,MAAM,eAAe,cAAc,cAAc;EACjD,MAAM,QAAQ,QAAQ,KAAK;AAC3B,MAAI,CAAC,MAAO;EAEZ,IAAIA;AACJ,MAAI;AACF,kBAAe,aAAa,aAAa,KAAK,aAAa,MAAM;UAC3D;AACN;;AAEF,MAAI,CAAC,aAAc;EAEnB,MAAM,OAAO,QAAQ,KAAK,MAAM,EAAE;AAElC,MAAI,KAAK,SAAS,SAAS,EAAE;AAC3B,cAAW;AACX;;EAGF,MAAM,SAAS,KAAK,SAAS,YAAY;EACzC,MAAM,eAAe,QAAQ,aAAa;AAE1C,MAAI;AACF,sBAAmB,gBAAgB,cAAc,OAAO;WACjD,KAAK;AACZ,WAAQ,OAAO,MAAM,GAAG,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CAAC,IAAI;AAC7E,WAAQ,WAAW;;;;AAKzB,SAAS,YAAkB;AACzB,SAAQ,OAAO,MACb;EACE;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK,CACb;;AAGH,SAAS,cAAc,MAA8C;AACnE,QAAO;EACL,aAAa;EACb,MAAM,KAAK;EACX,IAAI,KAAK;EACT,MAAM,KAAK,QAAQ;EACnB,QAAQ,KAAK,UAAU,EAAE;EACzB,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC;;AAGH,SAAS,mBACP,gBACA,cACA,QACM;CACN,MAAM,WAAW,IAAI,gBAAgB;CAErC,MAAM,MAAM,SAAS,MAAM;AAE3B,KAAI,CAAC,MAAM,QAAQ,IAAI,CACrB,OAAM,IAAI,MAAM,4CAA4C;CAG9D,MAAM,gBAAgB,KAAK,UAAU,KAAK,MAAM,EAAE;CAElD,IAAIC;AACJ,KAAI,OAAO,SAAS,aAAa,YAAY;EAC3C,MAAMC,UAAmB,SAAS,UAAU;AAC5C,MAAI,YAAY,QAAW;GACzB,MAAM,SAAS,oBAAoB,QAAQ;AAC3C,OAAI,kBAAkB,KAAK,OACzB,OAAM,IAAI,MAAM,yCAAyC,OAAO,UAAU;AAE5E,cAAW,cAAc,OAAO;;;AAIpC,KAAI,QAAQ;AACV,MAAI,UAAU;AACZ,WAAQ,OAAO,MAAM,2BAA2B,KAAK,UAAU,UAAU,MAAM,EAAE,CAAC,IAAI;AACtF,WAAQ,OAAO,MAAM,qBAAqB;;AAE5C,UAAQ,OAAO,MAAM,GAAG,cAAc,IAAI;AAC1C;;AAGF,eAAc,KAAK,cAAc,WAAW,EAAE,cAAc;AAC5D,KAAI,SACF,eAAc,KAAK,cAAc,iBAAiB,EAAE,KAAK,UAAU,UAAU,MAAM,EAAE,CAAC;CAGxF,MAAM,QAAQ,WAAW,8BAA8B;AACvD,SAAQ,OAAO,MAAM,SAAS,MAAM,MAAM,aAAa,IAAI"}
@@ -1,4 +1,4 @@
1
- import { c as errorInvalidRefValue, l as errorInvalidRefs, s as errorInvalidRefName, t as MigrationToolsError } from "../errors-CSAAto11.mjs";
1
+ import { c as errorInvalidRefValue, l as errorInvalidRefs, s as errorInvalidRefName, t as MigrationToolsError } from "../errors-C_XuSbX7.mjs";
2
2
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
3
3
  import { type } from "arktype";
4
4
  import { dirname, join } from "pathe";
@@ -1,4 +1,4 @@
1
- import { a as DraftMigrationManifest, c as MigrationHints, d as isAttested, f as isDraft, i as DraftMigrationBundle, l as MigrationManifest, n as AttestedMigrationManifest, o as MigrationChainEntry, r as BaseMigrationBundle, s as MigrationGraph, t as AttestedMigrationBundle, u as MigrationOps } from "../types-BW_pJEe8.mjs";
1
+ import { a as DraftMigrationManifest, c as MigrationHints, d as isAttested, f as isDraft, i as DraftMigrationBundle, l as MigrationManifest, n as AttestedMigrationManifest, o as MigrationChainEntry, r as BaseMigrationBundle, s as MigrationGraph, t as AttestedMigrationBundle, u as MigrationOps } from "../types-DXjq7Fum.mjs";
2
2
 
3
3
  //#region src/errors.d.ts
4
4
 
@@ -1,4 +1,4 @@
1
- import { t as MigrationToolsError } from "../errors-CSAAto11.mjs";
1
+ import { t as MigrationToolsError } from "../errors-C_XuSbX7.mjs";
2
2
 
3
3
  //#region src/types.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { a as errorInvalidJson, d as errorMissingFile, o as errorInvalidManifest, r as errorDirectoryExists, u as errorInvalidSlug } from "./errors-CSAAto11.mjs";
1
+ import { a as errorInvalidJson, d as errorMissingFile, o as errorInvalidManifest, r as errorDirectoryExists, u as errorInvalidSlug } from "./errors-C_XuSbX7.mjs";
2
2
  import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
3
3
  import { type } from "arktype";
4
4
  import { basename, dirname, join } from "pathe";
@@ -133,4 +133,4 @@ function formatMigrationDirName(timestamp, slug) {
133
133
 
134
134
  //#endregion
135
135
  export { writeMigrationOps as a, writeMigrationManifest as i, readMigrationPackage as n, writeMigrationPackage as o, readMigrationsDir as r, formatMigrationDirName as t };
136
- //# sourceMappingURL=io-LsuurzNb.mjs.map
136
+ //# sourceMappingURL=io-BO18-Evu.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"io-LsuurzNb.mjs","names":["manifestRaw: string","opsRaw: string","manifest: MigrationManifest","ops: MigrationOps","entries: string[]","packages: BaseMigrationBundle[]"],"sources":["../src/io.ts"],"sourcesContent":["import { mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';\nimport { type } from 'arktype';\nimport { basename, dirname, join } from 'pathe';\nimport {\n errorDirectoryExists,\n errorInvalidJson,\n errorInvalidManifest,\n errorInvalidSlug,\n errorMissingFile,\n} from './errors';\nimport type { BaseMigrationBundle, MigrationManifest, MigrationOps } from './types';\n\nconst MANIFEST_FILE = 'migration.json';\nconst OPS_FILE = 'ops.json';\nconst MAX_SLUG_LENGTH = 64;\n\nfunction hasErrnoCode(error: unknown, code: string): boolean {\n return error instanceof Error && (error as { code?: string }).code === code;\n}\n\nconst MigrationHintsSchema = type({\n used: 'string[]',\n applied: 'string[]',\n plannerVersion: 'string',\n planningStrategy: 'string',\n});\n\nconst MigrationManifestSchema = type({\n from: 'string',\n to: 'string',\n migrationId: 'string | null',\n kind: \"'regular' | 'baseline'\",\n fromContract: 'object | null',\n toContract: 'object',\n hints: MigrationHintsSchema,\n labels: 'string[]',\n 'authorship?': type({\n 'author?': 'string',\n 'email?': 'string',\n }),\n 'signature?': type({\n keyId: 'string',\n value: 'string',\n }).or('null'),\n createdAt: 'string',\n});\n\nconst MigrationOpSchema = type({\n id: 'string',\n label: 'string',\n operationClass: \"'additive' | 'widening' | 'destructive' | 'data'\",\n});\n\n// Intentionally shallow: operation-specific payload validation is owned by planner/runner layers.\nconst MigrationOpsSchema = MigrationOpSchema.array();\n\nexport async function writeMigrationPackage(\n dir: string,\n manifest: MigrationManifest,\n ops: MigrationOps,\n): Promise<void> {\n await mkdir(dirname(dir), { recursive: true });\n\n try {\n await mkdir(dir);\n } catch (error) {\n if (hasErrnoCode(error, 'EEXIST')) {\n throw errorDirectoryExists(dir);\n }\n throw error;\n }\n\n await writeFile(join(dir, MANIFEST_FILE), JSON.stringify(manifest, null, 2), { flag: 'wx' });\n await writeFile(join(dir, OPS_FILE), JSON.stringify(ops, null, 2), { flag: 'wx' });\n}\n\nexport async function writeMigrationManifest(\n dir: string,\n manifest: MigrationManifest,\n): Promise<void> {\n await writeFile(join(dir, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}\\n`);\n}\n\nexport async function writeMigrationOps(dir: string, ops: MigrationOps): Promise<void> {\n await writeFile(join(dir, OPS_FILE), `${JSON.stringify(ops, null, 2)}\\n`);\n}\n\nexport async function readMigrationPackage(dir: string): Promise<BaseMigrationBundle> {\n const manifestPath = join(dir, MANIFEST_FILE);\n const opsPath = join(dir, OPS_FILE);\n\n let manifestRaw: string;\n try {\n manifestRaw = await readFile(manifestPath, 'utf-8');\n } catch (error) {\n if (hasErrnoCode(error, 'ENOENT')) {\n throw errorMissingFile(MANIFEST_FILE, dir);\n }\n throw error;\n }\n\n let opsRaw: string;\n try {\n opsRaw = await readFile(opsPath, 'utf-8');\n } catch (error) {\n if (hasErrnoCode(error, 'ENOENT')) {\n throw errorMissingFile(OPS_FILE, dir);\n }\n throw error;\n }\n\n let manifest: MigrationManifest;\n try {\n manifest = JSON.parse(manifestRaw);\n } catch (e) {\n throw errorInvalidJson(manifestPath, e instanceof Error ? e.message : String(e));\n }\n\n let ops: MigrationOps;\n try {\n ops = JSON.parse(opsRaw);\n } catch (e) {\n throw errorInvalidJson(opsPath, e instanceof Error ? e.message : String(e));\n }\n\n validateManifest(manifest, manifestPath);\n validateOps(ops, opsPath);\n\n return {\n dirName: basename(dir),\n dirPath: dir,\n manifest,\n ops,\n };\n}\n\nfunction validateManifest(\n manifest: unknown,\n filePath: string,\n): asserts manifest is MigrationManifest {\n const result = MigrationManifestSchema(manifest);\n if (result instanceof type.errors) {\n throw errorInvalidManifest(filePath, result.summary);\n }\n}\n\nfunction validateOps(ops: unknown, filePath: string): asserts ops is MigrationOps {\n const result = MigrationOpsSchema(ops);\n if (result instanceof type.errors) {\n throw errorInvalidManifest(filePath, result.summary);\n }\n}\n\nexport async function readMigrationsDir(\n migrationsRoot: string,\n): Promise<readonly BaseMigrationBundle[]> {\n let entries: string[];\n try {\n entries = await readdir(migrationsRoot);\n } catch (error) {\n if (hasErrnoCode(error, 'ENOENT')) {\n return [];\n }\n throw error;\n }\n\n const packages: BaseMigrationBundle[] = [];\n\n for (const entry of entries.sort()) {\n const entryPath = join(migrationsRoot, entry);\n const entryStat = await stat(entryPath);\n if (!entryStat.isDirectory()) continue;\n\n const manifestPath = join(entryPath, MANIFEST_FILE);\n try {\n await stat(manifestPath);\n } catch {\n continue; // skip non-migration directories\n }\n\n packages.push(await readMigrationPackage(entryPath));\n }\n\n return packages;\n}\n\nexport function formatMigrationDirName(timestamp: Date, slug: string): string {\n const sanitized = slug\n .toLowerCase()\n .replace(/[^a-z0-9]/g, '_')\n .replace(/_+/g, '_')\n .replace(/^_|_$/g, '');\n\n if (sanitized.length === 0) {\n throw errorInvalidSlug(slug);\n }\n\n const truncated = sanitized.slice(0, MAX_SLUG_LENGTH);\n\n const y = timestamp.getUTCFullYear();\n const mo = String(timestamp.getUTCMonth() + 1).padStart(2, '0');\n const d = String(timestamp.getUTCDate()).padStart(2, '0');\n const h = String(timestamp.getUTCHours()).padStart(2, '0');\n const mi = String(timestamp.getUTCMinutes()).padStart(2, '0');\n\n return `${y}${mo}${d}T${h}${mi}_${truncated}`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"io-BO18-Evu.mjs","names":["manifestRaw: string","opsRaw: string","manifest: MigrationManifest","ops: MigrationOps","entries: string[]","packages: BaseMigrationBundle[]"],"sources":["../src/io.ts"],"sourcesContent":["import { mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';\nimport { type } from 'arktype';\nimport { basename, dirname, join } from 'pathe';\nimport {\n errorDirectoryExists,\n errorInvalidJson,\n errorInvalidManifest,\n errorInvalidSlug,\n errorMissingFile,\n} from './errors';\nimport type { BaseMigrationBundle, MigrationManifest, MigrationOps } from './types';\n\nconst MANIFEST_FILE = 'migration.json';\nconst OPS_FILE = 'ops.json';\nconst MAX_SLUG_LENGTH = 64;\n\nfunction hasErrnoCode(error: unknown, code: string): boolean {\n return error instanceof Error && (error as { code?: string }).code === code;\n}\n\nconst MigrationHintsSchema = type({\n used: 'string[]',\n applied: 'string[]',\n plannerVersion: 'string',\n planningStrategy: 'string',\n});\n\nconst MigrationManifestSchema = type({\n from: 'string',\n to: 'string',\n migrationId: 'string | null',\n kind: \"'regular' | 'baseline'\",\n fromContract: 'object | null',\n toContract: 'object',\n hints: MigrationHintsSchema,\n labels: 'string[]',\n 'authorship?': type({\n 'author?': 'string',\n 'email?': 'string',\n }),\n 'signature?': type({\n keyId: 'string',\n value: 'string',\n }).or('null'),\n createdAt: 'string',\n});\n\nconst MigrationOpSchema = type({\n id: 'string',\n label: 'string',\n operationClass: \"'additive' | 'widening' | 'destructive' | 'data'\",\n});\n\n// Intentionally shallow: operation-specific payload validation is owned by planner/runner layers.\nconst MigrationOpsSchema = MigrationOpSchema.array();\n\nexport async function writeMigrationPackage(\n dir: string,\n manifest: MigrationManifest,\n ops: MigrationOps,\n): Promise<void> {\n await mkdir(dirname(dir), { recursive: true });\n\n try {\n await mkdir(dir);\n } catch (error) {\n if (hasErrnoCode(error, 'EEXIST')) {\n throw errorDirectoryExists(dir);\n }\n throw error;\n }\n\n await writeFile(join(dir, MANIFEST_FILE), JSON.stringify(manifest, null, 2), { flag: 'wx' });\n await writeFile(join(dir, OPS_FILE), JSON.stringify(ops, null, 2), { flag: 'wx' });\n}\n\nexport async function writeMigrationManifest(\n dir: string,\n manifest: MigrationManifest,\n): Promise<void> {\n await writeFile(join(dir, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}\\n`);\n}\n\nexport async function writeMigrationOps(dir: string, ops: MigrationOps): Promise<void> {\n await writeFile(join(dir, OPS_FILE), `${JSON.stringify(ops, null, 2)}\\n`);\n}\n\nexport async function readMigrationPackage(dir: string): Promise<BaseMigrationBundle> {\n const manifestPath = join(dir, MANIFEST_FILE);\n const opsPath = join(dir, OPS_FILE);\n\n let manifestRaw: string;\n try {\n manifestRaw = await readFile(manifestPath, 'utf-8');\n } catch (error) {\n if (hasErrnoCode(error, 'ENOENT')) {\n throw errorMissingFile(MANIFEST_FILE, dir);\n }\n throw error;\n }\n\n let opsRaw: string;\n try {\n opsRaw = await readFile(opsPath, 'utf-8');\n } catch (error) {\n if (hasErrnoCode(error, 'ENOENT')) {\n throw errorMissingFile(OPS_FILE, dir);\n }\n throw error;\n }\n\n let manifest: MigrationManifest;\n try {\n manifest = JSON.parse(manifestRaw);\n } catch (e) {\n throw errorInvalidJson(manifestPath, e instanceof Error ? e.message : String(e));\n }\n\n let ops: MigrationOps;\n try {\n ops = JSON.parse(opsRaw);\n } catch (e) {\n throw errorInvalidJson(opsPath, e instanceof Error ? e.message : String(e));\n }\n\n validateManifest(manifest, manifestPath);\n validateOps(ops, opsPath);\n\n return {\n dirName: basename(dir),\n dirPath: dir,\n manifest,\n ops,\n };\n}\n\nfunction validateManifest(\n manifest: unknown,\n filePath: string,\n): asserts manifest is MigrationManifest {\n const result = MigrationManifestSchema(manifest);\n if (result instanceof type.errors) {\n throw errorInvalidManifest(filePath, result.summary);\n }\n}\n\nfunction validateOps(ops: unknown, filePath: string): asserts ops is MigrationOps {\n const result = MigrationOpsSchema(ops);\n if (result instanceof type.errors) {\n throw errorInvalidManifest(filePath, result.summary);\n }\n}\n\nexport async function readMigrationsDir(\n migrationsRoot: string,\n): Promise<readonly BaseMigrationBundle[]> {\n let entries: string[];\n try {\n entries = await readdir(migrationsRoot);\n } catch (error) {\n if (hasErrnoCode(error, 'ENOENT')) {\n return [];\n }\n throw error;\n }\n\n const packages: BaseMigrationBundle[] = [];\n\n for (const entry of entries.sort()) {\n const entryPath = join(migrationsRoot, entry);\n const entryStat = await stat(entryPath);\n if (!entryStat.isDirectory()) continue;\n\n const manifestPath = join(entryPath, MANIFEST_FILE);\n try {\n await stat(manifestPath);\n } catch {\n continue; // skip non-migration directories\n }\n\n packages.push(await readMigrationPackage(entryPath));\n }\n\n return packages;\n}\n\nexport function formatMigrationDirName(timestamp: Date, slug: string): string {\n const sanitized = slug\n .toLowerCase()\n .replace(/[^a-z0-9]/g, '_')\n .replace(/_+/g, '_')\n .replace(/^_|_$/g, '');\n\n if (sanitized.length === 0) {\n throw errorInvalidSlug(slug);\n }\n\n const truncated = sanitized.slice(0, MAX_SLUG_LENGTH);\n\n const y = timestamp.getUTCFullYear();\n const mo = String(timestamp.getUTCMonth() + 1).padStart(2, '0');\n const d = String(timestamp.getUTCDate()).padStart(2, '0');\n const h = String(timestamp.getUTCHours()).padStart(2, '0');\n const mi = String(timestamp.getUTCMinutes()).padStart(2, '0');\n\n return `${y}${mo}${d}T${h}${mi}_${truncated}`;\n}\n"],"mappings":"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"}
@@ -97,4 +97,4 @@ declare function isAttested(bundle: BaseMigrationBundle): bundle is AttestedMigr
97
97
  declare function isDraft(bundle: BaseMigrationBundle): bundle is DraftMigrationBundle;
98
98
  //#endregion
99
99
  export { DraftMigrationManifest as a, MigrationHints as c, isAttested as d, isDraft as f, DraftMigrationBundle as i, MigrationManifest as l, AttestedMigrationManifest as n, MigrationChainEntry as o, BaseMigrationBundle as r, MigrationGraph as s, AttestedMigrationBundle as t, MigrationOps as u };
100
- //# sourceMappingURL=types-BW_pJEe8.d.mts.map
100
+ //# sourceMappingURL=types-DXjq7Fum.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types-BW_pJEe8.d.mts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;UAGiB,cAAA;;EAAA,SAAA,OAAA,EAAc,SAAA,MAAA,EAAA;EAUrB,SAAA,cAAA,EAAqB,MAAA;EAIN,SAAA,gBAAA,EAAA,MAAA;;;;AAczB;AAQA,UA1BU,qBAAA,CA0BiC;EAS/B,SAAA,IAAA,EAAA,MAAiB;EAEjB,SAAA,EAAA,EAAA,MAAY;EAMP,SAAA,IAAA,EAAA,SAAmB,GAAA,UAGf;EAQJ,SAAA,YAAA,EAlDQ,QAkDgB,GAAA,IACpB;EAGJ,SAAA,UAAA,EArDM,QAqDe;EAQrB,SAAA,KAAA,EA5DC,cA4DkB;EASnB,SAAA,MAAA,EAAc,SAAA,MAAA,EAAA;EACb,SAAA,UAAA,CAAA,EAAA;IACoC,SAAA,MAAA,CAAA,EAAA,MAAA;IAA7B,SAAA,KAAA,CAAA,EAAA,MAAA;EAC6B,CAAA;EAA7B,SAAA,SAAA,CAAA,EAAA;IACqB,SAAA,KAAA,EAAA,MAAA;IAApB,SAAA,KAAA,EAAA,MAAA;EAAW,CAAA,GAAA,IAAA;EAOrB,SAAA,SAAU,EAAA,MAAS;AAInC;;;;;;UAxEiB,sBAAA,SAA+B;;;;;;;UAQ/B,yBAAA,SAAkC;;;;;;;;KASvC,iBAAA,GAAoB,yBAAyB;KAE7C,YAAA,YAAwB;;;;;UAMnB,mBAAA;;;qBAGI;gBACL;;;;;;UAOC,uBAAA,SAAgC;qBAC5B;;UAGJ,oBAAA,SAA6B;qBACzB;;;;;;UAOJ,mBAAA;;;;;;;;UASA,cAAA;kBACC;yBACO,6BAA6B;yBAC7B,6BAA6B;0BAC5B,oBAAoB;;;;;;iBAO9B,UAAA,SAAmB,gCAAgC;iBAInD,OAAA,SAAgB,gCAAgC"}
1
+ {"version":3,"file":"types-DXjq7Fum.d.mts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;UAGiB,cAAA;;EAAA,SAAA,OAAA,EAAc,SAAA,MAAA,EAAA;EAUrB,SAAA,cAAA,EAAqB,MAAA;EAIN,SAAA,gBAAA,EAAA,MAAA;;;;AAczB;AAQA,UA1BU,qBAAA,CA0BiC;EAS/B,SAAA,IAAA,EAAA,MAAiB;EAEjB,SAAA,EAAA,EAAA,MAAY;EAMP,SAAA,IAAA,EAAA,SAAmB,GAAA,UAGf;EAQJ,SAAA,YAAA,EAlDQ,QAkDgB,GAAA,IACpB;EAGJ,SAAA,UAAA,EArDM,QAqDe;EAQrB,SAAA,KAAA,EA5DC,cA4DkB;EASnB,SAAA,MAAA,EAAc,SAAA,MAAA,EAAA;EACb,SAAA,UAAA,CAAA,EAAA;IACoC,SAAA,MAAA,CAAA,EAAA,MAAA;IAA7B,SAAA,KAAA,CAAA,EAAA,MAAA;EAC6B,CAAA;EAA7B,SAAA,SAAA,CAAA,EAAA;IACqB,SAAA,KAAA,EAAA,MAAA;IAApB,SAAA,KAAA,EAAA,MAAA;EAAW,CAAA,GAAA,IAAA;EAOrB,SAAA,SAAU,EAAA,MAAS;AAInC;;;;;;UAxEiB,sBAAA,SAA+B;;;;;;;UAQ/B,yBAAA,SAAkC;;;;;;;;KASvC,iBAAA,GAAoB,yBAAyB;KAE7C,YAAA,YAAwB;;;;;UAMnB,mBAAA;;;qBAGI;gBACL;;;;;;UAOC,uBAAA,SAAgC;qBAC5B;;UAGJ,oBAAA,SAA6B;qBACzB;;;;;;UAOJ,mBAAA;;;;;;;;UASA,cAAA;kBACC;yBACO,6BAA6B;yBAC7B,6BAA6B;0BAC5B,oBAAoB;;;;;;iBAO9B,UAAA,SAAmB,gCAAgC;iBAInD,OAAA,SAAgB,gCAAgC"}
package/package.json CHANGED
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "name": "@prisma-next/migration-tools",
3
- "version": "0.3.0",
3
+ "version": "0.4.0-dev.1",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "On-disk migration persistence, attestation, and chain reconstruction for Prisma Next",
7
7
  "dependencies": {
8
8
  "arktype": "^2.1.29",
9
9
  "pathe": "^2.0.3",
10
- "@prisma-next/contract": "0.3.0",
11
- "@prisma-next/framework-components": "0.3.0",
12
- "@prisma-next/utils": "0.3.0"
10
+ "@prisma-next/contract": "0.4.0-dev.1",
11
+ "@prisma-next/utils": "0.4.0-dev.1",
12
+ "@prisma-next/framework-components": "0.4.0-dev.1"
13
13
  },
14
14
  "devDependencies": {
15
15
  "tsdown": "0.18.4",
16
16
  "typescript": "5.9.3",
17
17
  "vitest": "4.0.17",
18
- "@prisma-next/tsconfig": "0.0.0",
19
- "@prisma-next/tsdown": "0.0.0"
18
+ "@prisma-next/tsdown": "0.0.0",
19
+ "@prisma-next/tsconfig": "0.0.0"
20
20
  },
21
21
  "files": [
22
22
  "dist",
@@ -54,6 +54,10 @@
54
54
  "types": "./dist/exports/migration-ts.d.mts",
55
55
  "import": "./dist/exports/migration-ts.mjs"
56
56
  },
57
+ "./migration": {
58
+ "types": "./dist/exports/migration.d.mts",
59
+ "import": "./dist/exports/migration.mjs"
60
+ },
57
61
  "./package.json": "./package.json"
58
62
  },
59
63
  "repository": {
@@ -0,0 +1 @@
1
+ export { Migration, type MigrationMeta } from '../migration-base';
@@ -0,0 +1,141 @@
1
+ import { realpathSync, writeFileSync } from 'node:fs';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { type } from 'arktype';
4
+ import { dirname, join } from 'pathe';
5
+
6
+ export interface MigrationMeta {
7
+ readonly from: string;
8
+ readonly to: string;
9
+ readonly kind?: 'regular' | 'baseline';
10
+ readonly labels?: readonly string[];
11
+ }
12
+
13
+ const MigrationMetaSchema = type({
14
+ from: 'string',
15
+ to: 'string',
16
+ 'kind?': "'regular' | 'baseline'",
17
+ 'labels?': 'string[]',
18
+ });
19
+
20
+ export abstract class Migration<TOperation = unknown> {
21
+ abstract plan(): TOperation[];
22
+
23
+ describe(): MigrationMeta | undefined {
24
+ return undefined;
25
+ }
26
+
27
+ /**
28
+ * Entrypoint guard for migration files. When called at module scope,
29
+ * detects whether the file is being run directly (e.g. `tsx migration.ts`)
30
+ * and if so, serializes the migration plan to `ops.json` (and optionally
31
+ * `migration.json`) in the same directory. When the file is imported by
32
+ * another module, this is a no-op.
33
+ *
34
+ * Usage (at module scope, after the class definition):
35
+ *
36
+ * class MyMigration extends Migration { ... }
37
+ * export default MyMigration;
38
+ * Migration.run(import.meta.url, MyMigration);
39
+ */
40
+ static run(importMetaUrl: string, MigrationClass: new () => Migration): void {
41
+ if (!importMetaUrl) return;
42
+
43
+ const metaFilename = fileURLToPath(importMetaUrl);
44
+ const argv1 = process.argv[1];
45
+ if (!argv1) return;
46
+
47
+ let isEntrypoint: boolean;
48
+ try {
49
+ isEntrypoint = realpathSync(metaFilename) === realpathSync(argv1);
50
+ } catch {
51
+ return;
52
+ }
53
+ if (!isEntrypoint) return;
54
+
55
+ const args = process.argv.slice(2);
56
+
57
+ if (args.includes('--help')) {
58
+ printHelp();
59
+ return;
60
+ }
61
+
62
+ const dryRun = args.includes('--dry-run');
63
+ const migrationDir = dirname(metaFilename);
64
+
65
+ try {
66
+ serializeMigration(MigrationClass, migrationDir, dryRun);
67
+ } catch (err) {
68
+ process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
69
+ process.exitCode = 1;
70
+ }
71
+ }
72
+ }
73
+
74
+ function printHelp(): void {
75
+ process.stdout.write(
76
+ [
77
+ 'Usage: tsx <migration-file> [options]',
78
+ '',
79
+ 'Options:',
80
+ ' --dry-run Print operations to stdout without writing files',
81
+ ' --help Show this help message',
82
+ '',
83
+ ].join('\n'),
84
+ );
85
+ }
86
+
87
+ function buildManifest(meta: MigrationMeta): Record<string, unknown> {
88
+ return {
89
+ migrationId: null,
90
+ from: meta.from,
91
+ to: meta.to,
92
+ kind: meta.kind ?? 'regular',
93
+ labels: meta.labels ?? [],
94
+ createdAt: new Date().toISOString(),
95
+ };
96
+ }
97
+
98
+ function serializeMigration(
99
+ MigrationClass: new () => Migration,
100
+ migrationDir: string,
101
+ dryRun: boolean,
102
+ ): void {
103
+ const instance = new MigrationClass();
104
+
105
+ const ops = instance.plan();
106
+
107
+ if (!Array.isArray(ops)) {
108
+ throw new Error('plan() must return an array of operations');
109
+ }
110
+
111
+ const serializedOps = JSON.stringify(ops, null, 2);
112
+
113
+ let manifest: Record<string, unknown> | undefined;
114
+ if (typeof instance.describe === 'function') {
115
+ const rawMeta: unknown = instance.describe();
116
+ if (rawMeta !== undefined) {
117
+ const parsed = MigrationMetaSchema(rawMeta);
118
+ if (parsed instanceof type.errors) {
119
+ throw new Error(`describe() returned invalid metadata: ${parsed.summary}`);
120
+ }
121
+ manifest = buildManifest(parsed);
122
+ }
123
+ }
124
+
125
+ if (dryRun) {
126
+ if (manifest) {
127
+ process.stdout.write(`--- migration.json ---\n${JSON.stringify(manifest, null, 2)}\n`);
128
+ process.stdout.write('--- ops.json ---\n');
129
+ }
130
+ process.stdout.write(`${serializedOps}\n`);
131
+ return;
132
+ }
133
+
134
+ writeFileSync(join(migrationDir, 'ops.json'), serializedOps);
135
+ if (manifest) {
136
+ writeFileSync(join(migrationDir, 'migration.json'), JSON.stringify(manifest, null, 2));
137
+ }
138
+
139
+ const files = manifest ? 'ops.json + migration.json' : 'ops.json';
140
+ process.stdout.write(`Wrote ${files} to ${migrationDir}\n`);
141
+ }