@prisma-next/cli 0.5.0-dev.3 → 0.5.0-dev.30
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 +56 -21
- package/dist/agent-skill-mongo.md +63 -31
- package/dist/agent-skill-postgres.md +1 -1
- package/dist/cli-errors-By1iVE3z.mjs +34 -0
- package/dist/cli-errors-By1iVE3z.mjs.map +1 -0
- package/dist/{cli-errors-C0JhVj0c.d.mts → cli-errors-DDeVsP2Y.d.mts} +1 -0
- package/dist/cli.mjs +131 -15
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-TG7rbCWT.mjs → client-keSCAgjW.mjs} +43 -19
- package/dist/client-keSCAgjW.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +7 -2
- package/dist/commands/contract-infer.d.mts.map +1 -1
- package/dist/commands/contract-infer.mjs +8 -2
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +11 -9
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +8 -5
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.mjs +8 -7
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.mjs +10 -9
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +10 -9
- package/dist/commands/db-verify.mjs.map +1 -1
- package/dist/commands/migration-apply.d.mts +2 -2
- package/dist/commands/migration-apply.d.mts.map +1 -1
- package/dist/commands/migration-apply.mjs +15 -38
- package/dist/commands/migration-apply.mjs.map +1 -1
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +24 -30
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +14 -5
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +45 -47
- package/dist/commands/migration-plan.mjs.map +1 -1
- package/dist/commands/migration-ref.d.mts +6 -4
- package/dist/commands/migration-ref.d.mts.map +1 -1
- package/dist/commands/migration-ref.mjs +31 -40
- package/dist/commands/migration-ref.mjs.map +1 -1
- package/dist/commands/migration-show.d.mts +13 -7
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +28 -29
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +5 -4
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +7 -2
- package/dist/{config-loader-_W4T21X1.mjs → config-loader-ih8ViDb_.mjs} +2 -2
- package/dist/config-loader-ih8ViDb_.mjs.map +1 -0
- package/dist/config-loader.mjs +1 -1
- package/dist/contract-emit-DS5NzZh2.mjs +6 -0
- package/dist/contract-emit-DWtGQYCD.mjs +150 -0
- package/dist/contract-emit-DWtGQYCD.mjs.map +1 -0
- package/dist/contract-emit-RZBWzkop.mjs +329 -0
- package/dist/contract-emit-RZBWzkop.mjs.map +1 -0
- package/dist/{contract-enrichment-CGW6mm-E.mjs → contract-enrichment-4Ptgw3Pe.mjs} +1 -1
- package/dist/{contract-enrichment-CGW6mm-E.mjs.map → contract-enrichment-4Ptgw3Pe.mjs.map} +1 -1
- package/dist/{contract-infer-BP3DrGgz.mjs → contract-infer-GztVCOCJ.mjs} +11 -19
- package/dist/contract-infer-GztVCOCJ.mjs.map +1 -0
- package/dist/exports/control-api.d.mts +78 -21
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +7 -5
- package/dist/exports/index.mjs +8 -3
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.d.mts +39 -0
- package/dist/exports/init-output.d.mts.map +1 -0
- package/dist/exports/init-output.mjs +3 -0
- package/dist/{framework-components-DfZKQBQ2.mjs → framework-components-Bgcre3Z6.mjs} +2 -2
- package/dist/{framework-components-DfZKQBQ2.mjs.map → framework-components-Bgcre3Z6.mjs.map} +1 -1
- package/dist/init-DAbQMxIR.mjs +2062 -0
- package/dist/init-DAbQMxIR.mjs.map +1 -0
- package/dist/{inspect-live-schema-DWzf4Q_m.mjs → inspect-live-schema-BaR9ISwa.mjs} +9 -9
- package/dist/inspect-live-schema-BaR9ISwa.mjs.map +1 -0
- package/dist/migration-cli.d.mts +41 -11
- package/dist/migration-cli.d.mts.map +1 -1
- package/dist/migration-cli.mjs +308 -84
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-CLMD302g.mjs → migration-command-scaffold-D1dWuEWQ.mjs} +7 -7
- package/dist/{migration-command-scaffold-CLMD302g.mjs.map → migration-command-scaffold-D1dWuEWQ.mjs.map} +1 -1
- package/dist/{migration-status-B0HLF7So.mjs → migration-status-CP5k8O5i.mjs} +21 -35
- package/dist/migration-status-CP5k8O5i.mjs.map +1 -0
- package/dist/{migrations-B0dOQlk0.mjs → migrations-MEoKMiV5.mjs} +42 -21
- package/dist/migrations-MEoKMiV5.mjs.map +1 -0
- package/dist/output-BpcQrnnq.mjs +103 -0
- package/dist/output-BpcQrnnq.mjs.map +1 -0
- package/dist/{progress-adapter-B-YvmcDu.mjs → progress-adapter-DgRGldpT.mjs} +1 -1
- package/dist/{progress-adapter-B-YvmcDu.mjs.map → progress-adapter-DgRGldpT.mjs.map} +1 -1
- package/dist/quick-reference-mongo.md +34 -13
- package/dist/quick-reference-postgres.md +11 -9
- package/dist/{result-handler-CIyu0Pdt.mjs → result-handler-BmVh8AeV.mjs} +12 -93
- package/dist/result-handler-BmVh8AeV.mjs.map +1 -0
- package/dist/{terminal-ui-C5k88MmW.mjs → terminal-ui-u2YgKghu.mjs} +76 -2
- package/dist/terminal-ui-u2YgKghu.mjs.map +1 -0
- package/dist/{verify-BxiVp50b.mjs → verify-BT9tgCOH.mjs} +2 -2
- package/dist/{verify-BxiVp50b.mjs.map → verify-BT9tgCOH.mjs.map} +1 -1
- package/package.json +21 -15
- package/src/cli.ts +32 -6
- package/src/commands/contract-emit.ts +67 -163
- package/src/commands/contract-infer.ts +7 -20
- package/src/commands/db-init.ts +1 -0
- package/src/commands/db-update.ts +1 -1
- package/src/commands/init/detect-pnpm-catalog.ts +141 -0
- package/src/commands/init/errors.ts +254 -0
- package/src/commands/init/exit-codes.ts +62 -0
- package/src/commands/init/hygiene-gitattributes.ts +97 -0
- package/src/commands/init/hygiene-gitignore.ts +48 -0
- package/src/commands/init/hygiene-package-scripts.ts +91 -0
- package/src/commands/init/index.ts +112 -7
- package/src/commands/init/init.ts +766 -144
- package/src/commands/init/inputs.ts +421 -0
- package/src/commands/init/output.ts +147 -0
- package/src/commands/init/probe-db.ts +308 -0
- package/src/commands/init/reinit-cleanup.ts +83 -0
- package/src/commands/init/templates/agent-skill-mongo.md +63 -31
- package/src/commands/init/templates/agent-skill-postgres.md +1 -1
- package/src/commands/init/templates/agent-skill.ts +25 -3
- package/src/commands/init/templates/code-templates.ts +125 -32
- package/src/commands/init/templates/env.ts +80 -0
- package/src/commands/init/templates/quick-reference-mongo.md +34 -13
- package/src/commands/init/templates/quick-reference-postgres.md +11 -9
- package/src/commands/init/templates/quick-reference.ts +42 -3
- package/src/commands/init/templates/tsconfig.ts +167 -5
- package/src/commands/inspect-live-schema.ts +10 -5
- package/src/commands/migration-apply.ts +16 -51
- package/src/commands/migration-new.ts +26 -32
- package/src/commands/migration-plan.ts +80 -55
- package/src/commands/migration-ref.ts +40 -54
- package/src/commands/migration-show.ts +53 -36
- package/src/commands/migration-status.ts +33 -50
- package/src/config-path-validation.ts +0 -1
- package/src/control-api/client.ts +21 -0
- package/src/control-api/operations/contract-emit.ts +198 -115
- package/src/control-api/operations/db-init.ts +8 -5
- package/src/control-api/operations/db-update.ts +8 -5
- package/src/control-api/operations/migration-apply.ts +29 -9
- package/src/control-api/types.ts +61 -7
- package/src/exports/control-api.ts +2 -1
- package/src/exports/init-output.ts +10 -0
- package/src/migration-cli.ts +445 -122
- package/src/utils/cli-errors.ts +49 -2
- package/src/utils/command-helpers.ts +13 -26
- package/src/utils/emit-queue.ts +26 -0
- package/src/utils/formatters/graph-migration-mapper.ts +2 -2
- package/src/utils/formatters/migrations.ts +62 -26
- package/src/utils/publish-contract-artifact-pair.ts +134 -0
- package/dist/cli-errors-DHq6GQGu.mjs +0 -5
- package/dist/client-TG7rbCWT.mjs.map +0 -1
- package/dist/config-loader-_W4T21X1.mjs.map +0 -1
- package/dist/contract-emit-CNYyzJwF.mjs +0 -195
- package/dist/contract-emit-CNYyzJwF.mjs.map +0 -1
- package/dist/contract-emit-CQfj7xJn.mjs +0 -122
- package/dist/contract-emit-CQfj7xJn.mjs.map +0 -1
- package/dist/contract-emit-fhNwwhkQ.mjs +0 -4
- package/dist/contract-infer-BP3DrGgz.mjs.map +0 -1
- package/dist/extract-operation-statements-DZUJNmL3.mjs +0 -13
- package/dist/extract-operation-statements-DZUJNmL3.mjs.map +0 -1
- package/dist/extract-sql-ddl-DDMX-9mz.mjs +0 -26
- package/dist/extract-sql-ddl-DDMX-9mz.mjs.map +0 -1
- package/dist/init-CQfo_4Ro.mjs +0 -430
- package/dist/init-CQfo_4Ro.mjs.map +0 -1
- package/dist/inspect-live-schema-DWzf4Q_m.mjs.map +0 -1
- package/dist/migration-status-B0HLF7So.mjs.map +0 -1
- package/dist/migrations-B0dOQlk0.mjs.map +0 -1
- package/dist/result-handler-CIyu0Pdt.mjs.map +0 -1
- package/dist/terminal-ui-C5k88MmW.mjs.map +0 -1
- package/dist/validate-contract-deps-esa-VQ0h.mjs +0 -37
- package/dist/validate-contract-deps-esa-VQ0h.mjs.map +0 -1
- package/src/control-api/operations/extract-operation-statements.ts +0 -14
- package/src/control-api/operations/extract-sql-ddl.ts +0 -47
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-DAbQMxIR.mjs","names":["KNOWN: ReadonlySet<string>","entries: PnpmCatalogOverride[]","entries: Array<[string, string]>","ARTEFACT_FILENAMES: readonly string[]","ARTEFACT_FILENAMES","REQUIRED_GITIGNORE_ENTRIES: readonly string[]","REQUIRED_SCRIPTS: readonly RequiredScript[]","scripts: Record<string, string>","warnings: string[]","TARGET_ALIASES: ReadonlyMap<string, TargetId>","AUTHORING_VALUES: ReadonlyMap<string, AuthoringId>","missing: string[]","otherTarget: TargetId","parsed: Record<string, unknown>","driverResult: DriverResult","causeMessage","ARTEFACT_FILENAMES: readonly string[]","result: string[]","variables","vars: TemplateVars","MIN_SERVER_VERSION: Record<TargetId, string>","TARGET_LABEL: Record<TargetId, string>","lines: string[]","vars: TemplateVars","REQUIRED_COMPILER_OPTIONS: Record<string, string | boolean>","REQUIRED_COMPILER_OPTIONS_TYPES: readonly string[]","errors: ParseError[]","parseJsonc","result: string[]","warnings: string[]","filesWritten: string[]","filesDeleted: string[]","inputs: ResolvedInitInputs","filesToWrite: FileEntry[]","filesToDelete: string[]","merged: string","parsedPackageJson: Record<string, unknown> | null","install: InstallReport","output: InitOutput"],"sources":["../src/commands/init/detect-package-manager.ts","../src/commands/init/detect-pnpm-catalog.ts","../src/commands/init/errors.ts","../src/commands/init/hygiene-gitattributes.ts","../src/commands/init/hygiene-gitignore.ts","../src/commands/init/hygiene-package-scripts.ts","../src/commands/init/templates/code-templates.ts","../src/commands/init/inputs.ts","../src/commands/init/probe-db.ts","../src/commands/init/reinit-cleanup.ts","../src/commands/init/templates/render.ts","../src/commands/init/templates/agent-skill.ts","../src/commands/init/templates/env.ts","../src/commands/init/templates/quick-reference.ts","../src/commands/init/templates/tsconfig.ts","../src/commands/init/init.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { detect } from 'package-manager-detector/detect';\nimport { join } from 'pathe';\n\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun' | 'deno';\n\nconst KNOWN: ReadonlySet<string> = new Set<PackageManager>(['pnpm', 'npm', 'yarn', 'bun', 'deno']);\n\nexport async function detectPackageManager(cwd: string): Promise<PackageManager> {\n const result = await detect({ cwd });\n if (result && KNOWN.has(result.name)) {\n return result.name as PackageManager;\n }\n return 'npm';\n}\n\nexport function hasProjectManifest(cwd: string): boolean {\n return (\n existsSync(join(cwd, 'package.json')) ||\n existsSync(join(cwd, 'deno.json')) ||\n existsSync(join(cwd, 'deno.jsonc'))\n );\n}\n\nexport function formatRunCommand(pm: PackageManager, bin: string, args: string): string {\n if (pm === 'npm') {\n return `npx ${bin} ${args}`;\n }\n if (pm === 'deno') {\n return `deno run npm:${bin} ${args}`;\n }\n return `${pm} ${bin} ${args}`;\n}\n\nexport function formatAddArgs(pm: PackageManager, packages: string[]): string[] {\n if (pm === 'deno') {\n return ['add', ...packages.map((p) => `npm:${p}`)];\n }\n return ['add', ...packages];\n}\n\nexport function formatAddDevArgs(pm: PackageManager, packages: string[]): string[] {\n if (pm === 'deno') {\n return ['add', '--dev', ...packages.map((p) => `npm:${p}`)];\n }\n return ['add', '-D', ...packages];\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'pathe';\n\n/**\n * Catalog entry detected in a `pnpm-workspace.yaml` that overrides one of\n * the packages `init` installs. The `version` is the raw value as written\n * in the workspace file (no normalisation), so the warning surfaces the\n * exact text the user can search for if they want to find the override.\n */\nexport interface PnpmCatalogOverride {\n readonly name: string;\n readonly version: string;\n}\n\n/**\n * Result of scanning for a pnpm workspace catalog that overrides any of\n * the packages `init` is about to install. Returns `null` when no\n * `pnpm-workspace.yaml` is found in `baseDir` or any ancestor; an empty\n * `entries` array means a workspace exists but contains none of our\n * packages.\n */\nexport interface PnpmCatalogScanResult {\n /** Absolute path of the `pnpm-workspace.yaml` that was consulted. */\n readonly workspaceFile: string;\n readonly entries: readonly PnpmCatalogOverride[];\n}\n\n/**\n * Walks up from `baseDir` looking for `pnpm-workspace.yaml`, then scans\n * its top-level `catalog:` block for entries that match any of `packages`.\n *\n * Implements FR7.3 / Spec Decision 8 (honour-and-warn): when `init` runs\n * inside a pnpm workspace whose catalog overrides one of the packages it\n * installs, surface a structured warning so the user knows the catalog\n * version (not the published `latest`) is what ended up in their\n * `node_modules`. pnpm itself does this silently; the warning closes the\n * \"looks fine, must be wrong version six months later\" gap.\n *\n * Notes / scope:\n *\n * - We only inspect the unnamed top-level `catalog:` block. pnpm also\n * supports `catalogs:` (plural — *named* catalogs referenced via\n * `catalog:foo` specifiers); those don't apply to a vanilla\n * `pnpm add prisma-next` invocation, so we skip them.\n * - We don't validate YAML syntax exhaustively. The file format pnpm\n * ships is line-oriented and well-known; a minimal regex is more\n * robust than depending on a YAML parser for one warning.\n * - We don't compare against the registry's `latest` — pnpm uses the\n * catalog version regardless, so the warning fires whenever a match\n * exists. The user-facing copy explains how to opt out.\n */\nexport function detectPnpmCatalogOverrides(\n baseDir: string,\n packages: readonly string[],\n): PnpmCatalogScanResult | null {\n const workspaceFile = findNearestPnpmWorkspaceFile(baseDir);\n if (workspaceFile === null) {\n return null;\n }\n\n const contents = readFileSync(workspaceFile, 'utf-8');\n const catalog = extractCatalogBlock(contents);\n if (catalog === null) {\n return { workspaceFile, entries: [] };\n }\n\n const wanted = new Set(packages);\n const entries: PnpmCatalogOverride[] = [];\n for (const [name, version] of catalog) {\n if (wanted.has(name)) {\n entries.push({ name, version });\n }\n }\n return { workspaceFile, entries };\n}\n\nfunction findNearestPnpmWorkspaceFile(baseDir: string): string | null {\n let dir = baseDir;\n let prev = '';\n while (dir !== prev) {\n const candidate = join(dir, 'pnpm-workspace.yaml');\n if (existsSync(candidate)) {\n return candidate;\n }\n prev = dir;\n dir = dirname(dir);\n }\n return null;\n}\n\n/**\n * Returns the entries inside the top-level `catalog:` block as `[name, version]`\n * pairs in document order, or `null` when no `catalog:` block exists.\n *\n * The parser is intentionally minimal: it reads line-by-line, locates the\n * top-level `catalog:` line (no leading whitespace), then collects every\n * subsequent indented line of the form `<key>: <value>` until the next\n * top-level key (or end of file). Quotes around `<key>` and `<value>`\n * are stripped; comments (`#…`) are ignored.\n */\nfunction extractCatalogBlock(contents: string): Array<[string, string]> | null {\n const lines = contents.split(/\\r?\\n/);\n const startIdx = lines.findIndex((line) => /^catalog\\s*:\\s*$/.test(line));\n if (startIdx === -1) {\n return null;\n }\n\n const entries: Array<[string, string]> = [];\n for (let i = startIdx + 1; i < lines.length; i++) {\n const raw = lines[i] ?? '';\n if (raw.trim() === '' || /^\\s*#/.test(raw)) {\n continue;\n }\n if (!/^\\s/.test(raw)) {\n // Hit the next top-level key — catalog block ended.\n break;\n }\n const match = raw.match(/^\\s+(?:'([^']+)'|\"([^\"]+)\"|([^:\\s'\"]+))\\s*:\\s*(.*?)\\s*(?:#.*)?$/);\n if (!match) {\n continue;\n }\n const name = match[1] ?? match[2] ?? match[3];\n if (name === undefined) continue;\n const rawValue = match[4] ?? '';\n const version = stripQuotes(rawValue.trim());\n if (version === '') continue;\n entries.push([name, version]);\n }\n return entries;\n}\n\nfunction stripQuotes(value: string): string {\n if (value.length >= 2) {\n const first = value[0];\n const last = value[value.length - 1];\n if ((first === '\"' && last === '\"') || (first === \"'\" && last === \"'\")) {\n return value.slice(1, -1);\n }\n }\n return value;\n}\n","import { CliStructuredError } from '../../utils/cli-errors';\n\n/**\n * No `package.json` / `deno.json` / `deno.jsonc` in the target directory.\n *\n * `init` cannot bootstrap a fresh project from a bare directory (NG1) — that\n * gap is tracked separately. The fix is for the user to run `npm init` (or\n * the equivalent for their package manager) first.\n */\nexport function errorInitMissingManifest(): CliStructuredError {\n return new CliStructuredError('5001', 'No project manifest found', {\n domain: 'CLI',\n why: 'No package.json or deno.json found in the target directory. `prisma-next init` requires an existing project to attach to.',\n fix: 'Initialize your project first (e.g. `npm init -y` or `deno init`), then re-run `prisma-next init`.',\n docsUrl: 'https://prisma-next.dev/docs/cli/init',\n });\n}\n\n/**\n * Re-init in non-interactive mode without `--force`. Distinct from the\n * decline-the-prompt path (which is `errorInitUserAborted`) because here\n * the user was never given the choice — `--force` is the contract.\n */\nexport function errorInitReinitNeedsForce(): CliStructuredError {\n return new CliStructuredError('5002', 'Project is already initialized', {\n domain: 'CLI',\n why: 'A `prisma-next.config.ts` already exists in this directory. Re-running `init` would overwrite the scaffolded files; in non-interactive mode `init` will not do that without `--force`.',\n fix: 'Pass `--force` to overwrite the existing scaffold, or run `init` interactively to confirm.',\n docsUrl: 'https://prisma-next.dev/docs/cli/init',\n });\n}\n\n/**\n * Non-interactive mode is missing one or more required inputs. Lists every\n * missing flag in the error so an agent / CI script can react without\n * needing to parse English.\n *\n * @param missing — kebab-case flag names without leading dashes\n * @param why — additional context (e.g. \"stdin is not a TTY\") that helps\n * the user understand why interactive fallback was skipped.\n */\nexport function errorInitMissingFlags(options: {\n readonly missing: readonly string[];\n readonly why: string;\n}): CliStructuredError {\n const flagList = options.missing.map((flag) => `--${flag}`).join(', ');\n const fixList = options.missing\n .map((flag) => {\n switch (flag) {\n case 'target':\n return '--target postgres|mongodb';\n case 'authoring':\n return '--authoring psl|typescript';\n case 'schema-path':\n return '--schema-path <path>';\n default:\n return `--${flag} <value>`;\n }\n })\n .join(' ');\n return new CliStructuredError('5003', 'Missing required flags', {\n domain: 'CLI',\n why: `${options.why} Missing required flag(s): ${flagList}.`,\n fix: `Re-run with the missing flag(s) supplied, e.g. \\`prisma-next init --yes ${fixList}\\`. Use \\`prisma-next init --help\\` to see every flag.`,\n docsUrl: 'https://prisma-next.dev/docs/cli/init',\n meta: { missingFlags: options.missing },\n });\n}\n\n/**\n * A flag value was supplied but is not in the allowed set. Lists the\n * allowed values in `meta` for machine-readable consumption.\n */\nexport function errorInitInvalidFlagValue(options: {\n readonly flag: string;\n readonly value: string;\n readonly allowed: readonly string[];\n}): CliStructuredError {\n return new CliStructuredError('5004', `Invalid value for --${options.flag}`, {\n domain: 'CLI',\n why: `\\`--${options.flag} ${options.value}\\` is not one of: ${options.allowed.join(', ')}.`,\n fix: `Use one of: ${options.allowed.map((v) => `--${options.flag} ${v}`).join(', ')}.`,\n docsUrl: 'https://prisma-next.dev/docs/cli/init',\n meta: { flag: options.flag, value: options.value, allowed: options.allowed },\n });\n}\n\n/**\n * The user cancelled an interactive prompt (Ctrl-C, escape, declined a\n * selection). Distinct from `errorInitReinitNeedsForce` because that path\n * applies to non-interactive mode where the user was never given the\n * choice; this one is the generic \"user said no\" path. Maps to exit code\n * 3 (USER_ABORTED).\n */\nexport function errorInitUserAborted(): CliStructuredError {\n return new CliStructuredError('5006', 'Init cancelled', {\n domain: 'CLI',\n why: 'The interactive prompt was cancelled before all required inputs were supplied. No files were modified.',\n fix: 'Re-run `prisma-next init` and complete the prompts, or pass the required inputs as flags (see `--help`) for a non-interactive run.',\n severity: 'info',\n });\n}\n\n/**\n * `--strict-probe` was supplied without `--probe-db`. Per FR8.3 / NFR9\n * (offline-by-default), `--strict-probe` is a no-op without `--probe-db` —\n * but rather than silently ignoring it we tell the user what they probably\n * meant. Without this guard, the flag combination silently does nothing,\n * which is exactly the kind of \"looks like it worked\" trap that a strict\n * mode is supposed to prevent.\n */\nexport function errorInitStrictProbeWithoutProbe(): CliStructuredError {\n return new CliStructuredError('5005', '`--strict-probe` requires `--probe-db`', {\n domain: 'CLI',\n why: '`--strict-probe` only changes how a *failed* probe is reported; without `--probe-db` no probe is attempted in the first place. (`init` is offline-by-default — it never opens a connection to your database without explicit consent.)',\n fix: 'Add `--probe-db` to opt in to the probe, or drop `--strict-probe` if you do not need the version check.',\n docsUrl: 'https://prisma-next.dev/docs/cli/init',\n });\n}\n\n/**\n * Dependency installation failed and the pnpm → npm fallback (FR7.2)\n * either did not apply (pm ≠ pnpm or stderr did not match a recognised\n * leak) or also failed. Files scaffolded before the install step are\n * already on disk; `meta.filesWritten` carries the list so a follow-up\n * agent can resume manually. Maps to exit code `4 = INSTALL_FAILED`.\n */\nexport function errorInitInstallFailed(options: {\n readonly addCommand: string;\n readonly addDevCommand: string;\n readonly emitCommand: string;\n readonly filesWritten: readonly string[];\n readonly stderrLines: readonly string[];\n}): CliStructuredError {\n const trimmed = options.stderrLines.map((s) => s.trim()).filter(Boolean);\n const why =\n trimmed.length === 0\n ? 'The package manager exited with an error and no recoverable fallback applied.'\n : `The package manager exited with: ${trimmed[0]}`;\n return new CliStructuredError('5007', 'Failed to install dependencies', {\n domain: 'CLI',\n why,\n fix: `Install manually:\\n ${options.addCommand}\\n ${options.addDevCommand}\\nThen run \\`${options.emitCommand}\\` to emit the contract.`,\n docsUrl: 'https://prisma-next.dev/docs/cli/init',\n meta: {\n filesWritten: options.filesWritten,\n stderr: trimmed,\n },\n });\n}\n\n/**\n * The user's project manifest (typically `package.json`) failed to parse\n * as JSON. Init reads the manifest to merge `scripts` (FR3.5) and to\n * skip `@types/node` when it is already declared (FR2.1); a malformed\n * file would otherwise surface as an `INTERNAL_ERROR` with a raw\n * `SyntaxError` stack, which violates the FR1.6 contract that every\n * documented failure mode maps to a stable exit code.\n *\n * Maps to exit code `2 = PRECONDITION` — the user can fix the manifest\n * and re-run.\n */\nexport function errorInitInvalidManifest(options: {\n readonly path: string;\n readonly cause: string;\n}): CliStructuredError {\n return new CliStructuredError('5010', `Failed to parse ${options.path}`, {\n domain: 'CLI',\n why: `\\`${options.path}\\` is not valid JSON: ${options.cause}`,\n fix: `Fix the JSON syntax in \\`${options.path}\\` (a missing comma or unbalanced brace is the most common cause), then re-run \\`prisma-next init\\`.`,\n docsUrl: 'https://prisma-next.dev/docs/cli/init',\n meta: { path: options.path, cause: options.cause },\n });\n}\n\n/**\n * The user's existing `tsconfig.json` could not be parsed even with JSONC\n * tolerance (comments + trailing commas) enabled. Init merges the\n * minimum compiler options the scaffolded files need (FR2.2), so an\n * unparseable tsconfig is a hard precondition failure: we cannot\n * faithfully edit a file we cannot read.\n *\n * Init must surface this **before** writing any scaffold file so the\n * user's working tree stays byte-identical (FR6.2 / NFR3) — see\n * `runInit` for the precondition gate.\n *\n * Maps to exit code `2 = PRECONDITION` — the user can fix the file and\n * re-run.\n */\nexport function errorInitInvalidTsconfig(options: {\n readonly path: string;\n readonly cause: string;\n}): CliStructuredError {\n return new CliStructuredError('5011', `Failed to parse ${options.path}`, {\n domain: 'CLI',\n why: `\\`${options.path}\\` is not valid JSON or JSONC: ${options.cause}`,\n fix: `Fix the syntax in \\`${options.path}\\` and re-run \\`prisma-next init\\`. \\`init\\` accepts JSONC (comments and trailing commas) but cannot recover from unbalanced braces or missing commas.`,\n docsUrl: 'https://prisma-next.dev/docs/cli/init',\n meta: { path: options.path, cause: options.cause },\n });\n}\n\n/**\n * `--probe-db` was supplied along with `--strict-probe` and the probe\n * could not complete (no `DATABASE_URL`, network/auth error, the target\n * driver was not installed, …). Without `--strict-probe` the probe\n * surfaces these as warnings; `--strict-probe` escalates them to\n * fatal so a CI gate can rely on \"init exit code 2 means something\n * about the runtime environment is wrong\" (FR8.3).\n *\n * Maps to exit code `2 = PRECONDITION`. The caller's project files\n * are already on disk by this point — the probe runs after the write\n * phase — but the install/emit steps may or may not have completed\n * depending on `--no-install` and the exact failure mode; `meta`\n * carries `filesWritten` so a follow-up agent can resume manually.\n */\nexport function errorInitProbeFailed(options: {\n readonly cause: string;\n readonly filesWritten: readonly string[];\n}): CliStructuredError {\n return new CliStructuredError('5012', 'Database probe failed', {\n domain: 'CLI',\n why: `\\`--probe-db\\` could not complete and \\`--strict-probe\\` was set: ${options.cause}`,\n fix: 'Confirm `DATABASE_URL` points at a reachable server, or drop `--strict-probe` to treat probe failures as warnings.',\n docsUrl: 'https://prisma-next.dev/docs/cli/init',\n meta: {\n filesWritten: options.filesWritten,\n cause: options.cause,\n },\n });\n}\n\n/**\n * `prisma-next contract emit` failed after a successful install. Surface\n * the underlying error so the user can fix it and re-run; files and\n * dependencies remain on disk untouched. Maps to exit code\n * `5 = EMIT_FAILED`.\n */\nexport function errorInitEmitFailed(options: {\n readonly emitCommand: string;\n readonly filesWritten: readonly string[];\n readonly cause: string;\n}): CliStructuredError {\n return new CliStructuredError('5008', 'Failed to emit contract', {\n domain: 'CLI',\n why: `\\`prisma-next contract emit\\` failed: ${options.cause}`,\n fix: `Inspect your contract file, fix the underlying issue, then re-run \\`${options.emitCommand}\\`. Pass \\`-v\\` for the full error envelope.`,\n docsUrl: 'https://prisma-next.dev/docs/cli/contract-emit',\n meta: {\n filesWritten: options.filesWritten,\n cause: options.cause,\n },\n });\n}\n","import type { TargetId } from './templates/code-templates';\n\n/**\n * The schema-relative `.gitattributes` entries written for a freshly\n * initialised project (FR3.4). Mirrors the relevant subset of the\n * repo-root [`.gitattributes`](../../../../../../../../.gitattributes):\n *\n * - **Today**: `contract.json`, `contract.d.ts` are emitted on every\n * `prisma-next contract emit`. Marking them `linguist-generated`\n * keeps GitHub's diff stats honest and collapses the file in code\n * review by default.\n * - **Forward-looking**: `end-contract.*`, `start-contract.*`, `ops.json`,\n * `migration.json` are not yet emitted by `init` flows but will be\n * produced by adjacent commands (lower / migration tooling). Adding\n * them now matches Decision 5 (forward-looking subset) so the file\n * does not need to be amended every time a new artefact lands.\n *\n * Patterns are written relative to the schema directory so a user\n * who runs `init --schema-path db/contract.prisma` gets\n * `db/contract.json linguist-generated` — not the workspace-glob form\n * `<glob>/contract.json` (which would over-match any unrelated\n * `contract.json` the user has elsewhere) and not the absolute\n * `prisma/contract.json` (which would silently break for a non-default\n * schema path).\n */\nconst ARTEFACT_FILENAMES: readonly string[] = [\n 'contract.json',\n 'contract.d.ts',\n 'end-contract.json',\n 'end-contract.d.ts',\n 'start-contract.json',\n 'start-contract.d.ts',\n 'ops.json',\n 'migration.json',\n];\n\nconst ATTRIBUTE = 'linguist-generated';\n\n/**\n * Computes the `.gitattributes` lines this scaffold expects to own. Each\n * line has the shape `<path> linguist-generated`. The `target` parameter\n * is currently unused but accepted for symmetry with the other hygiene\n * helpers and to leave room for target-specific entries (e.g. a future\n * Mongo-only artefact) without a signature break.\n */\nexport function requiredGitattributesLines(\n schemaDir: string,\n _target: TargetId,\n): readonly string[] {\n const dir = schemaDir === '.' ? '' : schemaDir.replace(/\\/+$/, '');\n const prefix = dir === '' ? '' : `${dir}/`;\n return ARTEFACT_FILENAMES.map((file) => `${prefix}${file} ${ATTRIBUTE}`);\n}\n\n/**\n * Idempotent `.gitattributes` merge (FR3.4 / FR9.3). Returns the new file\n * content given the existing content (or `undefined` if the file does\n * not yet exist).\n *\n * Equivalence is exact-line: a user-customised line like\n * `prisma/*.json linguist-generated` is *not* recognised as covering\n * `prisma/contract.json linguist-generated`. We accept that\n * over-specification — preserving the user's broad pattern *and*\n * appending the narrow one — because the narrow lines are what the\n * acceptance criteria pin (FR3.4 AC).\n *\n * Returns `null` when no changes are required (file already contains\n * every required entry).\n */\nexport function mergeGitattributes(\n existing: string | undefined,\n required: readonly string[],\n): string | null {\n if (existing === undefined) {\n return `${required.join('\\n')}\\n`;\n }\n\n const presentLines = new Set(\n existing\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0 && !line.startsWith('#')),\n );\n\n const missing = required.filter((line) => !presentLines.has(line));\n if (missing.length === 0) {\n return null;\n }\n\n // Mirrors `mergeGitignore`: a zero-byte existing file would otherwise\n // gain a leading blank line, because `''.endsWith('\\n')` is false. The\n // empty-file case is uncommon (most projects either don't have a\n // `.gitattributes` or have one with content), but symmetric handling\n // keeps the two mergers' invariants identical.\n const separator = existing.length === 0 || existing.endsWith('\\n') ? '' : '\\n';\n return `${existing}${separator}${missing.join('\\n')}\\n`;\n}\n","/**\n * The minimal `.gitignore` lines a Prisma Next scaffold needs (FR3.3).\n * Order matches what Node tooling typically writes today.\n *\n * `node_modules/` first because it's the byte-largest miss; `dist/`\n * because the scaffolded `tsconfig.json` writes there; `.env` last so\n * the secret-bearing file is the one most-recently visible in any diff\n * (a paranoid-correct ordering — humans skim from the top).\n */\nexport const REQUIRED_GITIGNORE_ENTRIES: readonly string[] = ['node_modules/', 'dist/', '.env'];\n\n/**\n * Idempotent `.gitignore` merge (FR3.3 / FR9.3). Returns the new file\n * content given the existing content (or `undefined` if the file does\n * not yet exist). Adds only entries that are not already present and\n * never duplicates a line. Existing comments and blank lines are\n * preserved verbatim — `.gitignore` is parsed by `git` without a tree,\n * so any line modification risks changing semantics.\n *\n * Pattern equivalence is line-literal: `node_modules/` and `node_modules`\n * are treated as different entries. This is intentional — `git` treats\n * them differently (the trailing slash restricts the match to\n * directories), and the AC pins the trailing-slash form.\n *\n * Returns `null` when no changes are required (file already contains\n * every required entry). The caller can use this to decide whether to\n * include `.gitignore` in `filesWritten`.\n */\nexport function mergeGitignore(existing: string | undefined): string | null {\n if (existing === undefined) {\n return `${REQUIRED_GITIGNORE_ENTRIES.join('\\n')}\\n`;\n }\n\n const present = new Set(\n existing\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0 && !line.startsWith('#')),\n );\n\n const missing = REQUIRED_GITIGNORE_ENTRIES.filter((entry) => !present.has(entry));\n if (missing.length === 0) {\n return null;\n }\n\n const separator = existing.length === 0 || existing.endsWith('\\n') ? '' : '\\n';\n return `${existing}${separator}${missing.join('\\n')}\\n`;\n}\n","/**\n * The package.json `scripts` entries `init` adds idempotently (FR3.5).\n * The script *name* mirrors the CLI subcommand path (`contract:emit` →\n * `prisma-next contract emit`) so the script is greppable: a user\n * encountering `npm run contract:emit` in CI logs can navigate\n * straight to the equivalent CLI invocation.\n *\n * No watch-mode entry is included (Spec Decision 9) — file-watching is\n * the build tool's job (Vite plugin, `tsc --watch`, etc.).\n */\nexport interface RequiredScript {\n readonly name: string;\n readonly command: string;\n}\n\nexport const REQUIRED_SCRIPTS: readonly RequiredScript[] = [\n { name: 'contract:emit', command: 'prisma-next contract emit' },\n];\n\nexport interface PackageScriptsMergeResult {\n /**\n * The new package.json content. `null` when no changes are required\n * (every required script is already present with the correct\n * command).\n */\n readonly content: string | null;\n /**\n * Structured warnings raised when an existing script of the same\n * name maps to a different command. Each warning names the script,\n * the existing command, and the command we wanted to write — the\n * user can decide whether to keep their override or update it.\n */\n readonly warnings: readonly string[];\n}\n\n/**\n * Idempotent `package.json#scripts` merge with collision detection\n * (FR3.5 / FR9.3):\n *\n * - If a required script is **missing**, append it.\n * - If a required script is **already present and identical**, leave\n * the file alone (idempotency).\n * - If a required script is **present but maps to a different command**,\n * skip the write for that script and surface a structured warning.\n * The user's override is sacred — `init` should never silently\n * overwrite a custom build pipeline.\n *\n * Preserves the existing key order (so a user who has alphabetised\n * their scripts does not see them reshuffled) and appends new entries\n * at the end.\n *\n * The `package.json` is parsed and re-stringified through `JSON` —\n * comments are not preserved (package.json does not support them per\n * spec). Trailing newline matches the original input's trailing\n * newline behaviour.\n */\nexport function mergePackageScripts(\n existing: string,\n required: readonly RequiredScript[] = REQUIRED_SCRIPTS,\n): PackageScriptsMergeResult {\n const parsed = JSON.parse(existing) as Record<string, unknown>;\n const scripts: Record<string, string> =\n typeof parsed['scripts'] === 'object' && parsed['scripts'] !== null\n ? { ...(parsed['scripts'] as Record<string, string>) }\n : {};\n\n const warnings: string[] = [];\n let mutated = false;\n\n for (const { name, command } of required) {\n const existingValue = scripts[name];\n if (existingValue === undefined) {\n scripts[name] = command;\n mutated = true;\n continue;\n }\n if (existingValue !== command) {\n warnings.push(\n `package.json already has a \"${name}\" script with a different command — keeping yours.\\n existing: ${existingValue}\\n expected: ${command}\\nIf you want the default, remove your \"${name}\" script and re-run \\`init\\`.`,\n );\n }\n }\n\n if (!mutated) {\n return { content: null, warnings };\n }\n\n parsed['scripts'] = scripts;\n const trailingNewline = existing.endsWith('\\n') ? '\\n' : '';\n return { content: `${JSON.stringify(parsed, null, 2)}${trailingNewline}`, warnings };\n}\n","export type TargetId = 'postgres' | 'mongo';\nexport type AuthoringId = 'psl' | 'typescript';\n\nexport function targetPackageName(target: TargetId): string {\n return target === 'postgres' ? '@prisma-next/postgres' : '@prisma-next/mongo';\n}\n\nexport function targetLabel(target: TargetId): string {\n return target === 'postgres' ? 'PostgreSQL' : 'MongoDB';\n}\n\nexport function defaultSchemaPath(authoring: AuthoringId): string {\n if (authoring === 'typescript') {\n return 'prisma/contract.ts';\n }\n return 'prisma/contract.prisma';\n}\n\nexport function starterSchema(target: TargetId, authoring: AuthoringId): string {\n if (authoring === 'typescript') {\n return target === 'mongo' ? starterSchemaTsMongo() : starterSchemaTsPostgres();\n }\n return target === 'mongo' ? starterSchemaPslMongo() : starterSchemaPslPostgres();\n}\n\n/**\n * Renders a short authoring-appropriate schema sample (FR5.1) for embedding\n * in `prisma-next.md`. Returns a complete fenced markdown code block.\n *\n * The sample intentionally shows just one model: it's illustrative, not\n * a substitute for the full scaffolded contract file. The TS samples use\n * the same outer shape as `starterSchemaTs*` (FR5.3) so a user reading\n * the doc and the file side-by-side sees the same structure.\n */\nexport function schemaSample(target: TargetId, authoring: AuthoringId): string {\n if (authoring === 'typescript') {\n return target === 'mongo' ? schemaSampleTsMongo() : schemaSampleTsPostgres();\n }\n return target === 'mongo' ? schemaSamplePslMongo() : schemaSamplePslPostgres();\n}\n\nfunction schemaSamplePslPostgres(): string {\n return `\\`\\`\\`prisma\nmodel User {\n id Int @id @default(autoincrement())\n email String @unique\n name String?\n}\n\\`\\`\\``;\n}\n\nfunction schemaSamplePslMongo(): string {\n return `\\`\\`\\`prisma\nmodel User {\n id ObjectId @id @map(\"_id\")\n email String @unique\n name String?\n @@map(\"users\")\n}\n\\`\\`\\``;\n}\n\nfunction schemaSampleTsPostgres(): string {\n return `\\`\\`\\`typescript\nimport sqlFamily from '@prisma-next/family-sql/pack';\nimport { defineContract } from '@prisma-next/sql-contract-ts/contract-builder';\nimport postgresPack from '@prisma-next/target-postgres/pack';\n\nexport const contract = defineContract(\n { family: sqlFamily, target: postgresPack },\n ({ field, model }) => ({\n models: {\n User: model('User', {\n fields: {\n id: field.id.uuidv7(),\n email: field.text().unique(),\n name: field.text().optional(),\n },\n }),\n },\n }),\n);\n\\`\\`\\``;\n}\n\nfunction schemaSampleTsMongo(): string {\n return `\\`\\`\\`typescript\nimport mongoFamily from '@prisma-next/family-mongo/pack';\nimport { defineContract } from '@prisma-next/mongo-contract-ts/contract-builder';\nimport mongoTarget from '@prisma-next/target-mongo/pack';\n\nexport const contract = defineContract(\n { family: mongoFamily, target: mongoTarget },\n ({ field, model }) => ({\n models: {\n User: model('User', {\n collection: 'users',\n fields: {\n _id: field.objectId(),\n email: field.string(),\n name: field.string().optional(),\n },\n }),\n },\n }),\n);\n\\`\\`\\``;\n}\n\nfunction starterSchemaPslPostgres(): string {\n return `model User {\n id Int @id @default(autoincrement())\n email String @unique\n name String?\n posts Post[]\n createdAt DateTime @default(now())\n}\n\nmodel Post {\n id Int @id @default(autoincrement())\n title String\n content String?\n author User @relation(fields: [authorId], references: [id])\n authorId Int\n createdAt DateTime @default(now())\n}\n`;\n}\n\nfunction starterSchemaPslMongo(): string {\n return `model User {\n id ObjectId @id @map(\"_id\")\n email String @unique\n name String?\n posts Post[]\n @@map(\"users\")\n}\n\nmodel Post {\n id ObjectId @id @map(\"_id\")\n title String\n content String?\n author User @relation(fields: [authorId], references: [id])\n authorId ObjectId\n @@map(\"posts\")\n}\n`;\n}\n\nfunction starterSchemaTsPostgres(): string {\n return `import sqlFamily from '@prisma-next/family-sql/pack';\nimport { defineContract } from '@prisma-next/sql-contract-ts/contract-builder';\nimport postgresPack from '@prisma-next/target-postgres/pack';\n\nexport const contract = defineContract(\n { family: sqlFamily, target: postgresPack },\n ({ field, model, rel }) => ({\n models: {\n User: model('User', {\n fields: {\n id: field.id.uuidv7(),\n email: field.text().unique(),\n name: field.text().optional(),\n createdAt: field.createdAt(),\n },\n relations: {\n posts: rel.hasMany('Post', { by: 'authorId' }),\n },\n }),\n\n Post: model('Post', {\n fields: {\n id: field.id.uuidv7(),\n title: field.text(),\n content: field.text().optional(),\n authorId: field.uuid(),\n createdAt: field.createdAt(),\n },\n relations: {\n author: rel.belongsTo('User', { from: 'authorId', to: 'id' }),\n },\n }),\n },\n }),\n);\n`;\n}\n\nfunction starterSchemaTsMongo(): string {\n return `import mongoFamily from '@prisma-next/family-mongo/pack';\nimport { defineContract } from '@prisma-next/mongo-contract-ts/contract-builder';\nimport mongoTarget from '@prisma-next/target-mongo/pack';\n\nexport const contract = defineContract(\n { family: mongoFamily, target: mongoTarget },\n ({ field, model, rel }) => ({\n models: {\n User: model('User', {\n collection: 'users',\n fields: {\n _id: field.objectId(),\n email: field.string(),\n name: field.string().optional(),\n },\n relations: {\n posts: rel.hasMany('Post', { from: '_id', to: 'authorId' }),\n },\n }),\n\n Post: model('Post', {\n collection: 'posts',\n fields: {\n _id: field.objectId(),\n title: field.string(),\n content: field.string().optional(),\n authorId: field.objectId(),\n },\n relations: {\n author: rel.belongsTo('User', { from: 'authorId', to: '_id' }),\n },\n }),\n },\n }),\n);\n`;\n}\n\nexport function configFile(target: TargetId, contractPath: string): string {\n const pkg = targetPackageName(target);\n return `import 'dotenv/config';\nimport { defineConfig } from '${pkg}/config';\n\nexport default defineConfig({\n contract: ${JSON.stringify(contractPath)},\n db: {\n connection: process.env['DATABASE_URL']!,\n },\n});\n`;\n}\n\nexport function dbFile(target: TargetId): string {\n if (target === 'postgres') {\n return `import postgres from '@prisma-next/postgres/runtime';\nimport type { Contract } from './contract.d';\nimport contractJson from './contract.json' with { type: 'json' };\n\nexport const db = postgres<Contract>({ contractJson });\n`;\n }\n\n return `import mongo from '@prisma-next/mongo/runtime';\nimport type { Contract } from './contract.d';\nimport contractJson from './contract.json' with { type: 'json' };\n\nexport const db = mongo<Contract>({\n contractJson,\n url: process.env['DATABASE_URL']!,\n});\n`;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport * as clack from '@clack/prompts';\nimport { extname, join, normalize } from 'pathe';\nimport type { GlobalFlags } from '../../utils/global-flags';\nimport {\n errorInitInvalidFlagValue,\n errorInitMissingFlags,\n errorInitReinitNeedsForce,\n errorInitStrictProbeWithoutProbe,\n errorInitUserAborted,\n} from './errors';\nimport {\n type AuthoringId,\n defaultSchemaPath,\n type TargetId,\n targetLabel,\n targetPackageName,\n} from './templates/code-templates';\n\n/**\n * Raw command-line input as Commander.js parses it. `target` here uses the\n * user-facing `mongodb` spelling (matching the flag); the internal\n * `TargetId` uses `mongo`. The mapping happens in `resolveInitInputs`.\n */\nexport interface InitFlagOptions {\n readonly target?: string;\n readonly authoring?: string;\n readonly schemaPath?: string;\n readonly force?: boolean;\n readonly writeEnv?: boolean;\n readonly probeDb?: boolean;\n readonly strictProbe?: boolean;\n readonly install?: boolean;\n}\n\n/**\n * The fully-resolved set of decisions `runInit` operates on. After this\n * value object is constructed, `runInit` should not need to consult the\n * environment again for any user-visible decision.\n */\nexport interface ResolvedInitInputs {\n readonly target: TargetId;\n readonly authoring: AuthoringId;\n readonly schemaPath: string;\n readonly install: boolean;\n readonly writeEnv: boolean;\n readonly probeDb: boolean;\n readonly strictProbe: boolean;\n /**\n * True if the project already has `prisma-next.config.ts` and the user\n * has agreed (or `--force` has been supplied) to overwrite it.\n */\n readonly reinit: boolean;\n /**\n * FR9.2 — set to the **previous** facade package name (e.g.\n * `@prisma-next/postgres`) when re-init is switching targets and the\n * user has consented to remove it from `package.json#dependencies`.\n * `null` when no removal is needed: not a re-init, no previous facade\n * present, the previous facade matches the chosen target, or the user\n * declined the interactive confirm. The chosen-target facade itself\n * is added separately via the install step.\n */\n readonly removePreviousFacade: string | null;\n}\n\nconst TARGET_ALIASES: ReadonlyMap<string, TargetId> = new Map([\n ['postgres', 'postgres'],\n ['postgresql', 'postgres'],\n ['mongo', 'mongo'],\n ['mongodb', 'mongo'],\n]);\n\nconst AUTHORING_VALUES: ReadonlyMap<string, AuthoringId> = new Map([\n ['psl', 'psl'],\n ['typescript', 'typescript'],\n ['ts', 'typescript'],\n]);\n\n/**\n * Resolves every required input for `runInit`. In interactive mode, missing\n * inputs are prompted via clack; in non-interactive mode, missing required\n * inputs throw a structured error listing exactly which flags are missing\n * (FR1.4). Throws `CliStructuredError` on any unrecoverable input issue.\n *\n * `canPrompt` is decoupled from `flags.interactive` so the action handler\n * (`./index.ts`) owns the merge of stdout-TTY (decoration) and stdin-TTY\n * (prompts). `flags.interactive` continues to gate `TerminalUI` decoration\n * — see [Style Guide § Interactivity](../../../../../../../docs/CLI%20Style%20Guide.md#interactivity).\n */\nexport async function resolveInitInputs(ctx: {\n readonly baseDir: string;\n readonly options: InitFlagOptions;\n readonly flags: GlobalFlags;\n readonly canPrompt: boolean;\n}): Promise<ResolvedInitInputs> {\n const { baseDir, options, flags, canPrompt } = ctx;\n // `--force` and `--yes` are deliberately separate: `--force` is the\n // contract for \"overwrite an existing scaffold\" (works in both modes);\n // `--yes` only auto-accepts interactive prompts and never substitutes\n // for the explicit destructive opt-in. In non-interactive mode, `--yes`\n // alone does nothing useful; the user must supply `--target`,\n // `--authoring`, and (for re-init) `--force`.\n const force = Boolean(options.force);\n const autoAcceptPrompts = Boolean(flags.yes);\n\n // --strict-probe is a no-op without --probe-db; surface the mistake\n // rather than silently swallowing it (FR8.3 / NFR9).\n if (options.strictProbe && !options.probeDb) {\n throw errorInitStrictProbeWithoutProbe();\n }\n\n const reinit = await resolveReinit({ baseDir, force, canPrompt, autoAcceptPrompts });\n const target = resolveTarget(options.target);\n const authoring = resolveAuthoring(options.authoring);\n\n // Now collect what's still missing under non-interactive rules.\n const missing: string[] = [];\n if (target === undefined) missing.push('target');\n if (authoring === undefined) missing.push('authoring');\n\n if (!canPrompt && missing.length > 0) {\n const reason = process.stdin.isTTY\n ? 'Non-interactive mode is active (`--no-interactive` or stdout is piped).'\n : 'stdin is not a TTY, so `init` cannot prompt interactively.';\n throw errorInitMissingFlags({ missing, why: reason });\n }\n\n // Interactive path — fall back to clack for anything still missing.\n const finalTarget = target ?? (await promptTarget());\n const finalAuthoring = authoring ?? (await promptAuthoring());\n const finalSchemaPath =\n options.schemaPath !== undefined\n ? validateSchemaPath(options.schemaPath, finalAuthoring)\n : canPrompt\n ? await promptSchemaPath(finalAuthoring)\n : defaultSchemaPath(finalAuthoring);\n\n // FR3.2: `--write-env` is the explicit opt-in for non-interactive\n // mode. Interactive runs additionally get a single confirm — but only\n // when the flag was not already supplied (an explicit `--write-env`\n // suppresses the prompt) and `--yes` did not auto-accept everything\n // (in which case interactive mode is effectively non-interactive and\n // the flag-only contract applies). See Style Guide § Interactivity.\n const writeEnv = await resolveWriteEnv({\n flag: options.writeEnv,\n canPrompt,\n autoAcceptPrompts,\n });\n\n // FR9.2 — when re-init switches targets, ask whether to drop the\n // previous facade from `dependencies`. Detection happens here (not in\n // `runInit`) so the prompt sequence stays in one place; the actual\n // edit is applied during `runInit`'s precondition phase alongside the\n // other `package.json` merges.\n const removePreviousFacade = await resolveRemovePreviousFacade({\n baseDir,\n target: finalTarget,\n reinit,\n force,\n canPrompt,\n autoAcceptPrompts,\n });\n\n return {\n target: finalTarget,\n authoring: finalAuthoring,\n schemaPath: finalSchemaPath,\n install: options.install !== false,\n writeEnv,\n probeDb: Boolean(options.probeDb),\n strictProbe: Boolean(options.strictProbe),\n reinit,\n removePreviousFacade,\n };\n}\n\nasync function resolveWriteEnv(opts: {\n readonly flag: boolean | undefined;\n readonly canPrompt: boolean;\n readonly autoAcceptPrompts: boolean;\n}): Promise<boolean> {\n if (opts.flag !== undefined) {\n return Boolean(opts.flag);\n }\n if (!opts.canPrompt || opts.autoAcceptPrompts) {\n return false;\n }\n const result = await clack.confirm({\n message: 'Also write a .env file from .env.example? (gitignored)',\n initialValue: false,\n output: process.stderr,\n });\n if (clack.isCancel(result)) {\n throw errorInitUserAborted();\n }\n return Boolean(result);\n}\n\n/**\n * FR9.2 — detects whether re-init is switching targets (the previous\n * facade differs from the chosen target's facade) and resolves the\n * remove-or-keep question.\n *\n * The non-interactive contract is the same as the `--force` re-init\n * gate above: a non-interactive run that reaches this helper always\n * has `--force` (otherwise `resolveReinit` would have thrown 5002), so\n * the removal proceeds without further prompting. Interactive runs see\n * a `clack.confirm` with `initialValue: true` — the destructive default\n * is correct because keeping both facades produces a project that\n * imports from one but pays for both in the lockfile, which is a\n * silent foot-gun the user almost never wants.\n *\n * Returns the previous facade package name when the user consented (or\n * was force-ed) to remove it, otherwise `null`. Parse failures on\n * `package.json` resolve to `null` here — `runInit`'s precondition\n * gate surfaces a structured 5010 error for the same file shortly\n * after, so we avoid double-reporting and keep this helper side-effect\n * free under hostile inputs.\n */\nasync function resolveRemovePreviousFacade(opts: {\n readonly baseDir: string;\n readonly target: TargetId;\n readonly reinit: boolean;\n readonly force: boolean;\n readonly canPrompt: boolean;\n readonly autoAcceptPrompts: boolean;\n}): Promise<string | null> {\n if (!opts.reinit) {\n return null;\n }\n const packageJsonPath = join(opts.baseDir, 'package.json');\n if (!existsSync(packageJsonPath)) {\n return null;\n }\n const otherTarget: TargetId = opts.target === 'postgres' ? 'mongo' : 'postgres';\n const otherFacade = targetPackageName(otherTarget);\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as Record<string, unknown>;\n } catch {\n return null;\n }\n const deps = parsed['dependencies'];\n if (deps === null || typeof deps !== 'object' || Array.isArray(deps)) {\n return null;\n }\n if (!Object.hasOwn(deps as Record<string, unknown>, otherFacade)) {\n return null;\n }\n\n // `--force` (and `--yes` in interactive mode) auto-confirms the\n // removal. The `!canPrompt` branch is unreachable in practice because\n // the FR9.0 reinit gate already required `--force` for non-interactive\n // re-init, but we keep the guard for defence-in-depth.\n if (opts.force || (opts.canPrompt && opts.autoAcceptPrompts)) {\n return otherFacade;\n }\n if (!opts.canPrompt) {\n return otherFacade;\n }\n const result = await clack.confirm({\n message: `Switching from ${targetLabel(otherTarget)} to ${targetLabel(opts.target)} — remove ${otherFacade} from package.json dependencies?`,\n initialValue: true,\n output: process.stderr,\n });\n if (clack.isCancel(result)) {\n throw errorInitUserAborted();\n }\n return result === true ? otherFacade : null;\n}\n\nasync function resolveReinit(opts: {\n readonly baseDir: string;\n readonly force: boolean;\n readonly canPrompt: boolean;\n readonly autoAcceptPrompts: boolean;\n}): Promise<boolean> {\n const configPath = join(opts.baseDir, 'prisma-next.config.ts');\n if (!existsSync(configPath)) {\n return false;\n }\n if (opts.force) {\n return true;\n }\n if (!opts.canPrompt) {\n throw errorInitReinitNeedsForce();\n }\n // In interactive mode, `--yes` auto-accepts the re-init confirm.\n if (opts.autoAcceptPrompts) {\n return true;\n }\n const result = await clack.confirm({\n message:\n 'This project is already initialized. Re-initialize? This will overwrite all generated files.',\n initialValue: false,\n output: process.stderr,\n });\n if (clack.isCancel(result) || result !== true) {\n throw errorInitUserAborted();\n }\n return true;\n}\n\nfunction resolveTarget(value: string | undefined): TargetId | undefined {\n if (value === undefined) return undefined;\n const mapped = TARGET_ALIASES.get(value.toLowerCase());\n if (mapped === undefined) {\n throw errorInitInvalidFlagValue({\n flag: 'target',\n value,\n allowed: ['postgres', 'mongodb'],\n });\n }\n return mapped;\n}\n\nfunction resolveAuthoring(value: string | undefined): AuthoringId | undefined {\n if (value === undefined) return undefined;\n const mapped = AUTHORING_VALUES.get(value.toLowerCase());\n if (mapped === undefined) {\n throw errorInitInvalidFlagValue({\n flag: 'authoring',\n value,\n allowed: ['psl', 'typescript'],\n });\n }\n return mapped;\n}\n\n/**\n * Validates `--schema-path` against the chosen `--authoring` style: PSL\n * authoring requires a `.prisma` file and TypeScript authoring requires a\n * `.ts` file. Mismatched combinations would silently scaffold PSL content\n * into a `.ts` file (or vice versa); this validator surfaces the mistake\n * as a precondition error naming both flags.\n */\nfunction validateSchemaPath(value: string, authoring: AuthoringId): string {\n const trimmed = value.trim();\n if (trimmed.length === 0) {\n throw errorInitInvalidFlagValue({\n flag: 'schema-path',\n value,\n allowed: ['<non-empty file path with .prisma or .ts extension>'],\n });\n }\n if (trimmed.endsWith('/') || trimmed.endsWith('\\\\')) {\n throw errorInitInvalidFlagValue({\n flag: 'schema-path',\n value,\n allowed: ['<file path, not a directory>'],\n });\n }\n const ext = extname(trimmed).toLowerCase();\n const expected = authoring === 'typescript' ? '.ts' : '.prisma';\n if (ext !== expected) {\n throw errorInitInvalidFlagValue({\n flag: 'schema-path',\n value,\n allowed: [`<file path ending in ${expected} for --authoring ${authoring}>`],\n });\n }\n return normalize(trimmed);\n}\n\nasync function promptTarget(): Promise<TargetId> {\n const result = await clack.select({\n message: 'What database are you using?',\n options: [\n { value: 'postgres' as TargetId, label: 'PostgreSQL' },\n { value: 'mongo' as TargetId, label: 'MongoDB' },\n ],\n output: process.stderr,\n });\n if (clack.isCancel(result)) {\n throw errorInitUserAborted();\n }\n return result as TargetId;\n}\n\nasync function promptAuthoring(): Promise<AuthoringId> {\n const result = await clack.select({\n message: 'How do you want to write your schema?',\n options: [\n { value: 'psl' as AuthoringId, label: 'Prisma Schema Language (.prisma)' },\n { value: 'typescript' as AuthoringId, label: 'TypeScript (.ts)' },\n ],\n output: process.stderr,\n });\n if (clack.isCancel(result)) {\n throw errorInitUserAborted();\n }\n return result as AuthoringId;\n}\n\nasync function promptSchemaPath(authoring: AuthoringId): Promise<string> {\n const expectedExt = authoring === 'typescript' ? '.ts' : '.prisma';\n const result = await clack.text({\n message: 'Where should the schema file go?',\n initialValue: defaultSchemaPath(authoring),\n validate(value = '') {\n const trimmed = value.trim();\n if (trimmed.length === 0) return 'Path cannot be empty';\n if (trimmed.endsWith('/') || trimmed.endsWith('\\\\'))\n return 'Path must be a file, not a directory';\n const ext = extname(trimmed).toLowerCase();\n if (ext === '') return 'Path must include a file extension (e.g. .prisma or .ts)';\n if (ext !== expectedExt) {\n return `Schema path must end in ${expectedExt} for --authoring ${authoring} (got ${ext}).`;\n }\n return undefined;\n },\n output: process.stderr,\n });\n if (clack.isCancel(result)) {\n throw errorInitUserAborted();\n }\n // Pipe through `validateSchemaPath` so the final value goes through the\n // same canonicalisation as the flag path — defence-in-depth in case\n // the inline `validate` ever drifts from the flag-mode rules.\n return validateSchemaPath(result as string, authoring);\n}\n","import { createRequire } from 'node:module';\nimport { join } from 'pathe';\nimport type { TargetId } from './templates/code-templates';\n\n/**\n * Result of an attempted database probe (FR8.3). `kind` is the\n * machine-readable status; `message` is the human-readable line we\n * surface in `init`'s warning channel (or, under `--strict-probe`, in\n * the structured error). The probe never throws — every failure\n * mode is folded into one of these variants so `runInit` can branch\n * exactly once.\n */\nexport type ProbeOutcome =\n | {\n readonly kind: 'ok';\n readonly serverVersion: string;\n readonly minVersion: string;\n readonly meetsMinimum: true;\n readonly message: string;\n }\n | {\n readonly kind: 'below-minimum';\n readonly serverVersion: string;\n readonly minVersion: string;\n readonly meetsMinimum: false;\n readonly message: string;\n }\n | {\n readonly kind: 'no-database-url';\n readonly minVersion: string;\n readonly meetsMinimum: null;\n readonly message: string;\n }\n | {\n readonly kind: 'connection-failed';\n readonly minVersion: string;\n readonly meetsMinimum: null;\n readonly cause: string;\n readonly message: string;\n }\n | {\n readonly kind: 'driver-missing';\n readonly minVersion: string;\n readonly meetsMinimum: null;\n readonly cause: string;\n readonly message: string;\n };\n\nexport interface ProbeContext {\n readonly baseDir: string;\n readonly target: TargetId;\n readonly databaseUrl: string | undefined;\n readonly minVersion: string;\n}\n\n/**\n * Optional injection seam exposed for unit tests so the probe logic\n * (env handling, version parsing, comparator, message formatting) can\n * be exercised without a live database. Production callers omit this\n * argument and get the real `pg` / `mongodb` driver path.\n */\nexport interface ProbeOverrides {\n readonly probePostgres?: (databaseUrl: string) => Promise<DriverResult>;\n readonly probeMongo?: (databaseUrl: string) => Promise<DriverResult>;\n readonly requireFromBaseDir?: (baseDir: string, moduleId: string) => unknown;\n}\n\ninterface DriverResult {\n readonly serverVersion: string;\n}\n\n/**\n * Connects (when configured) to the user's database and returns a\n * structured outcome describing whether the server meets the declared\n * minimum (FR8.1). Pure with respect to its inputs: no I/O happens\n * unless `databaseUrl` is set.\n *\n * The outcome is shaped so that `--strict-probe` can branch on the\n * `kind`/`meetsMinimum` pair without re-stringifying the message:\n *\n * - `ok` — informational; `init` continues.\n * - `below-minimum` — warning; `init` continues regardless of\n * `--strict-probe` (the spec scopes strict-probe to \"probe\n * *failures*\", and a successful probe that finds an old server is\n * not a failure).\n * - `no-database-url` / `connection-failed` / `driver-missing` —\n * warning by default, fatal under `--strict-probe`.\n */\nexport async function probeServerVersion(\n ctx: ProbeContext,\n overrides: ProbeOverrides = {},\n): Promise<ProbeOutcome> {\n const { databaseUrl, minVersion, target } = ctx;\n if (databaseUrl === undefined || databaseUrl.trim().length === 0) {\n return {\n kind: 'no-database-url',\n minVersion,\n meetsMinimum: null,\n message:\n 'Skipped --probe-db: DATABASE_URL is not set in the current shell environment. (init does not read .env for the probe; export the variable or drop --probe-db.)',\n };\n }\n\n let driverResult: DriverResult;\n try {\n if (target === 'postgres') {\n driverResult =\n overrides.probePostgres !== undefined\n ? await overrides.probePostgres(databaseUrl)\n : await defaultProbePostgres(databaseUrl, ctx.baseDir, overrides);\n } else {\n driverResult =\n overrides.probeMongo !== undefined\n ? await overrides.probeMongo(databaseUrl)\n : await defaultProbeMongo(databaseUrl, ctx.baseDir, overrides);\n }\n } catch (err) {\n if (err instanceof DriverMissingError) {\n return {\n kind: 'driver-missing',\n minVersion,\n meetsMinimum: null,\n cause: err.message,\n message: `Skipped --probe-db: ${err.message}. (Run with install enabled, or install the driver yourself, then re-run \\`prisma-next init --probe-db\\`.)`,\n };\n }\n const cause = redactDatabaseUrlSecrets(causeMessage(err));\n return {\n kind: 'connection-failed',\n minVersion,\n meetsMinimum: null,\n cause,\n message: `--probe-db could not connect: ${cause}.`,\n };\n }\n\n const meets = compareVersionPrefix(driverResult.serverVersion, minVersion);\n if (meets < 0) {\n return {\n kind: 'below-minimum',\n serverVersion: driverResult.serverVersion,\n minVersion,\n meetsMinimum: false,\n message: `--probe-db: server reports version ${driverResult.serverVersion}, below the declared minimum (${minVersion}). Some queries may fail until the server is upgraded.`,\n };\n }\n return {\n kind: 'ok',\n serverVersion: driverResult.serverVersion,\n minVersion,\n meetsMinimum: true,\n message: `--probe-db: server reports version ${driverResult.serverVersion} (>= ${minVersion}).`,\n };\n}\n\n/**\n * Compares two semver-prefix strings (\"14\", \"14.2\", \"6.0\", …) by\n * numeric components left-to-right. Returns a negative number when `a`\n * is older than `b`, zero when both versions agree on every numeric\n * component (treating missing trailing components as `0`), and a\n * positive number when `a` is newer.\n *\n * The loop runs over the **longer** of the two prefixes so that\n * `'14'` compares less than `'14.1'` — without that, the shorter\n * prefix would be silently accepted whenever the configured minimum\n * has a non-zero minor or patch.\n *\n * Exported for unit tests.\n */\nexport function compareVersionPrefix(a: string, b: string): number {\n const aParts = parseNumericParts(a);\n const bParts = parseNumericParts(b);\n const len = Math.max(aParts.length, bParts.length);\n for (let i = 0; i < len; i += 1) {\n const aPart = aParts[i] ?? 0;\n const bPart = bParts[i] ?? 0;\n if (aPart !== bPart) return aPart - bPart;\n }\n return 0;\n}\n\nfunction parseNumericParts(version: string): readonly number[] {\n const match = version.match(/^[^\\d]*(\\d+(?:\\.\\d+){0,3})/);\n if (match === null) return [];\n return (match[1] ?? '').split('.').map((part) => Number.parseInt(part, 10));\n}\n\nclass DriverMissingError extends Error {}\n\nfunction causeMessage(err: unknown): string {\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\n/**\n * Strips `user:password@` userinfo from any URL-shaped substring before\n * we surface the cause to the user. Mirrors `redactSecrets` in\n * `init.ts` — the probe path has its own redactor because the inputs\n * here include the raw connection string by construction (driver\n * errors echo the URL back).\n *\n * Exported for unit tests.\n */\nexport function redactDatabaseUrlSecrets(text: string): string {\n if (!text) return text;\n return text.replace(/([a-zA-Z][a-zA-Z0-9+.-]*:\\/\\/)([^/@\\s]+)@/g, '$1***@');\n}\n\nasync function defaultProbePostgres(\n databaseUrl: string,\n baseDir: string,\n overrides: ProbeOverrides,\n): Promise<DriverResult> {\n const pg = requirePeer<{ Client: new (cfg: { connectionString: string }) => PgClient }>(\n 'pg',\n baseDir,\n overrides,\n );\n const client = new pg.Client({ connectionString: databaseUrl });\n await client.connect();\n try {\n const result = await client.query('SELECT version() as version');\n const versionString = String(result?.rows?.[0]?.version ?? '');\n const parsed = parsePostgresVersion(versionString);\n return { serverVersion: parsed };\n } finally {\n await client.end().catch(() => undefined);\n }\n}\n\ninterface PgClient {\n connect(): Promise<void>;\n query(sql: string): Promise<{ rows: ReadonlyArray<{ version: string }> }>;\n end(): Promise<void>;\n}\n\n/**\n * Extracts the numeric prefix from a Postgres `version()` row, e.g.\n *\n * `PostgreSQL 14.10 on x86_64-pc-linux-gnu, ...` → `\"14.10\"`\n * `PostgreSQL 16beta1 on …` → `\"16\"` (we\n * conservatively drop the suffix; minimum-version comparisons\n * treat 16beta1 as 16, which is what every reasonable user\n * expects).\n *\n * Exported for unit tests.\n */\nexport function parsePostgresVersion(versionString: string): string {\n const match = versionString.match(/PostgreSQL\\s+(\\d+(?:\\.\\d+)?)/i);\n if (match === null || match[1] === undefined) {\n throw new Error(`Could not parse PostgreSQL version from \\`${versionString}\\``);\n }\n return match[1];\n}\n\nasync function defaultProbeMongo(\n databaseUrl: string,\n baseDir: string,\n overrides: ProbeOverrides,\n): Promise<DriverResult> {\n const mongodb = requirePeer<{\n MongoClient: new (\n url: string,\n ) => {\n connect(): Promise<unknown>;\n db(name?: string): {\n admin(): { command(cmd: Record<string, unknown>): Promise<{ version?: string }> };\n };\n close(): Promise<void>;\n };\n }>('mongodb', baseDir, overrides);\n const client = new mongodb.MongoClient(databaseUrl);\n await client.connect();\n try {\n const buildInfo = await client.db().admin().command({ buildInfo: 1 });\n const versionString = String(buildInfo.version ?? '');\n if (versionString.length === 0) {\n throw new Error('buildInfo did not include a `version` field');\n }\n return { serverVersion: versionString };\n } finally {\n await client.close().catch(() => undefined);\n }\n}\n\n/**\n * Loads a peer driver (`pg` / `mongodb`) from the user's project\n * `node_modules`. We deliberately resolve from `baseDir` rather than\n * from the CLI bundle — the CLI does not depend on `pg` or `mongodb`\n * directly, but the user's `init`-generated `package.json` does (via\n * the target facade). Failure to resolve is folded into a typed\n * `DriverMissingError` so `probeServerVersion` can map it to a\n * `driver-missing` outcome rather than letting a `MODULE_NOT_FOUND`\n * leak as a generic connection failure.\n */\nfunction requirePeer<T>(moduleId: string, baseDir: string, overrides: ProbeOverrides): T {\n try {\n if (overrides.requireFromBaseDir !== undefined) {\n return overrides.requireFromBaseDir(baseDir, moduleId) as T;\n }\n const requireFromBase = createRequire(join(baseDir, 'package.json'));\n return requireFromBase(moduleId) as T;\n } catch (err) {\n throw new DriverMissingError(\n `\\`${moduleId}\\` is not installed in this project (resolved from ${baseDir}; cause: ${causeMessage(err)})`,\n );\n }\n}\n","import { existsSync } from 'node:fs';\nimport { join } from 'pathe';\n\n/**\n * Filenames the contract pipeline emits next to the user's schema source\n * (`<schemaDir>/contract.json`, `<schemaDir>/contract.d.ts`, …). Mirrors\n * `ARTEFACT_FILENAMES` in `hygiene-gitattributes.ts`; kept as a separate\n * constant here because the cleanup contract is target-agnostic and we\n * deliberately do not want a stale `start-contract.json` from a previous\n * target lingering after a re-init.\n *\n * If a future emit pipeline produces an additional artefact, add it here\n * **and** to the gitattributes list — the two stay in lockstep so the\n * file `init` advertises as `linguist-generated` is exactly the file\n * `init` is willing to delete on re-init.\n */\nconst ARTEFACT_FILENAMES: readonly string[] = [\n 'contract.json',\n 'contract.d.ts',\n 'end-contract.json',\n 'end-contract.d.ts',\n 'start-contract.json',\n 'start-contract.d.ts',\n 'ops.json',\n 'migration.json',\n];\n\n/**\n * Returns the schema-relative paths of stale contract artefacts the\n * previous `init` run (or a `contract emit`) left behind in `schemaDir`.\n * Paths are returned relative to `baseDir` so the caller can plumb them\n * into `filesWritten`-style logging without re-deriving the path.\n *\n * Pure function: no filesystem mutation. Used by `runInit`'s precondition\n * phase (FR6.2 / NFR3 atomicity) so a downstream parse failure leaves\n * the artefacts on disk and the project byte-identical to its pre-init\n * state.\n */\nexport function findStaleArtefacts(baseDir: string, schemaDir: string): readonly string[] {\n const result: string[] = [];\n for (const filename of ARTEFACT_FILENAMES) {\n const rel = join(schemaDir, filename);\n if (existsSync(join(baseDir, rel))) {\n result.push(rel);\n }\n }\n return result;\n}\n\n/**\n * Drops a single key from `package.json#dependencies`, returning the new\n * file content. Returns `null` when the dependency was already absent —\n * the caller can skip the write to keep re-init idempotent (FR9.3).\n *\n * Used by `runInit` for the FR9.2 target-switch path: when the user\n * re-inits a project from `--target postgres` to `--target mongodb` (or\n * vice versa), the previous facade is removed from `dependencies` so the\n * resulting project depends only on the chosen target's facade.\n *\n * Devs/peers/optional dep groups are intentionally *not* touched — the\n * facades are only ever in `dependencies` (FR4 / FR7), and broadening\n * the search would risk clobbering an unrelated dep with the same name\n * in `peerDependencies`.\n *\n * Throws `SyntaxError` if `existing` is not parseable as JSON; the\n * caller (`runInit`) already guards on that with a structured 5010\n * error before this helper is reached.\n */\nexport function removeDependency(existing: string, depName: string): string | null {\n const parsed = JSON.parse(existing) as Record<string, unknown>;\n const deps = parsed['dependencies'];\n if (deps === null || typeof deps !== 'object' || Array.isArray(deps)) {\n return null;\n }\n if (!Object.hasOwn(deps as Record<string, unknown>, depName)) {\n return null;\n }\n const next = { ...(deps as Record<string, unknown>) };\n delete next[depName];\n parsed['dependencies'] = next;\n const trailingNewline = existing.endsWith('\\n') ? '\\n' : '';\n return `${JSON.stringify(parsed, null, 2)}${trailingNewline}`;\n}\n","import { readFileSync } from 'node:fs';\nimport { join } from 'pathe';\n\nexport function renderTemplate(\n templateFile: string,\n variableNames: readonly string[],\n vars: Record<string, string>,\n): string {\n const templatePath = join(import.meta.dirname, templateFile);\n const raw = readFileSync(templatePath, 'utf-8');\n let result = raw;\n for (const key of variableNames) {\n const value = vars[key];\n if (value === undefined) {\n throw new Error(`Template variable '${key}' is not defined`);\n }\n result = result.replaceAll(`{{${key}}}`, value);\n }\n return result;\n}\n","import { dirname } from 'pathe';\nimport type { AuthoringId, TargetId } from './code-templates';\nimport { renderTemplate } from './render';\n\nexport const variables = [\n 'schemaPath',\n 'schemaDir',\n 'dbImportPath',\n 'pkgRun',\n 'authoringLabel',\n] as const;\n\ntype TemplateVars = Record<(typeof variables)[number], string>;\n\n/**\n * Renders the per-project agent skill (FR5.2). The skill template is\n * target-specific (Postgres vs Mongo query syntax differs); the authoring\n * style enters via:\n *\n * - `schemaPath` — already routed through {@link agentSkillMd}'s caller\n * (the AC says a TS-authoring scaffold must reference `prisma/contract.ts`).\n * - `authoringLabel` — a short human-readable note (`PSL` / `TypeScript`)\n * the skill template uses when describing the contract file.\n */\nexport function agentSkillMd(\n target: TargetId,\n authoring: AuthoringId,\n schemaPath: string,\n pkgRun: string,\n): string {\n const schemaDir = dirname(schemaPath);\n const vars: TemplateVars = {\n schemaPath,\n schemaDir,\n dbImportPath: `./${schemaDir}/db`,\n pkgRun,\n authoringLabel: authoring === 'typescript' ? 'TypeScript' : 'PSL',\n };\n const templateFile = `agent-skill-${target}.md`;\n return renderTemplate(templateFile, variables, vars);\n}\n","import type { TargetId } from './code-templates';\n\n/**\n * The minimum supported server version for each target (FR8.1). The\n * authoritative source of truth is each target package's\n * `package.json#prismaNext.minServerVersion` field — this module\n * mirrors those values and a workspace-level test asserts the two\n * never drift (`templates/tsconfig-env.test.ts`).\n *\n * Bumping a value here in isolation is **not** safe: edit the\n * corresponding target package's `package.json` first, then mirror\n * here. The scaffold's `.env.example` (FR3.1, FR8.2) and the\n * \"Requirements\" section of `prisma-next.md` both read from this\n * constant, so a stale value lies to every freshly initialised user.\n */\nexport const MIN_SERVER_VERSION: Record<TargetId, string> = {\n postgres: '14',\n mongo: '6.0',\n};\n\nexport const TARGET_LABEL: Record<TargetId, string> = {\n postgres: 'PostgreSQL',\n mongo: 'MongoDB',\n};\n\n/**\n * Renders the placeholder body shared by `.env` and `.env.example`:\n * the target-specific connection-string requirement comments and the\n * commented-shape `DATABASE_URL` line. The output is identical for both\n * authoring styles — the env file is orthogonal to PSL vs TS schema\n * authoring.\n */\nfunction envPlaceholderBody(target: TargetId): string {\n const label = TARGET_LABEL[target];\n const minVersion = MIN_SERVER_VERSION[target];\n const lines: string[] = [];\n lines.push(`# Connection string for ${label}.`);\n lines.push(`# Requires ${label} >= ${minVersion}.`);\n lines.push('');\n if (target === 'postgres') {\n lines.push('DATABASE_URL=\"postgresql://user:password@localhost:5432/mydb\"');\n } else {\n lines.push('DATABASE_URL=\"mongodb://localhost:27017/mydb\"');\n }\n lines.push('');\n return lines.join('\\n');\n}\n\n/**\n * Renders the `.env.example` content for a given target (FR3.1):\n *\n * - Carries a \"Copy this file to `.env`…\" intro that only makes sense\n * for the example file (the real `.env` is the destination of that\n * copy and so does not get the same intro).\n * - Documents the `DATABASE_URL` placeholder in the target's native URL\n * shape (Postgres: standard `postgresql://`, Mongo: `mongodb://` plus\n * a `mydb` database segment so the lazy facade has a `dbName`).\n * - Carries a `# Requires <db> >= <version>` comment so a fresh user\n * knows the minimum supported server before they first try to\n * connect (FR8.2).\n */\nexport function envExampleContent(target: TargetId): string {\n const lines: string[] = [];\n lines.push(\n '# Copy this file to `.env` and replace the placeholder with your real connection string.',\n );\n lines.push(envPlaceholderBody(target));\n return lines.join('\\n');\n}\n\n/**\n * Renders the initial `.env` content for `--write-env` / interactive\n * opt-in (FR3.2). Same placeholder body as `.env.example`, **without**\n * the example file's \"Copy this file to `.env`…\" intro: the real `.env`\n * is the destination of that copy, so the line would lie. Writing this\n * file is gitignored (FR3.3 ensures `.env` lands in `.gitignore`).\n */\nexport function envFileContent(target: TargetId): string {\n return envPlaceholderBody(target);\n}\n","import { dirname } from 'pathe';\nimport { type AuthoringId, schemaSample, type TargetId } from './code-templates';\nimport { MIN_SERVER_VERSION, TARGET_LABEL } from './env';\nimport { renderTemplate } from './render';\n\nexport const variables = [\n 'schemaPath',\n 'schemaDir',\n 'dbImportPath',\n 'pkgRun',\n 'schemaSample',\n 'requirements',\n] as const;\n\ntype TemplateVars = Record<(typeof variables)[number], string>;\n\nexport function quickReferenceMd(\n target: TargetId,\n authoring: AuthoringId,\n schemaPath: string,\n pkgRun: string,\n): string {\n const schemaDir = dirname(schemaPath);\n const vars: TemplateVars = {\n schemaPath,\n schemaDir,\n dbImportPath: `./${schemaDir}/db`,\n pkgRun,\n schemaSample: schemaSample(target, authoring),\n requirements: requirementsBlock(target),\n };\n const templateFile = `quick-reference-${target}.md`;\n return renderTemplate(templateFile, variables, vars);\n}\n\n/**\n * Renders the FR8.2 \"Requirements\" block injected into `prisma-next.md`\n * (the user-facing quick reference). Sources the minimum server\n * version from `MIN_SERVER_VERSION` — itself mirrored from each\n * target package's `package.json#prismaNext.minServerVersion`\n * (FR8.1).\n *\n * The verification command is target-specific — Postgres scaffolds\n * shouldn't ship Mongo's `db.runCommand` (and vice versa) just because\n * we couldn't be bothered to branch.\n */\nfunction requirementsBlock(target: TargetId): string {\n const label = TARGET_LABEL[target];\n const minVersion = MIN_SERVER_VERSION[target];\n const verifyCommand =\n target === 'postgres' ? '`SELECT version()`' : '`db.runCommand({ buildInfo: 1 })`';\n return [\n '## Requirements',\n '',\n `- **${label} ${minVersion} or newer.** Older servers are not supported. Run ${verifyCommand} against your server to verify.`,\n '- The CLI never connects to your database without explicit consent. Pass `--probe-db` to `prisma-next init` if you want `init` to verify the server version itself.',\n ].join('\\n');\n}\n","import {\n applyEdits,\n modify,\n type ParseError,\n parse as parseJsonc,\n printParseErrorCode,\n} from 'jsonc-parser';\n\n/**\n * Compiler options the scaffolded `prisma-next.config.ts` and `db.ts` need\n * to typecheck:\n *\n * - `module: 'preserve'` + `moduleResolution: 'bundler'` align with how\n * modern bundlers (and `tsdown`) consume our facade packages.\n * - `resolveJsonModule` lets `db.ts` import `contract.json with { type:\n * 'json' }` — the runtime path the facades document (FR4).\n *\n * `types: ['node']` is FR2.2 territory and lives in\n * `REQUIRED_COMPILER_OPTIONS_TYPES` because TS only honours an _array_\n * here, and a string-keyed merge would clobber any user-specified entries.\n * Merge handling preserves any extra `types` the user added.\n */\nexport const REQUIRED_COMPILER_OPTIONS: Record<string, string | boolean> = {\n module: 'preserve',\n moduleResolution: 'bundler',\n resolveJsonModule: true,\n};\n\n/**\n * Types that must be present in `compilerOptions.types` for the scaffold\n * to typecheck. With `moduleResolution: 'bundler'`, TypeScript does not\n * implicitly include all `@types/*` packages — `process.env` only resolves\n * when `node` is in this array (or `types` is omitted, but then any other\n * type listed here would force the same behaviour). Listing `node`\n * explicitly is the documented escape hatch (FR2.2).\n */\nexport const REQUIRED_COMPILER_OPTIONS_TYPES: readonly string[] = ['node'];\n\nexport function defaultTsConfig(): string {\n return JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n ...REQUIRED_COMPILER_OPTIONS,\n types: [...REQUIRED_COMPILER_OPTIONS_TYPES],\n strict: true,\n skipLibCheck: true,\n esModuleInterop: true,\n outDir: 'dist',\n },\n include: ['**/*.ts'],\n },\n null,\n 2,\n );\n}\n\n/**\n * Thrown by `mergeTsConfig` when the user's existing `tsconfig.json` is\n * not parseable as JSONC (TypeScript's actual configured dialect — see\n * FR6.1). Carries the raw parse errors so the caller can render an\n * actionable, location-aware message.\n *\n * `runInit` catches this exception during the precondition phase and\n * maps it to a `CliStructuredError(5011)` so the user's working tree\n * stays byte-identical when init bails (FR6.2 / NFR3).\n */\nexport class TsConfigParseError extends Error {\n readonly errors: readonly ParseError[];\n\n constructor(errors: readonly ParseError[]) {\n super(formatTsConfigParseErrors(errors));\n this.errors = errors;\n this.name = 'TsConfigParseError';\n }\n}\n\nfunction formatTsConfigParseErrors(errors: readonly ParseError[]): string {\n if (errors.length === 0) {\n return 'tsconfig.json is empty or not an object';\n }\n return errors.map((e) => `${printParseErrorCode(e.error)} at offset ${e.offset}`).join('; ');\n}\n\n/**\n * Merges the required compiler options into an existing `tsconfig.json`.\n *\n * Parsing is delegated to `jsonc-parser` so JSONC inputs (comments,\n * trailing commas) — TypeScript's real configuration dialect — survive\n * unchanged: edits are applied as text patches via `modify` /\n * `applyEdits`, preserving the user's formatting, key ordering, and\n * comments wherever the touched paths permit (FR6.1, AC \"Hostile\n * inputs\").\n *\n * Throws `TsConfigParseError` when the input is not parseable as JSONC.\n * The caller must catch this and surface a structured error before\n * writing any scaffold files (FR6.2 atomicity).\n */\nexport function mergeTsConfig(existing: string): string {\n const { config } = parseTsConfigText(existing);\n\n // Match the indentation / line-ending style of the existing file so\n // the merged output diffs cleanly against it. `jsonc-parser` uses\n // these only when it has to insert a brand-new object node;\n // existing-key edits replace the value in place.\n const formattingOptions = {\n tabSize: detectIndent(existing),\n insertSpaces: true,\n eol: existing.includes('\\r\\n') ? '\\r\\n' : '\\n',\n };\n\n let result = existing;\n for (const [key, value] of Object.entries(REQUIRED_COMPILER_OPTIONS)) {\n const edits = modify(result, ['compilerOptions', key], value, { formattingOptions });\n result = applyEdits(result, edits);\n }\n\n const existingTypes = (config['compilerOptions'] as Record<string, unknown> | undefined)?.[\n 'types'\n ];\n const mergedTypes = mergeTypesArray(existingTypes);\n const typesEdits = modify(result, ['compilerOptions', 'types'], mergedTypes, {\n formattingOptions,\n });\n result = applyEdits(result, typesEdits);\n\n return result;\n}\n\n/**\n * Parses an existing `tsconfig.json` (JSONC) and returns the structured\n * config alongside any non-fatal parse warnings. Throws\n * `TsConfigParseError` if the input cannot be parsed at all or does\n * not resolve to a JSON object — both cases mean we cannot safely\n * apply edits.\n *\n * Exposed independently so callers (notably `runInit`'s precondition\n * gate) can validate the file *before* any scaffold file is written.\n */\nexport function parseTsConfigText(text: string): {\n readonly config: Record<string, unknown>;\n} {\n const errors: ParseError[] = [];\n const value = parseJsonc(text, errors, {\n allowTrailingComma: true,\n disallowComments: false,\n allowEmptyContent: false,\n });\n\n if (value === undefined || value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new TsConfigParseError(errors);\n }\n if (errors.length > 0) {\n throw new TsConfigParseError(errors);\n }\n return { config: value as Record<string, unknown> };\n}\n\nfunction detectIndent(text: string): number {\n // Look at the first indented line. A 2-space indent (the TS default)\n // is by far the most common; we fall back to 2 when nothing useful\n // is detectable (e.g. a single-line tsconfig).\n const match = text.match(/^([ \\t]+)\\S/m);\n if (match === null) {\n return 2;\n }\n const indent = match[1] ?? '';\n if (indent.startsWith('\\t')) {\n return 1;\n }\n return indent.length || 2;\n}\n\n/**\n * Merges `REQUIRED_COMPILER_OPTIONS_TYPES` into the user's existing\n * `compilerOptions.types` array. Preserves order and dedupes. If the\n * user has no `types` array (or has set it to a non-array), we replace\n * with the required minimum — overwriting a non-array `types` is the\n * correct fix because anything other than a string array is invalid TS\n * config.\n */\nfunction mergeTypesArray(existing: unknown): readonly string[] {\n const result: string[] = [];\n if (Array.isArray(existing)) {\n for (const item of existing) {\n if (typeof item === 'string' && !result.includes(item)) {\n result.push(item);\n }\n }\n }\n for (const required of REQUIRED_COMPILER_OPTIONS_TYPES) {\n if (!result.includes(required)) {\n result.push(required);\n }\n }\n return result;\n}\n","import { execFile } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { promisify } from 'node:util';\nimport * as clack from '@clack/prompts';\nimport { dirname, isAbsolute, join } from 'pathe';\nimport { CliStructuredError } from '../../utils/cli-errors';\nimport { formatErrorJson, formatErrorOutput } from '../../utils/formatters/errors';\nimport type { GlobalFlags } from '../../utils/global-flags';\nimport { TerminalUI } from '../../utils/terminal-ui';\nimport {\n detectPackageManager,\n formatAddArgs,\n formatAddDevArgs,\n formatRunCommand,\n hasProjectManifest,\n type PackageManager,\n} from './detect-package-manager';\nimport { detectPnpmCatalogOverrides, type PnpmCatalogOverride } from './detect-pnpm-catalog';\nimport {\n errorInitEmitFailed,\n errorInitInstallFailed,\n errorInitInvalidManifest,\n errorInitInvalidTsconfig,\n errorInitMissingManifest,\n errorInitProbeFailed,\n} from './errors';\nimport {\n INIT_EXIT_EMIT_FAILED,\n INIT_EXIT_INSTALL_FAILED,\n INIT_EXIT_INTERNAL_ERROR,\n INIT_EXIT_OK,\n INIT_EXIT_PRECONDITION,\n INIT_EXIT_USER_ABORTED,\n} from './exit-codes';\nimport { mergeGitattributes, requiredGitattributesLines } from './hygiene-gitattributes';\nimport { mergeGitignore } from './hygiene-gitignore';\nimport { mergePackageScripts, REQUIRED_SCRIPTS } from './hygiene-package-scripts';\nimport { type InitFlagOptions, type ResolvedInitInputs, resolveInitInputs } from './inputs';\nimport {\n buildNextSteps,\n formatInitJson,\n type InitOutput,\n InitOutputSchema,\n renderInitOutro,\n} from './output';\nimport { type ProbeOutcome, type ProbeOverrides, probeServerVersion } from './probe-db';\nimport { findStaleArtefacts, removeDependency } from './reinit-cleanup';\nimport { agentSkillMd } from './templates/agent-skill';\nimport { configFile, dbFile, starterSchema, targetPackageName } from './templates/code-templates';\nimport { envExampleContent, envFileContent, MIN_SERVER_VERSION } from './templates/env';\nimport { quickReferenceMd } from './templates/quick-reference';\nimport { defaultTsConfig, mergeTsConfig, TsConfigParseError } from './templates/tsconfig';\n\ninterface FileEntry {\n readonly path: string;\n readonly content: string;\n /**\n * Optional human-mode message printed *after* the file is written —\n * matches the legacy `Updated tsconfig.json with required compiler\n * options.` line emitted when an existing tsconfig is merged. Kept\n * with the entry so the precondition phase decides what to say and\n * the write phase remains a dumb loop (FR6.2 atomicity).\n */\n readonly logMessage?: string;\n}\n\ninterface InstallReport {\n readonly skipped: boolean;\n readonly deps: readonly string[];\n readonly devDeps: readonly string[];\n readonly warnings: readonly string[];\n}\n\n/**\n * Runs the `init` command end-to-end and returns the exit code. Catches\n * structured CLI errors raised at every phase (input resolution, install,\n * emit) and renders them via the same UI surface as success output\n * (`--json` to stdout, human to stderr). Exit codes follow the documented\n * stable set in `./exit-codes.ts` (FR1.6) and the\n * [Style Guide § Exit Codes](../../../../../../../docs/CLI%20Style%20Guide.md#exit-codes).\n *\n * Layered for testability: the action handler in `./index.ts` is\n * responsible for parsing flags and constructing `runOptions`; this\n * function does no flag parsing of its own.\n */\nexport async function runInit(\n baseDir: string,\n runOptions: {\n readonly options: InitFlagOptions;\n readonly flags: GlobalFlags;\n /**\n * Whether `init` may render an interactive prompt. Decoupled from\n * `flags.interactive` (which gates `TerminalUI` decoration / stdout\n * mode) — see [Style Guide § Interactivity](../../../../../../../docs/CLI%20Style%20Guide.md#interactivity).\n */\n readonly canPrompt: boolean;\n /**\n * FR8.3 — test-only seam for the optional database version probe.\n * Production callers omit this; tests inject stub `probePostgres` /\n * `probeMongo` functions so the probe contract (env handling,\n * comparator, message formatting, `--strict-probe` escalation) can\n * be exercised without a live database. Never read at runtime by a\n * user invocation of the CLI.\n */\n readonly probeOverrides?: ProbeOverrides;\n },\n): Promise<number> {\n const { options, flags, canPrompt, probeOverrides } = runOptions;\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const warnings: string[] = [];\n const filesWritten: string[] = [];\n const filesDeleted: string[] = [];\n\n if (!flags.json && !flags.quiet) {\n clack.intro('prisma-next init', { output: process.stderr });\n }\n\n if (!hasProjectManifest(baseDir)) {\n return emitError(ui, flags, errorInitMissingManifest());\n }\n\n let inputs: ResolvedInitInputs;\n try {\n inputs = await resolveInitInputs({ baseDir, options, flags, canPrompt });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return emitError(ui, flags, error);\n }\n throw error;\n }\n\n const pm = await detectPackageManager(baseDir);\n const pkgRun = formatRunCommand(pm, 'prisma-next', '').trimEnd();\n\n const schemaDir = dirname(inputs.schemaPath);\n const configContractPath = isAbsolute(inputs.schemaPath)\n ? inputs.schemaPath\n : `./${inputs.schemaPath}`;\n\n // -----------------------------------------------------------------\n // Precondition phase (FR6.2 / NFR3 atomicity)\n //\n // Read every file we may need to merge with, parse it, compute the\n // merged content, and accumulate the full set of writes — *before*\n // touching the filesystem. A failure here (malformed package.json,\n // unparseable tsconfig.json, …) returns a structured error and the\n // user's project on disk stays byte-identical to its pre-init state.\n // -----------------------------------------------------------------\n const filesToWrite: FileEntry[] = [\n { path: inputs.schemaPath, content: starterSchema(inputs.target, inputs.authoring) },\n {\n path: 'prisma-next.config.ts',\n content: configFile(inputs.target, configContractPath),\n },\n { path: join(schemaDir, 'db.ts'), content: dbFile(inputs.target) },\n {\n path: 'prisma-next.md',\n content: quickReferenceMd(inputs.target, inputs.authoring, inputs.schemaPath, pkgRun),\n },\n {\n path: '.agents/skills/prisma-next/SKILL.md',\n content: agentSkillMd(inputs.target, inputs.authoring, inputs.schemaPath, pkgRun),\n },\n { path: '.env.example', content: envExampleContent(inputs.target) },\n ];\n\n // FR9.1 — on re-init, queue the previously-emitted contract artefacts\n // for deletion so a target switch (or schema-shape change) does not\n // leave a stale `contract.json` / `contract.d.ts` next to the new\n // schema source. Detection is filesystem-only (no parsing of the\n // previous config) so the cleanup is safe to run before the write\n // phase: each path is checked for existence in the precondition,\n // and missing-on-disk-at-write-time is tolerated.\n const filesToDelete: string[] = inputs.reinit ? [...findStaleArtefacts(baseDir, schemaDir)] : [];\n\n // FR3.2: a real `.env` is only written when the user opted in. Never\n // overwrite an existing `.env` — secrets live there and clobbering\n // them is the most damaging possible side-effect of `init`.\n if (inputs.writeEnv) {\n if (!existsSync(join(baseDir, '.env'))) {\n filesToWrite.push({ path: '.env', content: envFileContent(inputs.target) });\n } else {\n warnings.push(\n '.env already exists; leaving it untouched. Compare with .env.example for any new keys.',\n );\n }\n }\n\n // FR2.2 / FR6.1: tsconfig.json gets the minimum compiler options the\n // scaffolded files need. JSONC (TS's actual configured dialect) is\n // accepted; an unparseable file is mapped to a structured\n // precondition error (5011) rather than crashing mid-write.\n const tsconfigPath = join(baseDir, 'tsconfig.json');\n if (existsSync(tsconfigPath)) {\n const existing = readFileSync(tsconfigPath, 'utf-8');\n let merged: string;\n try {\n merged = mergeTsConfig(existing);\n } catch (err) {\n if (err instanceof TsConfigParseError) {\n return emitError(\n ui,\n flags,\n errorInitInvalidTsconfig({ path: 'tsconfig.json', cause: err.message }),\n );\n }\n throw err;\n }\n filesToWrite.push({\n path: 'tsconfig.json',\n content: merged,\n logMessage: 'Updated tsconfig.json with required compiler options.',\n });\n } else {\n filesToWrite.push({ path: 'tsconfig.json', content: defaultTsConfig() });\n }\n\n // FR3.3: idempotent .gitignore — append only what's missing.\n const gitignorePath = join(baseDir, '.gitignore');\n const existingGitignore = existsSync(gitignorePath)\n ? readFileSync(gitignorePath, 'utf-8')\n : undefined;\n const newGitignore = mergeGitignore(existingGitignore);\n if (newGitignore !== null) {\n filesToWrite.push({ path: '.gitignore', content: newGitignore });\n }\n\n // FR3.4: idempotent .gitattributes — linguist-generated entries for\n // the emitted artefacts so GitHub diff stats / code review collapse\n // them by default.\n const gitattributesPath = join(baseDir, '.gitattributes');\n const existingGitattributes = existsSync(gitattributesPath)\n ? readFileSync(gitattributesPath, 'utf-8')\n : undefined;\n const newGitattributes = mergeGitattributes(\n existingGitattributes,\n requiredGitattributesLines(schemaDir, inputs.target),\n );\n if (newGitattributes !== null) {\n filesToWrite.push({ path: '.gitattributes', content: newGitattributes });\n }\n\n // Read + parse package.json once for both the FR3.5 scripts merge and\n // the FR2.1 `@types/node`-presence check. A malformed manifest is\n // mapped to a structured precondition error (5010) rather than the\n // generic INTERNAL_ERROR fallback so CI/agents can branch on it.\n const packageJsonPath = join(baseDir, 'package.json');\n let parsedPackageJson: Record<string, unknown> | null = null;\n if (existsSync(packageJsonPath)) {\n const pkgRaw = readFileSync(packageJsonPath, 'utf-8');\n try {\n parsedPackageJson = JSON.parse(pkgRaw) as Record<string, unknown>;\n } catch (err) {\n if (err instanceof SyntaxError) {\n return emitError(\n ui,\n flags,\n errorInitInvalidManifest({ path: 'package.json', cause: err.message }),\n );\n }\n throw err;\n }\n\n // package.json edits are chained: FR9.2 facade-dep removal first\n // (so the script merge sees the cleaned `dependencies` and rounds\n // out a single re-stringification), then FR3.5 / FR9.3 idempotent\n // scripts merge with collision detection.\n let workingPkg = pkgRaw;\n let pkgChanged = false;\n if (inputs.removePreviousFacade !== null) {\n const next = removeDependency(workingPkg, inputs.removePreviousFacade);\n if (next !== null) {\n workingPkg = next;\n pkgChanged = true;\n }\n }\n const { content: nextPkg, warnings: scriptWarnings } = mergePackageScripts(\n workingPkg,\n REQUIRED_SCRIPTS,\n );\n if (nextPkg !== null) {\n workingPkg = nextPkg;\n pkgChanged = true;\n }\n if (pkgChanged) {\n filesToWrite.push({ path: 'package.json', content: workingPkg });\n }\n warnings.push(...scriptWarnings);\n }\n\n // -----------------------------------------------------------------\n // Write phase — every input has been parsed and every merged file is\n // staged. From here on, failures are only possible at the\n // install/emit stages, which the spec treats as discrete subsequent\n // phases (FR6.3): scaffold files remain on disk so the user can fix\n // and retry.\n // -----------------------------------------------------------------\n for (const file of filesToWrite) {\n const fullPath = join(baseDir, file.path);\n mkdirSync(dirname(fullPath), { recursive: true });\n writeFileSync(fullPath, file.content, 'utf-8');\n filesWritten.push(file.path);\n if (file.logMessage !== undefined && !flags.json && !flags.quiet) {\n ui.log(file.logMessage);\n }\n }\n\n // FR9.1 — delete stale artefacts after the new templates are written.\n // Order is intentional: the names do not collide with `filesToWrite`\n // (we never write `contract.json` from this command — that's `contract\n // emit`'s job), so deletion *after* the writes guarantees we never\n // remove a file we just produced. `existsSync` was checked in the\n // precondition phase, but a concurrent `git checkout` could have\n // already removed the file — `unlinkSync` would then throw ENOENT,\n // which we tolerate as the user-visible end state we wanted anyway.\n for (const rel of filesToDelete) {\n const fullPath = join(baseDir, rel);\n if (!existsSync(fullPath)) {\n continue;\n }\n try {\n unlinkSync(fullPath);\n filesDeleted.push(rel);\n } catch (err) {\n if (!(err instanceof Error && 'code' in err && (err as { code: string }).code === 'ENOENT')) {\n throw err;\n }\n }\n }\n\n const emitCommand = formatRunCommand(pm, 'prisma-next', 'contract emit');\n\n let install: InstallReport;\n try {\n install = await runInstall({\n baseDir,\n pm,\n target: inputs.target,\n install: inputs.install,\n flags,\n ui,\n filesWritten,\n hasTypesNode:\n parsedPackageJson !== null ? hasDirectDep(parsedPackageJson, '@types/node') : false,\n });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return emitError(ui, flags, error);\n }\n throw error;\n }\n warnings.push(...install.warnings);\n\n let contractEmitted = false;\n if (!install.skipped) {\n try {\n await runEmit({ baseDir, ui, filesWritten, emitCommand });\n contractEmitted = true;\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return emitError(ui, flags, error);\n }\n throw error;\n }\n }\n\n // FR8.3 — optional database version probe. Strictly opt-in: we never\n // open a network connection to the user's database without\n // `--probe-db`. The probe runs after install + emit so the target\n // driver (`pg` / `mongodb`) is guaranteed present in node_modules\n // for the CJS `createRequire` resolution.\n if (inputs.probeDb) {\n const outcome = await probeServerVersion(\n {\n baseDir,\n target: inputs.target,\n databaseUrl: process.env['DATABASE_URL'],\n minVersion: MIN_SERVER_VERSION[inputs.target],\n },\n probeOverrides ?? {},\n );\n const escalated = applyProbeOutcome(outcome, {\n strictProbe: inputs.strictProbe,\n warnings,\n });\n if (escalated !== null) {\n return emitError(ui, flags, errorInitProbeFailed({ cause: escalated, filesWritten }));\n }\n }\n\n const output: InitOutput = {\n ok: true,\n target: inputs.target === 'mongo' ? 'mongodb' : 'postgres',\n authoring: inputs.authoring,\n schemaPath: inputs.schemaPath,\n filesWritten,\n filesDeleted,\n packagesInstalled: {\n skipped: install.skipped,\n deps: [...install.deps],\n devDeps: [...install.devDeps],\n },\n contractEmitted,\n nextSteps: buildNextSteps({\n target: inputs.target === 'mongo' ? 'mongodb' : 'postgres',\n contractEmitted,\n emitCommand,\n schemaPath: inputs.schemaPath,\n }),\n warnings,\n };\n\n // Validate the success document at the boundary so a regression in any\n // upstream branch (templates, schema, install report) shows up as a\n // typed runtime failure here instead of an opaque consumer-side parse\n // error. The schema is also exported on the package surface for\n // downstream consumers.\n const validated = InitOutputSchema(output);\n if (validated instanceof Error || (validated as { problems?: unknown }).problems !== undefined) {\n // Route through `emitError` rather than throwing: the bare throw\n // bypassed `--json` envelope formatting and `exitCodeForError`, so a\n // 5009 regression would surface as an uncaught exception in\n // commander instead of the documented `INTERNAL_ERROR` envelope on\n // the right channel.\n return emitError(\n ui,\n flags,\n new CliStructuredError('5009', 'Init produced an invalid output document', {\n domain: 'CLI',\n why: `The success document failed schema validation: ${String(validated)}`,\n fix: 'This is a bug in prisma-next. Please report it with the full `-v` output.',\n docsUrl: 'https://prisma-next.dev/docs/cli/init',\n }),\n );\n }\n\n if (flags.json) {\n ui.output(formatInitJson(output));\n } else {\n renderInitOutro(ui, output, flags);\n if (!flags.quiet) {\n clack.outro('Done. Open prisma-next.md to get started.', { output: process.stderr });\n }\n }\n\n return INIT_EXIT_OK;\n}\n\n/**\n * Renders a structured CLI error to the right channel and returns the exit\n * code derived from the error's PN code. JSON-mode errors go to stdout\n * (so consumers always parse from one place); human-mode errors go to\n * stderr. Mirrors `handleResult` but returns init-specific exit codes\n * rather than the CLI/RUN binary.\n */\nfunction emitError(ui: TerminalUI, flags: GlobalFlags, error: CliStructuredError): number {\n const envelope = error.toEnvelope();\n if (flags.json) {\n ui.output(formatErrorJson(envelope));\n } else {\n ui.error(formatErrorOutput(envelope, flags));\n }\n return exitCodeForError(error);\n}\n\n/**\n * Maps a structured init error to its documented exit code. Centralised so\n * the error → exit-code contract lives next to the codes themselves.\n *\n * `5009` (and the unknown-code default branch) routes to\n * `INIT_EXIT_INTERNAL_ERROR` because those represent prisma-next bugs the\n * user did not cause — surfacing them as `PRECONDITION` would mislead\n * automation into thinking the caller mis-invoked the CLI.\n *\n * See [exit-codes.ts](./exit-codes.ts) for the canonical list and\n * [Style Guide § Exit Codes](../../../../../../../docs/CLI%20Style%20Guide.md#exit-codes)\n * for the reservation policy.\n *\n * Exported for unit tests so the mapping can be asserted without\n * round-tripping a full `runInit` invocation.\n */\nexport function exitCodeForError(error: { readonly code: string }): number {\n switch (error.code) {\n case '5001': // missing manifest — precondition\n case '5002': // re-init needs --force — precondition\n case '5003': // missing flags — precondition\n case '5004': // invalid flag value — precondition\n case '5005': // --strict-probe without --probe-db — precondition\n case '5010': // invalid manifest (malformed package.json) — precondition\n case '5011': // invalid tsconfig (unparseable JSONC) — precondition\n case '5012': // probe failed under --strict-probe — precondition\n return INIT_EXIT_PRECONDITION;\n case '5006': // user aborted interactive prompt\n return INIT_EXIT_USER_ABORTED;\n case '5007': // install failed\n return INIT_EXIT_INSTALL_FAILED;\n case '5008': // emit failed\n return INIT_EXIT_EMIT_FAILED;\n case '5009': // invalid output document — internal bug in prisma-next\n return INIT_EXIT_INTERNAL_ERROR;\n default:\n // Any unexpected code is treated as an internal bug rather than\n // mis-routed to PRECONDITION. Adding a new code requires an\n // explicit case above.\n return INIT_EXIT_INTERNAL_ERROR;\n }\n}\n\n/**\n * Folds a `ProbeOutcome` into init's warning channel and returns the\n * fatal cause string when `--strict-probe` should escalate. Mirrors\n * the FR8.3 contract:\n *\n * - `ok` — informational; nothing surfaced unless verbose. (We could\n * plumb a `note` here, but the spec only requires the warning side\n * of the contract; an \"all good\" line would just be noise on the\n * common path.)\n * - `below-minimum` — warning regardless of `--strict-probe`. The\n * probe ran successfully and found an old server; that is not a\n * probe *failure* (which is what `--strict-probe` escalates), it\n * is the probe doing its job.\n * - `no-database-url` / `connection-failed` / `driver-missing` —\n * warning by default, fatal under `--strict-probe`.\n *\n * Exported for unit tests so the branching contract can be asserted\n * without spinning up a full `runInit` round trip.\n */\nexport function applyProbeOutcome(\n outcome: ProbeOutcome,\n ctx: { readonly strictProbe: boolean; readonly warnings: string[] },\n): string | null {\n switch (outcome.kind) {\n case 'ok':\n return null;\n case 'below-minimum':\n ctx.warnings.push(outcome.message);\n return null;\n case 'no-database-url':\n case 'connection-failed':\n case 'driver-missing':\n if (ctx.strictProbe) {\n return outcome.message;\n }\n ctx.warnings.push(outcome.message);\n return null;\n }\n}\n\n/**\n * Drives the `pnpm add` / `npm install` step. Failures are escalated to\n * a structured `errorInitInstallFailed` (exit code 4) — the spec treats\n * an unrecoverable install as a hard outcome rather than a warning so\n * CI/agents can branch on the exit code (FR1.6).\n *\n * For pnpm specifically, we additionally implement the FR7.2 fallback:\n * if pnpm fails with a recognised workspace/catalog resolution error\n * class (typically caused by a registry version that leaked\n * `workspace:*` or `catalog:` specifiers), we retry the install using\n * `npm` and surface a non-fatal warning explaining the swap.\n */\nasync function runInstall(ctx: {\n readonly baseDir: string;\n readonly pm: Awaited<ReturnType<typeof detectPackageManager>>;\n readonly target: ResolvedInitInputs['target'];\n readonly install: boolean;\n readonly flags: GlobalFlags;\n readonly ui: TerminalUI;\n readonly filesWritten: readonly string[];\n /**\n * FR2.1 — set when the user already declares `@types/node` directly in\n * `dependencies` or `devDependencies`. We then skip adding it so a\n * pinned major (e.g. `^18` for a Node 18 runtime) survives `init`\n * unchanged. Transitive presence is intentionally ignored: detecting\n * it requires lockfile introspection and the realistic clobber risk\n * is the direct-pin case.\n */\n readonly hasTypesNode: boolean;\n}): Promise<InstallReport> {\n const { baseDir, pm, target, install, flags, ui, filesWritten, hasTypesNode } = ctx;\n const pkg = targetPackageName(target);\n const deps = [pkg, 'dotenv'];\n // FR2.1: under `moduleResolution: 'bundler'` (FR2.2) the scaffolded\n // `db.ts` / `prisma-next.config.ts` reference `process.env`, which\n // only typechecks with Node's ambient types in the resolution graph.\n // Pin it as a devDep rather than relying on a transitive resolution\n // through `dotenv` (whose types bundle is internal and not guaranteed\n // across versions). Skip when the user already declares `@types/node`\n // directly so a pinned major (e.g. `^18` for a Node 18 runtime) is\n // preserved. Listed last so the install log still leads with the\n // user-relevant `prisma-next` line.\n const devDeps = hasTypesNode ? ['prisma-next'] : ['prisma-next', '@types/node'];\n\n const addCommand = `${pm} ${formatAddArgs(pm, deps).join(' ')}`;\n const addDevCommand = `${pm} ${formatAddDevArgs(pm, devDeps).join(' ')}`;\n const emitCommand = formatRunCommand(pm, 'prisma-next', 'contract emit');\n\n // FR7.3 / Spec Decision 8 — honour-and-warn: if the surrounding pnpm\n // workspace pins one of our packages via the catalog, surface a\n // structured warning so the user knows the catalog version (not the\n // published `latest`) is what ends up installed. We collect the\n // warning whether or not we actually run install — the override\n // applies to a manual install too — but only when pnpm is the chosen\n // PM (catalog: specifiers are pnpm-specific).\n const catalogWarnings = pm === 'pnpm' ? buildCatalogWarnings(baseDir, [...deps, ...devDeps]) : [];\n\n if (!install) {\n if (!flags.json && !flags.quiet) {\n ui.note(\n [\n 'Run the following commands to complete setup:',\n '',\n ' 1. Install dependencies:',\n ` ${addCommand}`,\n ` ${addDevCommand}`,\n '',\n ' 2. Emit the contract:',\n ` ${emitCommand}`,\n ].join('\\n'),\n 'Manual steps',\n );\n }\n return { skipped: true, deps: [], devDeps: [], warnings: catalogWarnings };\n }\n\n const exec = promisify(execFile);\n const runPair = async (manager: PackageManager): Promise<void> => {\n await exec(manager, formatAddArgs(manager, deps), { cwd: baseDir });\n await exec(manager, formatAddDevArgs(manager, devDeps), { cwd: baseDir });\n };\n\n const allPackages = [...deps, ...devDeps].join(', ');\n const spinner = ui.spinner();\n spinner.start(`Installing ${allPackages}...`);\n try {\n await runPair(pm);\n spinner.stop(`Installed ${allPackages}`);\n return { skipped: false, deps, devDeps, warnings: catalogWarnings };\n } catch (err) {\n const stderrText = redactSecrets(readChildStderr(err));\n\n // FR7.2: detect a recognised pnpm workspace/catalog resolution error\n // and fall back to npm. Limited to pnpm specifically; npm/yarn/bun/deno\n // failures escalate straight to a structured install error.\n if (pm === 'pnpm' && isRecognisedPnpmResolutionError(stderrText)) {\n spinner.message(\n 'pnpm could not resolve a workspace/catalog dependency, retrying with npm...',\n );\n try {\n await runPair('npm');\n spinner.stop(`Installed ${allPackages} via npm (pnpm fallback)`);\n const fallbackWarning = [\n 'pnpm could not install: a published Prisma Next dependency leaked a `workspace:*` or `catalog:` specifier.',\n 'Falling back to `npm install` so init can complete.',\n stderrText ? ` pnpm error: ${stderrText.trim().split('\\n')[0]}` : '',\n 'Once the offending package republishes a clean version, re-run `pnpm install` to switch back.',\n ]\n .filter(Boolean)\n .join('\\n');\n return {\n skipped: false,\n deps,\n devDeps,\n // The pnpm fallback fired, so the workspace catalog is not the\n // version that was actually installed (npm bypassed pnpm's\n // resolver). Surface the fallback warning but suppress the\n // catalog-honour warning to avoid a contradictory message\n // pair.\n warnings: [fallbackWarning],\n };\n } catch (npmErr) {\n spinner.stop('Installation failed');\n const npmStderr = redactSecrets(readChildStderr(npmErr));\n throw errorInitInstallFailed({\n addCommand,\n addDevCommand,\n emitCommand,\n filesWritten,\n stderrLines: [stderrText, npmStderr],\n });\n }\n }\n\n spinner.stop('Installation failed');\n throw errorInitInstallFailed({\n addCommand,\n addDevCommand,\n emitCommand,\n filesWritten,\n stderrLines: [stderrText],\n });\n }\n}\n\n/**\n * Builds the FR7.3 catalog-honoured warning(s) for the surrounding pnpm\n * workspace, if any. Returns an empty array when no `pnpm-workspace.yaml`\n * exists in any ancestor or when the workspace's catalog has no entry\n * for any of the packages `init` is about to install.\n *\n * Exported for unit tests.\n */\nexport function buildCatalogWarnings(\n baseDir: string,\n packages: readonly string[],\n): readonly string[] {\n const result = detectPnpmCatalogOverrides(baseDir, packages);\n if (result === null || result.entries.length === 0) {\n return [];\n }\n return [formatCatalogWarning(result.workspaceFile, result.entries)];\n}\n\nfunction formatCatalogWarning(\n workspaceFile: string,\n entries: readonly PnpmCatalogOverride[],\n): string {\n const list = entries.map((entry) => ` • ${entry.name}: ${entry.version}`).join('\\n');\n return [\n 'pnpm workspace catalog overrides detected — pnpm will install these versions instead of `latest`:',\n list,\n `Catalog source: ${workspaceFile}`,\n 'To use the published `latest` instead, remove or update the catalog entry, then re-run `pnpm install`.',\n ].join('\\n');\n}\n\n/**\n * Recognised pnpm error signatures that justify a fallback to npm.\n *\n * These patterns indicate the published artefact itself is at fault\n * (a leaked `workspace:*` or `catalog:` specifier), not the user's\n * environment — pnpm is faithfully reporting \"I cannot resolve this\n * registry version\", and npm is willing to install it because npm\n * doesn't care about the protocol prefix when there's a fallback range.\n *\n * Exported for unit tests; do not depend on this from outside the init\n * command.\n */\nexport function isRecognisedPnpmResolutionError(stderr: string): boolean {\n if (!stderr) return false;\n return (\n stderr.includes('ERR_PNPM_WORKSPACE_PKG_NOT_FOUND') ||\n stderr.includes('ERR_PNPM_NO_MATCHING_VERSION') ||\n /No matching version found for .* in the catalog/i.test(stderr) ||\n /workspace:[^\\s]+ is not a valid (version|spec)/i.test(stderr) ||\n /catalog:[^\\s]* is not a valid (version|spec)/i.test(stderr)\n );\n}\n\n/**\n * FR2.1 — true when the parsed `package.json` declares `name` directly\n * in either `dependencies` or `devDependencies`. We deliberately don't\n * inspect `peerDependencies` (irrelevant for a leaf project) or the\n * lockfile (transitive presence is brittle to detect and not the\n * realistic clobber-risk path).\n *\n * Exported for unit tests.\n */\nexport function hasDirectDep(parsed: Record<string, unknown>, name: string): boolean {\n for (const field of ['dependencies', 'devDependencies'] as const) {\n const value = parsed[field];\n if (value !== null && typeof value === 'object' && name in value) {\n return true;\n }\n }\n return false;\n}\n\nfunction readChildStderr(err: unknown): string {\n if (err instanceof Error && 'stderr' in err) {\n return String((err as { stderr: string }).stderr ?? '');\n }\n return '';\n}\n\n/**\n * Redacts userinfo (`user:password@`) from any URL-shaped substring inside\n * package-manager stderr before we surface it in a warning or error\n * meta. pnpm and npm both include the offending registry URL in resolve\n * errors, and that URL can carry an auth token (e.g. corporate registry\n * mirrors that bake `_authToken` into the URL). The Style Guide\n * (Testing & Accessibility — \"Security: never print secrets\") requires\n * we never surface those.\n *\n * Exported for unit tests.\n */\nexport function redactSecrets(stderr: string): string {\n if (!stderr) return stderr;\n // Match `scheme://userinfo@host…` and replace the userinfo with `***`.\n return stderr.replace(/([a-zA-Z][a-zA-Z0-9+.-]*:\\/\\/)([^/@\\s]+)@/g, '$1***@');\n}\n\n/**\n * Drives `prisma-next contract emit` against the freshly scaffolded\n * project. On failure, throws `errorInitEmitFailed` with the underlying\n * cause embedded in `meta.cause` so the user can re-run with `-v` to see\n * the full envelope and follow the fix steps. Maps to exit code\n * `5 = EMIT_FAILED` (FR1.6).\n */\nasync function runEmit(ctx: {\n readonly baseDir: string;\n readonly ui: TerminalUI;\n readonly filesWritten: readonly string[];\n readonly emitCommand: string;\n}): Promise<void> {\n const spinner = ctx.ui.spinner();\n spinner.start('Emitting contract...');\n try {\n const { executeContractEmit } = await import('../../control-api/operations/contract-emit');\n const configFilePath = join(ctx.baseDir, 'prisma-next.config.ts');\n await executeContractEmit({ configPath: configFilePath });\n spinner.stop('Contract emitted');\n } catch (err) {\n spinner.stop('Contract emission failed');\n throw errorInitEmitFailed({\n emitCommand: ctx.emitCommand,\n filesWritten: ctx.filesWritten,\n cause: causeMessage(err),\n });\n }\n}\n\nfunction causeMessage(err: unknown): string {\n if (err instanceof Error) return err.message;\n return String(err);\n}\n"],"mappings":"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"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { t as loadConfig } from "./config-loader-
|
|
2
|
-
import { _ as errorUnexpected, c as errorDriverRequired, o as errorDatabaseConnectionRequired, t as CliStructuredError } from "./cli-errors-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { t as
|
|
1
|
+
import { t as loadConfig } from "./config-loader-ih8ViDb_.mjs";
|
|
2
|
+
import { _ as errorUnexpected, c as errorDriverRequired, o as errorDatabaseConnectionRequired, t as CliStructuredError } from "./cli-errors-By1iVE3z.mjs";
|
|
3
|
+
import { _ as formatStyledHeader, a as maskConnectionUrl, l as sanitizeErrorMessage } from "./result-handler-BmVh8AeV.mjs";
|
|
4
|
+
import { t as createProgressAdapter } from "./progress-adapter-DgRGldpT.mjs";
|
|
5
|
+
import { t as createControlClient } from "./client-keSCAgjW.mjs";
|
|
6
6
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
7
7
|
import { relative, resolve } from "pathe";
|
|
8
|
-
import { validatePrintableSqlSchemaIR } from "@prisma-next/psl-printer";
|
|
9
8
|
|
|
10
9
|
//#region src/commands/inspect-live-schema.ts
|
|
11
10
|
async function inspectLiveSchema(options, flags, ui, startTime, context) {
|
|
@@ -56,17 +55,18 @@ async function inspectLiveSchema(options, flags, ui, startTime, context) {
|
|
|
56
55
|
flags
|
|
57
56
|
});
|
|
58
57
|
try {
|
|
59
|
-
const
|
|
58
|
+
const schema = await client.introspect({
|
|
60
59
|
connection: dbConnection,
|
|
61
60
|
onProgress
|
|
62
61
|
});
|
|
63
|
-
const schema = config.family.familyId === "sql" ? validatePrintableSqlSchemaIR(schemaIR) : schemaIR;
|
|
64
62
|
const schemaView = client.toSchemaView(schema);
|
|
63
|
+
const pslContractAst = client.inferPslContract(schema);
|
|
65
64
|
const dbUrl = typeof dbConnection === "string" ? maskConnectionUrl(dbConnection) : void 0;
|
|
66
65
|
return ok({
|
|
67
66
|
config,
|
|
68
67
|
schema,
|
|
69
68
|
schemaView,
|
|
69
|
+
pslContractAst,
|
|
70
70
|
target: {
|
|
71
71
|
familyId: config.family.familyId,
|
|
72
72
|
id: config.target.targetId
|
|
@@ -88,4 +88,4 @@ async function inspectLiveSchema(options, flags, ui, startTime, context) {
|
|
|
88
88
|
|
|
89
89
|
//#endregion
|
|
90
90
|
export { inspectLiveSchema as t };
|
|
91
|
-
//# sourceMappingURL=inspect-live-schema-
|
|
91
|
+
//# sourceMappingURL=inspect-live-schema-BaR9ISwa.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect-live-schema-BaR9ISwa.mjs","names":["config: LoadedCliConfig","details: Array<{ label: string; value: string }>"],"sources":["../src/commands/inspect-live-schema.ts"],"sourcesContent":["import type { CoreSchemaView } from '@prisma-next/framework-components/control';\nimport type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { relative, resolve } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport {\n CliStructuredError,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorUnexpected,\n} from '../utils/cli-errors';\nimport { maskConnectionUrl, sanitizeErrorMessage } from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions, GlobalFlags } from '../utils/global-flags';\nimport { createProgressAdapter } from '../utils/progress-adapter';\nimport type { TerminalUI } from '../utils/terminal-ui';\n\nexport interface InspectLiveSchemaOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n}\n\ninterface InspectLiveSchemaContext {\n readonly commandName: string;\n readonly description: string;\n readonly url: string;\n}\n\ntype LoadedCliConfig = Awaited<ReturnType<typeof loadConfig>>;\n\nexport interface InspectLiveSchemaResult {\n readonly config: LoadedCliConfig;\n readonly schema: unknown;\n readonly schemaView: CoreSchemaView | undefined;\n /**\n * PSL AST inferred from the introspected schema, when the configured family\n * implements `PslContractInferCapable`. `undefined` for families that do not\n * support inference (e.g. Mongo today).\n */\n readonly pslContractAst: PslDocumentAst | undefined;\n readonly target: {\n readonly familyId: string;\n readonly id: string;\n };\n readonly meta: {\n readonly configPath?: string;\n readonly dbUrl?: string;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\nexport async function inspectLiveSchema(\n options: InspectLiveSchemaOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n context: InspectLiveSchemaContext,\n): Promise<Result<InspectLiveSchemaResult, CliStructuredError>> {\n let config: LoadedCliConfig;\n try {\n config = await loadConfig(options.config);\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: 'Failed to load config',\n }),\n );\n }\n\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n ];\n\n if (options.db) {\n details.push({ label: 'database', value: maskConnectionUrl(options.db) });\n } else if (config.db?.connection && typeof config.db.connection === 'string') {\n details.push({ label: 'database', value: maskConnectionUrl(config.db.connection) });\n }\n\n ui.stderr(\n formatStyledHeader({\n command: context.commandName,\n description: context.description,\n url: context.url,\n details,\n flags,\n }),\n );\n }\n\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for ${context.commandName} (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: context.commandName,\n }),\n );\n }\n\n if (!config.driver) {\n return notOk(\n errorDriverRequired({\n why: `Config.driver is required for ${context.commandName}`,\n }),\n );\n }\n\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n const onProgress = createProgressAdapter({ ui, flags });\n\n try {\n const schema = await client.introspect({\n connection: dbConnection,\n onProgress,\n });\n const schemaView = client.toSchemaView(schema);\n const pslContractAst = client.inferPslContract(schema);\n\n const dbUrl = typeof dbConnection === 'string' ? maskConnectionUrl(dbConnection) : undefined;\n\n return ok({\n config,\n schema,\n schemaView,\n pslContractAst,\n target: {\n familyId: config.family.familyId,\n id: config.target.targetId,\n },\n meta: {\n configPath,\n ...(dbUrl ? { dbUrl } : {}),\n },\n timings: {\n total: Date.now() - startTime,\n },\n });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n\n const rawMessage = error instanceof Error ? error.message : String(error);\n const safeMessage = sanitizeErrorMessage(\n rawMessage,\n typeof dbConnection === 'string' ? dbConnection : undefined,\n );\n return notOk(\n errorUnexpected(safeMessage, {\n why: `Unexpected error during ${context.commandName}: ${safeMessage}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n"],"mappings":";;;;;;;;;AAsDA,eAAsB,kBACpB,SACA,OACA,IACA,WACA,SAC8D;CAC9D,IAAIA;AACJ,KAAI;AACF,WAAS,MAAM,WAAW,QAAQ,OAAO;UAClC,OAAO;AACd,MAAI,mBAAmB,GAAG,MAAM,CAC9B,QAAO,MAAM,MAAM;AAGrB,SAAO,MACL,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACtE,KAAK,yBACN,CAAC,CACH;;CAGH,MAAM,aAAa,QAAQ,SACvB,SAAS,QAAQ,KAAK,EAAE,QAAQ,QAAQ,OAAO,CAAC,GAChD;AAEJ,KAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EAC/B,MAAMC,UAAmD,CACvD;GAAE,OAAO;GAAU,OAAO;GAAY,CACvC;AAED,MAAI,QAAQ,GACV,SAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,QAAQ,GAAG;GAAE,CAAC;WAChE,OAAO,IAAI,cAAc,OAAO,OAAO,GAAG,eAAe,SAClE,SAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,OAAO,GAAG,WAAW;GAAE,CAAC;AAGrF,KAAG,OACD,mBAAmB;GACjB,SAAS,QAAQ;GACjB,aAAa,QAAQ;GACrB,KAAK,QAAQ;GACb;GACA;GACD,CAAC,CACH;;CAGH,MAAM,eAAe,QAAQ,MAAM,OAAO,IAAI;AAC9C,KAAI,CAAC,aACH,QAAO,MACL,gCAAgC;EAC9B,KAAK,uCAAuC,QAAQ,YAAY,yBAAyB,WAAW;EACpG,aAAa,QAAQ;EACtB,CAAC,CACH;AAGH,KAAI,CAAC,OAAO,OACV,QAAO,MACL,oBAAoB,EAClB,KAAK,iCAAiC,QAAQ,eAC/C,CAAC,CACH;CAGH,MAAM,SAAS,oBAAoB;EACjC,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,QAAQ,OAAO;EACf,gBAAgB,OAAO,kBAAkB,EAAE;EAC5C,CAAC;CACF,MAAM,aAAa,sBAAsB;EAAE;EAAI;EAAO,CAAC;AAEvD,KAAI;EACF,MAAM,SAAS,MAAM,OAAO,WAAW;GACrC,YAAY;GACZ;GACD,CAAC;EACF,MAAM,aAAa,OAAO,aAAa,OAAO;EAC9C,MAAM,iBAAiB,OAAO,iBAAiB,OAAO;EAEtD,MAAM,QAAQ,OAAO,iBAAiB,WAAW,kBAAkB,aAAa,GAAG;AAEnF,SAAO,GAAG;GACR;GACA;GACA;GACA;GACA,QAAQ;IACN,UAAU,OAAO,OAAO;IACxB,IAAI,OAAO,OAAO;IACnB;GACD,MAAM;IACJ;IACA,GAAI,QAAQ,EAAE,OAAO,GAAG,EAAE;IAC3B;GACD,SAAS,EACP,OAAO,KAAK,KAAK,GAAG,WACrB;GACF,CAAC;UACK,OAAO;AACd,MAAI,mBAAmB,GAAG,MAAM,CAC9B,QAAO,MAAM,MAAM;EAIrB,MAAM,cAAc,qBADD,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAGvE,OAAO,iBAAiB,WAAW,eAAe,OACnD;AACD,SAAO,MACL,gBAAgB,aAAa,EAC3B,KAAK,2BAA2B,QAAQ,YAAY,IAAI,eACzD,CAAC,CACH;WACO;AACR,QAAM,OAAO,OAAO"}
|
package/dist/migration-cli.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Migration } from "@prisma-next/migration-tools/migration";
|
|
2
|
+
import { Writable } from "node:stream";
|
|
2
3
|
|
|
3
4
|
//#region src/migration-cli.d.ts
|
|
4
5
|
|
|
@@ -18,6 +19,20 @@ import { Migration } from "@prisma-next/migration-tools/migration";
|
|
|
18
19
|
* point for additional construction arguments.
|
|
19
20
|
*/
|
|
20
21
|
type MigrationConstructor = new (...args: any[]) => Migration;
|
|
22
|
+
/**
|
|
23
|
+
* Stream surface accepted by `MigrationCLI.run`'s `options.stdout` /
|
|
24
|
+
* `options.stderr`. Aliases node's `Writable` because clipanion's
|
|
25
|
+
* `BaseContext.stdout`/`stderr` are typed as `Writable`, and the CLI
|
|
26
|
+
* forwards the injected streams into clipanion's context.
|
|
27
|
+
*
|
|
28
|
+
* `process.stdout` and `process.stderr` are `Writable`-shaped, so the
|
|
29
|
+
* default-fallback path remains a no-op for existing two-argument
|
|
30
|
+
* callers like `MigrationCLI.run(import.meta.url, MyMigration)`.
|
|
31
|
+
*
|
|
32
|
+
* Tests inject a `Writable` subclass that captures chunks for
|
|
33
|
+
* assertions.
|
|
34
|
+
*/
|
|
35
|
+
type MigrationCliWritable = Writable;
|
|
21
36
|
/**
|
|
22
37
|
* The CLI surface invoked by an authored `migration.ts` file. Exposed as
|
|
23
38
|
* a class with a static `run` method (rather than a free function) to
|
|
@@ -32,19 +47,34 @@ type MigrationConstructor = new (...args: any[]) => Migration;
|
|
|
32
47
|
*/
|
|
33
48
|
declare class MigrationCLI {
|
|
34
49
|
/**
|
|
35
|
-
* Orchestrates a class-flow `migration.ts` script run.
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
50
|
+
* Orchestrates a class-flow `migration.ts` script run.
|
|
51
|
+
*
|
|
52
|
+
* The third argument is the in-process testability surface: callers
|
|
53
|
+
* (and tests) may inject `argv`, `stdout`, and `stderr` instead of
|
|
54
|
+
* relying on `process.argv` / `process.stdout` / `process.stderr`.
|
|
55
|
+
* Each option defaults to its `process` global when omitted, so
|
|
56
|
+
* existing two-argument call sites
|
|
57
|
+
* (`MigrationCLI.run(import.meta.url, MyMigration)`) continue to
|
|
58
|
+
* compile and behave identically.
|
|
59
|
+
*
|
|
60
|
+
* Returns the exit code so the caller can branch on it. Also writes
|
|
61
|
+
* the same code to `process.exitCode` so script-style callers that
|
|
62
|
+
* don't await the return value still surface a non-zero exit when
|
|
63
|
+
* something fails.
|
|
40
64
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
65
|
+
* Exit codes:
|
|
66
|
+
* - 0 — success, or `--help`, or imported-not-entrypoint no-op.
|
|
67
|
+
* - 1 — runtime/orchestration error (config not found, target
|
|
68
|
+
* mismatch, etc.).
|
|
69
|
+
* - 2 — usage error (unknown flag, malformed `--config`). Aligns
|
|
70
|
+
* with `docs/CLI Style Guide.md` § Exit Codes.
|
|
45
71
|
*/
|
|
46
|
-
static run(importMetaUrl: string, MigrationClass: MigrationConstructor
|
|
72
|
+
static run(importMetaUrl: string, MigrationClass: MigrationConstructor, options?: {
|
|
73
|
+
readonly argv?: readonly string[];
|
|
74
|
+
readonly stdout?: MigrationCliWritable;
|
|
75
|
+
readonly stderr?: MigrationCliWritable;
|
|
76
|
+
}): Promise<number>;
|
|
47
77
|
}
|
|
48
78
|
//#endregion
|
|
49
|
-
export { MigrationCLI, MigrationConstructor };
|
|
79
|
+
export { MigrationCLI, MigrationCliWritable, MigrationConstructor };
|
|
50
80
|
//# sourceMappingURL=migration-cli.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-cli.d.mts","names":[],"sources":["../src/migration-cli.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"migration-cli.d.mts","names":[],"sources":["../src/migration-cli.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;KA6EY,oBAAA,2BAA+C;;;;;;;;;;;;;;KAe/C,oBAAA,GAAuB;;;;;;;;;;;;;cAuEtB,YAAA;;;;;;;;;;;;;;;;;;;;;;;;oDA0BO;;sBAGI;sBACA;MAEnB"}
|