@prisma-next/cli 0.16.0-dev.4 → 0.16.0-dev.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -4
- package/dist/cli.mjs +6 -6
- package/dist/commands/db-sign.d.mts.map +1 -1
- package/dist/commands/db-sign.mjs +4 -6
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +5 -8
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/migrate.mjs +2 -2
- package/dist/commands/migration-check.d.mts +3 -1
- package/dist/commands/migration-check.d.mts.map +1 -1
- package/dist/commands/migration-check.mjs +1 -1
- package/dist/commands/migration-graph.mjs +1 -1
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +1 -1
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +12 -36
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-status.mjs +1 -1
- package/dist/commands/ref.d.mts.map +1 -1
- package/dist/commands/ref.mjs +7 -9
- package/dist/commands/ref.mjs.map +1 -1
- package/dist/{contract-at-errors-D9gEjYtg.mjs → contract-at-errors-CTtzKR6q.mjs} +6 -10
- package/dist/contract-at-errors-CTtzKR6q.mjs.map +1 -0
- package/dist/exports/init-output.d.mts.map +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{init-C3JhkHg-.mjs → init-CgKEi_t5.mjs} +53 -45
- package/dist/init-CgKEi_t5.mjs.map +1 -0
- package/dist/{migration-check-MHT3w7_v.mjs → migration-check-CcuayFB2.mjs} +49 -22
- package/dist/migration-check-CcuayFB2.mjs.map +1 -0
- package/dist/{migration-list-BAKujUjh.mjs → migration-list-6z6vuXHa.mjs} +3 -3
- package/dist/migration-list-6z6vuXHa.mjs.map +1 -0
- package/dist/{migration-plan-CreSVtWZ.mjs → migration-plan-DuMEUejG.mjs} +46 -54
- package/dist/migration-plan-DuMEUejG.mjs.map +1 -0
- package/dist/{migration-status-YgEvXf-u.mjs → migration-status-B61YOaMl.mjs} +3 -2
- package/dist/{migration-status-YgEvXf-u.mjs.map → migration-status-B61YOaMl.mjs.map} +1 -1
- package/dist/{output-mEQ74_nd.mjs → output-DWNYqZGc.mjs} +5 -6
- package/dist/output-DWNYqZGc.mjs.map +1 -0
- package/package.json +21 -21
- package/src/commands/db-sign.ts +6 -4
- package/src/commands/db-update.ts +13 -6
- package/src/commands/init/hygiene-gitattributes.ts +37 -21
- package/src/commands/init/init.ts +6 -6
- package/src/commands/init/output.ts +4 -5
- package/src/commands/init/reinit-cleanup.ts +16 -17
- package/src/commands/migration-check.ts +69 -32
- package/src/commands/migration-list.ts +1 -5
- package/src/commands/migration-new.ts +15 -39
- package/src/commands/migration-plan.ts +54 -76
- package/src/commands/ref.ts +18 -7
- package/src/utils/contract-at-errors.ts +9 -13
- package/src/utils/contract-space-seed-phase.ts +8 -6
- package/src/utils/plan-resolution.ts +1 -4
- package/dist/contract-at-errors-D9gEjYtg.mjs.map +0 -1
- package/dist/init-C3JhkHg-.mjs.map +0 -1
- package/dist/migration-check-MHT3w7_v.mjs.map +0 -1
- package/dist/migration-list-BAKujUjh.mjs.map +0 -1
- package/dist/migration-plan-CreSVtWZ.mjs.map +0 -1
- package/dist/output-mEQ74_nd.mjs.map +0 -1
package/dist/commands/ref.mjs
CHANGED
|
@@ -5,11 +5,11 @@ import { Command } from "commander";
|
|
|
5
5
|
import { loadConfig } from "@prisma-next/config-loader";
|
|
6
6
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
7
7
|
import { join } from "pathe";
|
|
8
|
-
import { readFile } from "node:fs/promises";
|
|
9
8
|
import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
|
|
10
9
|
import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
|
|
11
10
|
import { findLatestMigration, isGraphNode } from "@prisma-next/migration-tools/migration-graph";
|
|
12
11
|
import { deleteRefPaired, readRefs, validateRefName, validateRefValue, writeRefPaired } from "@prisma-next/migration-tools/refs";
|
|
12
|
+
import { contractSnapshotDir, readContractSnapshotJson } from "@prisma-next/migration-tools/contract-snapshot-store";
|
|
13
13
|
import { parseContractRef } from "@prisma-next/migration-tools/ref-resolution";
|
|
14
14
|
//#region src/commands/ref.ts
|
|
15
15
|
function mapError(error) {
|
|
@@ -47,17 +47,15 @@ async function executeRefSetCommand(name, contractInput, options) {
|
|
|
47
47
|
const graphTip = findLatestMigration(graph)?.to ?? null;
|
|
48
48
|
return notOk(errorRefSetHashNotInGraph(resolvedHash, [...graph.nodes].sort(), graphTip));
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const contractJsonPath = join(matchingBundle.dirPath, "end-contract.json");
|
|
50
|
+
if (!bundles.find((bundle) => bundle.metadata.to === resolvedHash)) return notOk(errorRefSetBundleNotFound(resolvedHash));
|
|
51
|
+
const contractJsonPath = join(contractSnapshotDir(migrationsDir, resolvedHash), "contract.json");
|
|
53
52
|
let contractJson;
|
|
54
53
|
try {
|
|
55
|
-
|
|
56
|
-
contractJson = JSON.parse(raw);
|
|
54
|
+
contractJson = await readContractSnapshotJson(migrationsDir, resolvedHash);
|
|
57
55
|
} catch (readError) {
|
|
58
|
-
if (readError
|
|
59
|
-
why: `Migration bundle for hash ${resolvedHash} is missing its
|
|
60
|
-
fix: "
|
|
56
|
+
if (MigrationToolsError.is(readError) && readError.code === "MIGRATION.CONTRACT_SNAPSHOT_MISSING") return notOk(errorFileNotFound(contractJsonPath, {
|
|
57
|
+
why: `Migration bundle for hash ${resolvedHash} is missing its contract snapshot at ${contractJsonPath}`,
|
|
58
|
+
fix: "Restore migrations/snapshots/ from version control, or re-run the command that produced this migration to regenerate its snapshot."
|
|
61
59
|
}));
|
|
62
60
|
throw readError;
|
|
63
61
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ref.mjs","names":[],"sources":["../../src/commands/ref.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { loadConfig } from '@prisma-next/config-loader';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findLatestMigration, isGraphNode } from '@prisma-next/migration-tools/migration-graph';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport type { RefEntry } from '@prisma-next/migration-tools/refs';\nimport {\n deleteRefPaired,\n readRefs,\n validateRefName,\n validateRefValue,\n writeRefPaired,\n} from '@prisma-next/migration-tools/refs';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join } from 'pathe';\nimport {\n CliStructuredError,\n errorFileNotFound,\n errorRefSetBundleNotFound,\n errorRefSetEmptySentinel,\n errorRefSetHashNotInGraph,\n errorRuntime,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n resolveMigrationPaths,\n setCommandDescriptions,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport { formatCommandHelp } from '../utils/formatters/help';\nimport { parseGlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { readContractIR } from '../utils/ref-advancement';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI } from '../utils/terminal-ui';\n\ninterface RefSetResult {\n readonly ok: true;\n readonly ref: string;\n readonly hash: string;\n readonly invariants: readonly string[];\n}\n\ninterface RefDeleteResult {\n readonly ok: true;\n readonly ref: string;\n readonly deleted: true;\n}\n\ninterface RefListResult {\n readonly ok: true;\n readonly refs: Record<string, RefEntry>;\n}\n\nfunction mapError(error: unknown): CliStructuredError {\n if (MigrationToolsError.is(error)) {\n return mapMigrationToolsError(error);\n }\n return errorUnexpected(error instanceof Error ? error.message : String(error));\n}\n\nfunction cliErrorInvalidRefName(name: string): CliStructuredError {\n return errorRuntime(`Invalid ref name \"${name}\"`, {\n why: `Ref name \"${name}\" does not match the required format`,\n fix: 'Ref names must be lowercase alphanumeric with hyphens or forward slashes, no `.` or `..` segments',\n });\n}\n\nexport async function executeRefSetCommand(\n name: string,\n contractInput: string,\n options: { config?: string },\n): Promise<Result<RefSetResult, CliStructuredError>> {\n if (!validateRefName(name)) {\n return notOk(cliErrorInvalidRefName(name));\n }\n\n try {\n const config = await loadConfig(options.config);\n const { migrationsDir, refsDir } = resolveMigrationPaths(options.config, config);\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return notOk(loaded.failure);\n }\n const graph = loaded.value.aggregate.app.graph();\n const bundles = loaded.value.aggregate.app.packages;\n const refs = loaded.value.aggregate.app.refs;\n\n let resolvedHash: string;\n if (validateRefValue(contractInput)) {\n resolvedHash = contractInput;\n } else {\n const refResult = parseContractRef(contractInput, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n resolvedHash = refResult.value.hash;\n }\n\n if (resolvedHash === EMPTY_CONTRACT_HASH) {\n return notOk(errorRefSetEmptySentinel(resolvedHash));\n }\n if (!isGraphNode(resolvedHash, graph)) {\n const graphTip = findLatestMigration(graph)?.to ?? null;\n return notOk(errorRefSetHashNotInGraph(resolvedHash, [...graph.nodes].sort(), graphTip));\n }\n\n const matchingBundle = bundles.find((bundle) => bundle.metadata.to === resolvedHash);\n if (!matchingBundle) {\n return notOk(errorRefSetBundleNotFound(resolvedHash));\n }\n\n const contractJsonPath = join(matchingBundle.dirPath, 'end-contract.json');\n let contractJson: Record<string, unknown>;\n try {\n const raw = await readFile(contractJsonPath, 'utf-8');\n contractJson = JSON.parse(raw) as Record<string, unknown>;\n } catch (readError) {\n if (readError instanceof Error && (readError as NodeJS.ErrnoException).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractJsonPath, {\n why: `Migration bundle for hash ${resolvedHash} is missing its end-contract snapshot at ${contractJsonPath}`,\n fix: 'Run `pnpm fixtures:check`, or re-emit the migration so its end-contract.json is restored.',\n }),\n );\n }\n throw readError;\n }\n\n const contractIR = await readContractIR(contractJson, contractJsonPath);\n const entry: RefEntry = { hash: resolvedHash, invariants: [] };\n await writeRefPaired(refsDir, name, entry, contractIR);\n return ok({ ok: true as const, ref: name, hash: resolvedHash, invariants: [] });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nexport async function executeRefDeleteCommand(\n name: string,\n options: { config?: string },\n): Promise<Result<RefDeleteResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n await deleteRefPaired(refsDir, name);\n return ok({ ok: true as const, ref: name, deleted: true as const });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nexport async function executeRefListCommand(options: {\n config?: string;\n}): Promise<Result<RefListResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n const refs = await readRefs(refsDir);\n return ok({ ok: true as const, refs });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nfunction createRefSetCommand(): Command {\n const command = new Command('set');\n setCommandDescriptions(\n command,\n 'Set a ref to a contract reference',\n 'Sets a named ref to point to a resolved contract reference (hash, alias, or path) in migrations/refs/.',\n );\n addGlobalOptions(command)\n .argument('<name>', 'Ref name (e.g., staging, production)')\n .argument(\n '<contract>',\n 'Contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n hash: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeRefSetCommand(name, hash, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n ui.output(`Set ref \"${value.ref}\" → ${value.hash}`);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefDeleteCommand(): Command {\n const command = new Command('delete');\n setCommandDescriptions(command, 'Delete a ref', 'Removes a named ref from migrations/refs/.');\n addGlobalOptions(command)\n .argument('<name>', 'Ref name to delete')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeRefDeleteCommand(name, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n ui.output(`Deleted ref \"${value.ref}\"`);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefListCommand(): Command {\n const command = new Command('list');\n setCommandDescriptions(command, 'List all refs', 'Lists all named refs from migrations/refs/.');\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: { config?: string; json?: string | boolean; quiet?: boolean }) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeRefListCommand(options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n const entries = Object.entries(value.refs);\n if (entries.length === 0) {\n ui.output('No refs defined');\n } else {\n for (const [refName, entry] of entries) {\n const invariantsSuffix =\n entry.invariants.length > 0 ? ` [invariants: ${entry.invariants.join(', ')}]` : '';\n ui.output(`${refName} → ${entry.hash}${invariantsSuffix}`);\n }\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n\nexport function createRefCommand(): Command {\n const command = new Command('ref');\n setCommandDescriptions(\n command,\n 'Manage contract refs',\n 'Manage named refs in migrations/refs/. Refs map logical environment\\n' +\n 'names (e.g., staging, production) to contract hashes.',\n );\n addGlobalOptions(command).configureHelp({\n formatHelp: (cmd) => formatCommandHelp({ command: cmd, flags: parseGlobalFlags({}) }),\n subcommandDescription: () => '',\n });\n command.addCommand(createRefSetCommand());\n command.addCommand(createRefDeleteCommand());\n command.addCommand(createRefListCommand());\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ref.mjs","names":[],"sources":["../../src/commands/ref.ts"],"sourcesContent":["import { loadConfig } from '@prisma-next/config-loader';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport {\n contractSnapshotDir,\n readContractSnapshotJson,\n} from '@prisma-next/migration-tools/contract-snapshot-store';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findLatestMigration, isGraphNode } from '@prisma-next/migration-tools/migration-graph';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport type { RefEntry } from '@prisma-next/migration-tools/refs';\nimport {\n deleteRefPaired,\n readRefs,\n validateRefName,\n validateRefValue,\n writeRefPaired,\n} from '@prisma-next/migration-tools/refs';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join } from 'pathe';\nimport {\n CliStructuredError,\n errorFileNotFound,\n errorRefSetBundleNotFound,\n errorRefSetEmptySentinel,\n errorRefSetHashNotInGraph,\n errorRuntime,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n resolveMigrationPaths,\n setCommandDescriptions,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport { formatCommandHelp } from '../utils/formatters/help';\nimport { parseGlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { readContractIR } from '../utils/ref-advancement';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI } from '../utils/terminal-ui';\n\ninterface RefSetResult {\n readonly ok: true;\n readonly ref: string;\n readonly hash: string;\n readonly invariants: readonly string[];\n}\n\ninterface RefDeleteResult {\n readonly ok: true;\n readonly ref: string;\n readonly deleted: true;\n}\n\ninterface RefListResult {\n readonly ok: true;\n readonly refs: Record<string, RefEntry>;\n}\n\nfunction mapError(error: unknown): CliStructuredError {\n if (MigrationToolsError.is(error)) {\n return mapMigrationToolsError(error);\n }\n return errorUnexpected(error instanceof Error ? error.message : String(error));\n}\n\nfunction cliErrorInvalidRefName(name: string): CliStructuredError {\n return errorRuntime(`Invalid ref name \"${name}\"`, {\n why: `Ref name \"${name}\" does not match the required format`,\n fix: 'Ref names must be lowercase alphanumeric with hyphens or forward slashes, no `.` or `..` segments',\n });\n}\n\nexport async function executeRefSetCommand(\n name: string,\n contractInput: string,\n options: { config?: string },\n): Promise<Result<RefSetResult, CliStructuredError>> {\n if (!validateRefName(name)) {\n return notOk(cliErrorInvalidRefName(name));\n }\n\n try {\n const config = await loadConfig(options.config);\n const { migrationsDir, refsDir } = resolveMigrationPaths(options.config, config);\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return notOk(loaded.failure);\n }\n const graph = loaded.value.aggregate.app.graph();\n const bundles = loaded.value.aggregate.app.packages;\n const refs = loaded.value.aggregate.app.refs;\n\n let resolvedHash: string;\n if (validateRefValue(contractInput)) {\n resolvedHash = contractInput;\n } else {\n const refResult = parseContractRef(contractInput, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n resolvedHash = refResult.value.hash;\n }\n\n if (resolvedHash === EMPTY_CONTRACT_HASH) {\n return notOk(errorRefSetEmptySentinel(resolvedHash));\n }\n if (!isGraphNode(resolvedHash, graph)) {\n const graphTip = findLatestMigration(graph)?.to ?? null;\n return notOk(errorRefSetHashNotInGraph(resolvedHash, [...graph.nodes].sort(), graphTip));\n }\n\n const matchingBundle = bundles.find((bundle) => bundle.metadata.to === resolvedHash);\n if (!matchingBundle) {\n return notOk(errorRefSetBundleNotFound(resolvedHash));\n }\n\n const contractJsonPath = join(\n contractSnapshotDir(migrationsDir, resolvedHash),\n 'contract.json',\n );\n let contractJson: Record<string, unknown>;\n try {\n contractJson = (await readContractSnapshotJson(migrationsDir, resolvedHash)) as Record<\n string,\n unknown\n >;\n } catch (readError) {\n if (\n MigrationToolsError.is(readError) &&\n readError.code === 'MIGRATION.CONTRACT_SNAPSHOT_MISSING'\n ) {\n return notOk(\n errorFileNotFound(contractJsonPath, {\n why: `Migration bundle for hash ${resolvedHash} is missing its contract snapshot at ${contractJsonPath}`,\n fix: 'Restore migrations/snapshots/ from version control, or re-run the command that produced this migration to regenerate its snapshot.',\n }),\n );\n }\n throw readError;\n }\n\n const contractIR = await readContractIR(contractJson, contractJsonPath);\n const entry: RefEntry = { hash: resolvedHash, invariants: [] };\n await writeRefPaired(refsDir, name, entry, contractIR);\n return ok({ ok: true as const, ref: name, hash: resolvedHash, invariants: [] });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nexport async function executeRefDeleteCommand(\n name: string,\n options: { config?: string },\n): Promise<Result<RefDeleteResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n await deleteRefPaired(refsDir, name);\n return ok({ ok: true as const, ref: name, deleted: true as const });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nexport async function executeRefListCommand(options: {\n config?: string;\n}): Promise<Result<RefListResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n const refs = await readRefs(refsDir);\n return ok({ ok: true as const, refs });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nfunction createRefSetCommand(): Command {\n const command = new Command('set');\n setCommandDescriptions(\n command,\n 'Set a ref to a contract reference',\n 'Sets a named ref to point to a resolved contract reference (hash, alias, or path) in migrations/refs/.',\n );\n addGlobalOptions(command)\n .argument('<name>', 'Ref name (e.g., staging, production)')\n .argument(\n '<contract>',\n 'Contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n hash: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeRefSetCommand(name, hash, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n ui.output(`Set ref \"${value.ref}\" → ${value.hash}`);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefDeleteCommand(): Command {\n const command = new Command('delete');\n setCommandDescriptions(command, 'Delete a ref', 'Removes a named ref from migrations/refs/.');\n addGlobalOptions(command)\n .argument('<name>', 'Ref name to delete')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeRefDeleteCommand(name, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n ui.output(`Deleted ref \"${value.ref}\"`);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefListCommand(): Command {\n const command = new Command('list');\n setCommandDescriptions(command, 'List all refs', 'Lists all named refs from migrations/refs/.');\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: { config?: string; json?: string | boolean; quiet?: boolean }) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeRefListCommand(options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n const entries = Object.entries(value.refs);\n if (entries.length === 0) {\n ui.output('No refs defined');\n } else {\n for (const [refName, entry] of entries) {\n const invariantsSuffix =\n entry.invariants.length > 0 ? ` [invariants: ${entry.invariants.join(', ')}]` : '';\n ui.output(`${refName} → ${entry.hash}${invariantsSuffix}`);\n }\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n\nexport function createRefCommand(): Command {\n const command = new Command('ref');\n setCommandDescriptions(\n command,\n 'Manage contract refs',\n 'Manage named refs in migrations/refs/. Refs map logical environment\\n' +\n 'names (e.g., staging, production) to contract hashes.',\n );\n addGlobalOptions(command).configureHelp({\n formatHelp: (cmd) => formatCommandHelp({ command: cmd, flags: parseGlobalFlags({}) }),\n subcommandDescription: () => '',\n });\n command.addCommand(createRefSetCommand());\n command.addCommand(createRefDeleteCommand());\n command.addCommand(createRefListCommand());\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { B as errorContractValidationFailed, F as CliStructuredError, W as errorFileNotFound, ct as errorUnexpected, it as errorSnapshotMissing, lt as mapMigrationToolsError } from "./command-helpers-Cpq44aVa.mjs";
|
|
2
2
|
import { notOk } from "@prisma-next/utils/result";
|
|
3
|
-
import { join } from "pathe";
|
|
4
3
|
import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
|
|
5
4
|
//#region src/utils/contract-at-errors.ts
|
|
6
5
|
function mapContractAtError(error, options) {
|
|
@@ -21,14 +20,11 @@ function mapContractAtError(error, options) {
|
|
|
21
20
|
why: error.why,
|
|
22
21
|
fix: error.fix
|
|
23
22
|
}));
|
|
24
|
-
case "MIGRATION.
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return notOk(errorFileNotFound(jsonPath, {
|
|
30
|
-
why: role === "to" ? `Target migration is missing its destination contract snapshot at ${jsonPath}` : `Predecessor migration is missing its destination contract snapshot at ${jsonPath}`,
|
|
31
|
-
fix: role === "to" ? "Re-emit the target migration so its sibling `end-contract.json` / `end-contract.d.ts` are restored, then re-run this command." : "Re-emit the predecessor migration (`prisma-next migration plan` from its source) so its sibling `end-contract.json` is restored, then re-run this command."
|
|
23
|
+
case "MIGRATION.CONTRACT_SNAPSHOT_MISSING": {
|
|
24
|
+
const expectedPath = typeof error.details?.["expectedPath"] === "string" ? error.details["expectedPath"] : "migrations/snapshots/";
|
|
25
|
+
return notOk(errorFileNotFound(expectedPath, {
|
|
26
|
+
why: (options?.artifactRole ?? "from") === "to" ? `Target migration is missing its contract snapshot at ${expectedPath}` : `Predecessor migration is missing its contract snapshot at ${expectedPath}`,
|
|
27
|
+
fix: "Restore migrations/snapshots/ from version control, or re-run the command that produced this migration to regenerate its snapshot."
|
|
32
28
|
}));
|
|
33
29
|
}
|
|
34
30
|
default: return notOk(mapMigrationToolsError(error));
|
|
@@ -39,4 +35,4 @@ function mapContractAtError(error, options) {
|
|
|
39
35
|
//#endregion
|
|
40
36
|
export { mapContractAtError as t };
|
|
41
37
|
|
|
42
|
-
//# sourceMappingURL=contract-at-errors-
|
|
38
|
+
//# sourceMappingURL=contract-at-errors-CTtzKR6q.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-at-errors-CTtzKR6q.mjs","names":[],"sources":["../src/utils/contract-at-errors.ts"],"sourcesContent":["import { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { notOk, type Result } from '@prisma-next/utils/result';\nimport {\n CliStructuredError,\n errorContractValidationFailed,\n errorFileNotFound,\n errorSnapshotMissing,\n errorUnexpected,\n mapMigrationToolsError,\n} from './cli-errors';\n\nexport function mapContractAtError(\n error: unknown,\n options?: { readonly artifactRole?: 'from' | 'to' },\n): Result<never, CliStructuredError> {\n if (MigrationToolsError.is(error)) {\n switch (error.code) {\n case 'MIGRATION.SNAPSHOT_MISSING': {\n const refName =\n typeof error.details?.['refName'] === 'string'\n ? error.details['refName']\n : typeof error.details?.['identifier'] === 'string'\n ? error.details['identifier']\n : 'unknown';\n return notOk(errorSnapshotMissing(refName));\n }\n case 'MIGRATION.CONTRACT_DESERIALIZATION_FAILED': {\n const filePath =\n typeof error.details?.['filePath'] === 'string'\n ? error.details['filePath']\n : 'ref-snapshot';\n const message =\n typeof error.details?.['message'] === 'string' ? error.details['message'] : error.message;\n const isRefSnapshot = filePath.endsWith('.contract.json');\n return notOk(\n errorContractValidationFailed(\n isRefSnapshot\n ? `Ref snapshot contract failed to deserialize: ${message}`\n : `Predecessor contract at ${filePath} failed to deserialize: ${message}`,\n { where: { path: isRefSnapshot ? 'ref-snapshot' : filePath } },\n ),\n );\n }\n case 'MIGRATION.INVALID_JSON': {\n const filePath =\n typeof error.details?.['filePath'] === 'string' ? error.details['filePath'] : 'unknown';\n const message =\n typeof error.details?.['parseError'] === 'string'\n ? error.details['parseError']\n : error.message;\n const role = options?.artifactRole ?? 'from';\n return notOk(\n errorContractValidationFailed(\n role === 'to'\n ? `Target contract at ${filePath} failed to deserialize: ${message}`\n : `Predecessor contract at ${filePath} failed to deserialize: ${message}`,\n { where: { path: filePath } },\n ),\n );\n }\n case 'MIGRATION.BUNDLE_NOT_FOUND_FOR_GRAPH_NODE':\n return notOk(\n errorUnexpected(error.message, {\n why: error.why,\n fix: error.fix,\n }),\n );\n case 'MIGRATION.CONTRACT_SNAPSHOT_MISSING': {\n const expectedPath =\n typeof error.details?.['expectedPath'] === 'string'\n ? error.details['expectedPath']\n : 'migrations/snapshots/';\n const role = options?.artifactRole ?? 'from';\n return notOk(\n errorFileNotFound(expectedPath, {\n why:\n role === 'to'\n ? `Target migration is missing its contract snapshot at ${expectedPath}`\n : `Predecessor migration is missing its contract snapshot at ${expectedPath}`,\n fix: 'Restore migrations/snapshots/ from version control, or re-run the command that produced this migration to regenerate its snapshot.',\n }),\n );\n }\n default:\n return notOk(mapMigrationToolsError(error));\n }\n }\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n throw error;\n}\n"],"mappings":";;;;AAWA,SAAgB,mBACd,OACA,SACmC;CACnC,IAAI,oBAAoB,GAAG,KAAK,GAC9B,QAAQ,MAAM,MAAd;EACE,KAAK,8BAOH,OAAO,MAAM,qBALX,OAAO,MAAM,UAAU,eAAe,WAClC,MAAM,QAAQ,aACd,OAAO,MAAM,UAAU,kBAAkB,WACvC,MAAM,QAAQ,gBACd,SACiC,CAAC;EAE5C,KAAK,6CAA6C;GAChD,MAAM,WACJ,OAAO,MAAM,UAAU,gBAAgB,WACnC,MAAM,QAAQ,cACd;GACN,MAAM,UACJ,OAAO,MAAM,UAAU,eAAe,WAAW,MAAM,QAAQ,aAAa,MAAM;GACpF,MAAM,gBAAgB,SAAS,SAAS,gBAAgB;GACxD,OAAO,MACL,8BACE,gBACI,gDAAgD,YAChD,2BAA2B,SAAS,0BAA0B,WAClE,EAAE,OAAO,EAAE,MAAM,gBAAgB,iBAAiB,SAAS,EAAE,CAC/D,CACF;EACF;EACA,KAAK,0BAA0B;GAC7B,MAAM,WACJ,OAAO,MAAM,UAAU,gBAAgB,WAAW,MAAM,QAAQ,cAAc;GAChF,MAAM,UACJ,OAAO,MAAM,UAAU,kBAAkB,WACrC,MAAM,QAAQ,gBACd,MAAM;GAEZ,OAAO,MACL,+BAFW,SAAS,gBAAgB,YAGzB,OACL,sBAAsB,SAAS,0BAA0B,YACzD,2BAA2B,SAAS,0BAA0B,WAClE,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,CAC9B,CACF;EACF;EACA,KAAK,6CACH,OAAO,MACL,gBAAgB,MAAM,SAAS;GAC7B,KAAK,MAAM;GACX,KAAK,MAAM;EACb,CAAC,CACH;EACF,KAAK,uCAAuC;GAC1C,MAAM,eACJ,OAAO,MAAM,UAAU,oBAAoB,WACvC,MAAM,QAAQ,kBACd;GAEN,OAAO,MACL,kBAAkB,cAAc;IAC9B,MAHS,SAAS,gBAAgB,YAIvB,OACL,wDAAwD,iBACxD,6DAA6D;IACnE,KAAK;GACP,CAAC,CACH;EACF;EACA,SACE,OAAO,MAAM,uBAAuB,KAAK,CAAC;CAC9C;CAEF,IAAI,mBAAmB,GAAG,KAAK,GAC7B,OAAO,MAAM,KAAK;CAEpB,MAAM;AACR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-output.d.mts","names":[],"sources":["../../src/commands/init/output.ts"],"mappings":";;;;;;;;;;;;;;;;cAkBa,gEAAgB;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"init-output.d.mts","names":[],"sources":["../../src/commands/init/output.ts"],"mappings":";;;;;;;;;;;;;;;;cAkBa,gEAAgB;;;;;;;;;;;;;;;;KAuBjB,oBAAoB,iBAAiB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as InitOutputSchema } from "../output-
|
|
1
|
+
import { t as InitOutputSchema } from "../output-DWNYqZGc.mjs";
|
|
2
2
|
export { InitOutputSchema };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { F as CliStructuredError, _ as createTerminalUI, b as formatErrorJson, x as formatErrorOutput } from "./command-helpers-Cpq44aVa.mjs";
|
|
2
2
|
import { a as starterSchema, c as version, i as schemaSample, n as dbFile, o as targetLabel, r as defaultSchemaPath, s as targetPackageName, t as configFile } from "./cli.mjs";
|
|
3
|
-
import { i as renderInitOutro, n as buildNextSteps, r as formatInitJson, t as InitOutputSchema } from "./output-
|
|
3
|
+
import { i as renderInitOutro, n as buildNextSteps, r as formatInitJson, t as InitOutputSchema } from "./output-DWNYqZGc.mjs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { basename, dirname, extname, isAbsolute, join, normalize } from "pathe";
|
|
6
6
|
import { blindCast } from "@prisma-next/utils/casts";
|
|
@@ -413,50 +413,59 @@ function errorInitSkillInstallFailed(options) {
|
|
|
413
413
|
//#endregion
|
|
414
414
|
//#region src/commands/init/hygiene-gitattributes.ts
|
|
415
415
|
/**
|
|
416
|
-
* The
|
|
417
|
-
*
|
|
418
|
-
*
|
|
416
|
+
* The `.gitattributes` entries written for a freshly initialised project
|
|
417
|
+
* (FR3.4). Mirrors the relevant subset of the repo-root
|
|
418
|
+
* [`.gitattributes`](../../../../../../../../.gitattributes):
|
|
419
419
|
*
|
|
420
420
|
* - **Today**: `contract.json`, `contract.d.ts` are emitted on every
|
|
421
421
|
* `prisma-next contract emit`. Marking them `linguist-generated`
|
|
422
422
|
* keeps GitHub's diff stats honest and collapses the file in code
|
|
423
423
|
* review by default.
|
|
424
|
-
* - **Forward-looking**: `
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
* who runs `init --schema-path db/contract.prisma`
|
|
432
|
-
* `db/contract.json linguist-generated` — not the workspace-glob
|
|
433
|
-
* `<glob>/contract.json` (which would over-match any unrelated
|
|
424
|
+
* - **Forward-looking**: `ops.json`, `migration.json` are not yet emitted
|
|
425
|
+
* by `init` flows but will be produced by adjacent commands (lower /
|
|
426
|
+
* migration tooling). Adding them now matches Decision 5
|
|
427
|
+
* (forward-looking subset) so the file does not need to be amended
|
|
428
|
+
* every time a new artifact lands.
|
|
429
|
+
*
|
|
430
|
+
* `ARTIFACT_FILENAMES` entries are written relative to the schema
|
|
431
|
+
* directory so a user who runs `init --schema-path db/contract.prisma`
|
|
432
|
+
* gets `db/contract.json linguist-generated` — not the workspace-glob
|
|
433
|
+
* form `<glob>/contract.json` (which would over-match any unrelated
|
|
434
434
|
* `contract.json` the user has elsewhere) and not the absolute
|
|
435
|
-
* `DEFAULT_CONTRACT_SOURCE_DIR/contract.json` (which would silently
|
|
436
|
-
* schema path).
|
|
435
|
+
* `DEFAULT_CONTRACT_SOURCE_DIR/contract.json` (which would silently
|
|
436
|
+
* break for a non-default schema path).
|
|
437
|
+
*
|
|
438
|
+
* The migration contract snapshot store (`migrations/snapshots/<hex>/`)
|
|
439
|
+
* is anchored to the migrations root instead, not the schema directory:
|
|
440
|
+
* migration package depth under `migrations/` varies (`app/<pkg>`,
|
|
441
|
+
* `<space>/<pkg>`, or a bare `<pkg>` in extension source repos), so no
|
|
442
|
+
* single schema-dir-relative pattern can reach every snapshot. See
|
|
443
|
+
* `STORE_GITATTRIBUTES_LINES` below.
|
|
437
444
|
*/
|
|
438
|
-
const
|
|
445
|
+
const ARTIFACT_FILENAMES$1 = [
|
|
439
446
|
"contract.json",
|
|
440
447
|
"contract.d.ts",
|
|
441
|
-
"end-contract.json",
|
|
442
|
-
"end-contract.d.ts",
|
|
443
|
-
"start-contract.json",
|
|
444
|
-
"start-contract.d.ts",
|
|
445
448
|
"ops.json",
|
|
446
449
|
"migration.json"
|
|
447
450
|
];
|
|
448
451
|
const ATTRIBUTE = "linguist-generated";
|
|
449
452
|
/**
|
|
453
|
+
* Full `.gitattributes` lines for the migration contract snapshot store,
|
|
454
|
+
* already anchored to the migrations root — unlike `ARTIFACT_FILENAMES`,
|
|
455
|
+
* these are not combined with the schema-relative prefix.
|
|
456
|
+
*/
|
|
457
|
+
const STORE_GITATTRIBUTES_LINES = [`migrations/snapshots/**/contract.json ${ATTRIBUTE}`, `migrations/snapshots/**/contract.d.ts ${ATTRIBUTE}`];
|
|
458
|
+
/**
|
|
450
459
|
* Computes the `.gitattributes` lines this scaffold expects to own. Each
|
|
451
460
|
* line has the shape `<path> linguist-generated`. The `target` parameter
|
|
452
461
|
* is currently unused but accepted for symmetry with the other hygiene
|
|
453
462
|
* helpers and to leave room for target-specific entries (e.g. a future
|
|
454
|
-
*
|
|
463
|
+
* family-specific artifact) without a signature break.
|
|
455
464
|
*/
|
|
456
465
|
function requiredGitattributesLines(schemaDir, _target) {
|
|
457
466
|
const dir = schemaDir === "." ? "" : schemaDir.replace(/\/+$/, "");
|
|
458
467
|
const prefix = dir === "" ? "" : `${dir}/`;
|
|
459
|
-
return
|
|
468
|
+
return [...ARTIFACT_FILENAMES$1.map((file) => `${prefix}${file} ${ATTRIBUTE}`), ...STORE_GITATTRIBUTES_LINES];
|
|
460
469
|
}
|
|
461
470
|
/**
|
|
462
471
|
* Idempotent `.gitattributes` merge (FR3.4 / FR9.3). Returns the new file
|
|
@@ -1037,40 +1046,39 @@ function requirePeer(moduleId, baseDir, overrides) {
|
|
|
1037
1046
|
/**
|
|
1038
1047
|
* Filenames the contract pipeline emits next to the user's schema source
|
|
1039
1048
|
* (`<schemaDir>/contract.json`, `<schemaDir>/contract.d.ts`, …). Mirrors
|
|
1040
|
-
* `
|
|
1041
|
-
*
|
|
1042
|
-
*
|
|
1043
|
-
*
|
|
1044
|
-
*
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
1049
|
-
|
|
1050
|
-
|
|
1049
|
+
* the schema-dir-relative `ARTIFACT_FILENAMES` in `hygiene-gitattributes.ts`
|
|
1050
|
+
* (not that file's migrations-root-anchored store lines, which are outside
|
|
1051
|
+
* this command's scope — reinit only ever touches `schemaDir`); kept as a
|
|
1052
|
+
* separate constant here because the cleanup contract is target-agnostic
|
|
1053
|
+
* and we deliberately do not want a stale artifact from a previous target
|
|
1054
|
+
* lingering after a re-init.
|
|
1055
|
+
*
|
|
1056
|
+
* If a future emit pipeline produces an additional schema-dir artifact,
|
|
1057
|
+
* add it here **and** to `ARTIFACT_FILENAMES` in `hygiene-gitattributes.ts`
|
|
1058
|
+
* — the two stay in lockstep so the file `init` advertises as
|
|
1059
|
+
* `linguist-generated` is exactly the file `init` is willing to delete on
|
|
1060
|
+
* re-init.
|
|
1061
|
+
*/
|
|
1062
|
+
const ARTIFACT_FILENAMES = [
|
|
1051
1063
|
"contract.json",
|
|
1052
1064
|
"contract.d.ts",
|
|
1053
|
-
"end-contract.json",
|
|
1054
|
-
"end-contract.d.ts",
|
|
1055
|
-
"start-contract.json",
|
|
1056
|
-
"start-contract.d.ts",
|
|
1057
1065
|
"ops.json",
|
|
1058
1066
|
"migration.json"
|
|
1059
1067
|
];
|
|
1060
1068
|
/**
|
|
1061
|
-
* Returns the schema-relative paths of stale contract
|
|
1069
|
+
* Returns the schema-relative paths of stale contract artifacts the
|
|
1062
1070
|
* previous `init` run (or a `contract emit`) left behind in `schemaDir`.
|
|
1063
1071
|
* Paths are returned relative to `baseDir` so the caller can plumb them
|
|
1064
1072
|
* into `filesWritten`-style logging without re-deriving the path.
|
|
1065
1073
|
*
|
|
1066
1074
|
* Pure function: no filesystem mutation. Used by `runInit`'s precondition
|
|
1067
1075
|
* phase (FR6.2 / NFR3 atomicity) so a downstream parse failure leaves
|
|
1068
|
-
* the
|
|
1076
|
+
* the artifacts on disk and the project byte-identical to its pre-init
|
|
1069
1077
|
* state.
|
|
1070
1078
|
*/
|
|
1071
|
-
function
|
|
1079
|
+
function findStaleArtifacts(baseDir, schemaDir) {
|
|
1072
1080
|
const result = [];
|
|
1073
|
-
for (const filename of
|
|
1081
|
+
for (const filename of ARTIFACT_FILENAMES) {
|
|
1074
1082
|
const rel = join(schemaDir, filename);
|
|
1075
1083
|
if (existsSync(join(baseDir, rel))) result.push(rel);
|
|
1076
1084
|
}
|
|
@@ -1669,7 +1677,7 @@ async function runInit(baseDir, runOptions) {
|
|
|
1669
1677
|
content: envExampleContent(inputs.target)
|
|
1670
1678
|
}
|
|
1671
1679
|
];
|
|
1672
|
-
const filesToDelete = inputs.reinit ? [...
|
|
1680
|
+
const filesToDelete = inputs.reinit ? [...findStaleArtifacts(baseDir, schemaDir)] : [];
|
|
1673
1681
|
if (existsSync(join(baseDir, ".agents/skills/prisma-next/SKILL.md"))) filesToDelete.push(LEGACY_SKILL_FILE);
|
|
1674
1682
|
if (inputs.writeEnv) if (!existsSync(join(baseDir, ".env"))) filesToWrite.push({
|
|
1675
1683
|
path: ".env",
|
|
@@ -2081,7 +2089,7 @@ function formatCatalogWarning(workspaceFile, entries) {
|
|
|
2081
2089
|
/**
|
|
2082
2090
|
* Recognised pnpm error signatures that justify a fallback to npm.
|
|
2083
2091
|
*
|
|
2084
|
-
* These patterns indicate the published
|
|
2092
|
+
* These patterns indicate the published artifact itself is at fault
|
|
2085
2093
|
* (a leaked `workspace:*` or `catalog:` specifier), not the user's
|
|
2086
2094
|
* environment — pnpm is faithfully reporting "I cannot resolve this
|
|
2087
2095
|
* registry version", and npm is willing to install it because npm
|
|
@@ -2193,4 +2201,4 @@ function sanitisePackageName(raw) {
|
|
|
2193
2201
|
//#endregion
|
|
2194
2202
|
export { runInit };
|
|
2195
2203
|
|
|
2196
|
-
//# sourceMappingURL=init-
|
|
2204
|
+
//# sourceMappingURL=init-CgKEi_t5.mjs.map
|