@prisma/orm-toolchain 8.0.0-rc.1-dev.46 → 8.0.0-rc.10
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 +1 -5
- package/dist/{aggregate-CPZB020V.mjs → aggregate-B4HKshLQ.mjs} +10 -10
- package/dist/aggregate-B4HKshLQ.mjs.map +1 -0
- package/dist/{aggregate-DLUJLq5Y.d.mts → aggregate-D_eX4zoo.d.mts} +3 -3
- package/dist/{aggregate-DLUJLq5Y.d.mts.map → aggregate-D_eX4zoo.d.mts.map} +1 -1
- package/dist/cli-telemetry.d.mts +8 -7
- package/dist/cli-telemetry.d.mts.map +1 -1
- package/dist/cli-telemetry.mjs +22 -24
- package/dist/cli-telemetry.mjs.map +1 -1
- package/dist/cli.d.mts +2 -6
- package/dist/cli.d.mts.map +1 -1
- package/dist/cli.mjs +447 -430
- package/dist/cli.mjs.map +1 -1
- package/dist/cli__control-api.d.mts +20 -11
- package/dist/cli__control-api.d.mts.map +1 -1
- package/dist/cli__control-api.mjs +1 -1
- package/dist/cli__control-api__testing.d.mts +1 -1
- package/dist/cli__init-output.mjs +1 -1
- package/dist/cli__migration-cli.mjs +6 -6
- package/dist/cli__migration-cli.mjs.map +1 -1
- package/dist/config-loader.d.mts +1 -1
- package/dist/config-loader.mjs +1 -1
- package/dist/{contract-snapshot-store-B0G1Fw_F-CHc4QfKb.mjs → contract-snapshot-store-qGrwlGmt-Cf2NFzRL.mjs} +3 -3
- package/dist/{contract-snapshot-store-B0G1Fw_F-CHc4QfKb.mjs.map → contract-snapshot-store-qGrwlGmt-Cf2NFzRL.mjs.map} +1 -1
- package/dist/{db-verify-BwgNK50T-DGvKgFCK.d.mts → db-verify-Yih5kWtB-B1kv76ec.d.mts} +5 -5
- package/dist/{db-verify-BwgNK50T-DGvKgFCK.d.mts.map → db-verify-Yih5kWtB-B1kv76ec.d.mts.map} +1 -1
- package/dist/{domain-type-generation-bpSO3Y0L-jo2C7LlH.mjs → domain-type-generation-CR9ECUau-DOlKbcaE.mjs} +20 -6
- package/dist/domain-type-generation-CR9ECUau-DOlKbcaE.mjs.map +1 -0
- package/dist/{domain-type-generation-PkAb39ob-Ct8AGqow.d.mts → domain-type-generation-X6-AaL1U-DHEoRf_y.d.mts} +14 -3
- package/dist/domain-type-generation-X6-AaL1U-DHEoRf_y.d.mts.map +1 -0
- package/dist/emitter.d.mts +2 -2
- package/dist/emitter.mjs +2 -2
- package/dist/emitter__domain-type-generation.d.mts +2 -2
- package/dist/emitter__domain-type-generation.mjs +2 -2
- package/dist/{errors-CXbGUWGu-CstQHPh6.mjs → errors-SoLLYLtw-DMxVbVs9.mjs} +9 -9
- package/dist/errors-SoLLYLtw-DMxVbVs9.mjs.map +1 -0
- package/dist/{exports-BZaG8_w_.mjs → exports-BXXeNWlj.mjs} +25 -47
- package/dist/exports-BXXeNWlj.mjs.map +1 -0
- package/dist/exports-CE6OD63o-4Qpqr2W7.mjs +398 -0
- package/dist/exports-CE6OD63o-4Qpqr2W7.mjs.map +1 -0
- package/dist/{exports-8ZUN43ve.mjs → exports-CYa2di3d.mjs} +382 -22
- package/dist/exports-CYa2di3d.mjs.map +1 -0
- package/dist/{graph-membership-BViWUMpP-C4lYYJdU.mjs → graph-membership-DY1Onbc3-CwBd6wuB.mjs} +3 -3
- package/dist/{graph-membership-BViWUMpP-C4lYYJdU.mjs.map → graph-membership-DY1Onbc3-CwBd6wuB.mjs.map} +1 -1
- package/dist/{import-roots-CfoYgejL.d.mts → import-roots-ARK1wjzc.d.mts} +3 -3
- package/dist/{import-roots-CfoYgejL.d.mts.map → import-roots-ARK1wjzc.d.mts.map} +1 -1
- package/dist/{import-roots-CNFBPAT1.mjs → import-roots-BHOrDJbI.mjs} +5 -5
- package/dist/import-roots-BHOrDJbI.mjs.map +1 -0
- package/dist/{index-Dgwl8Tzs.d.mts → index-D217lbiW.d.mts} +7 -3
- package/dist/index-D217lbiW.d.mts.map +1 -0
- package/dist/{index-DRs7L6N0.d.mts → index-u5RdrumF.d.mts} +2 -19
- package/dist/index-u5RdrumF.d.mts.map +1 -0
- package/dist/{invariants-CTHy88OP-CYI2a8IO.mjs → invariants-Cww4bv0v-BEiFxmbX.mjs} +3 -3
- package/dist/{invariants-CTHy88OP-CYI2a8IO.mjs.map → invariants-Cww4bv0v-BEiFxmbX.mjs.map} +1 -1
- package/dist/{io-635GlNx1-D3zrw2qu.mjs → io-BmWQNxRP-DQqbcPsS.mjs} +5 -5
- package/dist/{io-635GlNx1-D3zrw2qu.mjs.map → io-BmWQNxRP-DQqbcPsS.mjs.map} +1 -1
- package/dist/{migration-hspPIEeV.mjs → migration-B9w-7dKe.mjs} +4 -4
- package/dist/{migration-hspPIEeV.mjs.map → migration-B9w-7dKe.mjs.map} +1 -1
- package/dist/{migration-graph-_SJImD5V-BURyY1KM.mjs → migration-graph-CW4bMmTz-B5xFtFVB.mjs} +3 -3
- package/dist/{migration-graph-_SJImD5V-BURyY1KM.mjs.map → migration-graph-CW4bMmTz-B5xFtFVB.mjs.map} +1 -1
- package/dist/migration-tools.d.mts +3 -3
- package/dist/migration-tools.mjs +12 -12
- package/dist/migration-tools__aggregate.d.mts +1 -1
- package/dist/migration-tools__aggregate.mjs +1 -1
- package/dist/migration-tools__contract-snapshot-store.mjs +1 -1
- package/dist/migration-tools__errors.mjs +1 -1
- package/dist/migration-tools__invariants.mjs +1 -1
- package/dist/migration-tools__io.mjs +1 -1
- package/dist/migration-tools__migration-graph.mjs +2 -2
- package/dist/migration-tools__migration.mjs +1 -1
- package/dist/migration-tools__ref-resolution.d.mts +1 -1
- package/dist/migration-tools__ref-resolution.mjs +1 -1
- package/dist/migration-tools__refs.mjs +1 -1
- package/dist/migration-tools__spaces.d.mts +1 -1
- package/dist/migration-tools__spaces.mjs +2 -2
- package/dist/{output-CovTDY14-CUoAqLML.mjs → output-D83nTTpC-XlvN30yS.mjs} +4 -4
- package/dist/{output-CovTDY14-CUoAqLML.mjs.map → output-D83nTTpC-XlvN30yS.mjs.map} +1 -1
- package/dist/publish-surface.d.mts +1 -1
- package/dist/publish-surface.mjs +2 -2
- package/dist/publish-surface__import-roots.d.mts +1 -1
- package/dist/publish-surface__import-roots.mjs +1 -1
- package/dist/publish-surface__shells.mjs +1 -1
- package/dist/quick-reference-mongo.md +11 -11
- package/dist/quick-reference-postgres.md +10 -10
- package/dist/readme-mongo.md +6 -6
- package/dist/readme-postgres.md +6 -6
- package/dist/{ref-h6InR6dO-rGfl18Jv.mjs → ref-DcqFmceq-QaUjgZeM.mjs} +190 -87
- package/dist/ref-DcqFmceq-QaUjgZeM.mjs.map +1 -0
- package/dist/{ref-resolution-HeNBXW53.mjs → ref-resolution-BWpwb8_b.mjs} +9 -2
- package/dist/ref-resolution-BWpwb8_b.mjs.map +1 -0
- package/dist/{ref-resolution-COGOSL57.d.mts → ref-resolution-CaHQJXE0.d.mts} +11 -1
- package/dist/ref-resolution-CaHQJXE0.d.mts.map +1 -0
- package/dist/{refs-WK86uYYp-gM8tvWQP.mjs → refs-BpSpzdYB-BcDelHGt.mjs} +9 -9
- package/dist/refs-BpSpzdYB-BcDelHGt.mjs.map +1 -0
- package/dist/{shells-C4HbRAr5.mjs → shells-BIdFZwUY.mjs} +1 -6
- package/dist/shells-BIdFZwUY.mjs.map +1 -0
- package/dist/{spaces-Dj65JrwZ.d.mts → spaces-B20bgxF9.d.mts} +2 -2
- package/dist/{spaces-Dj65JrwZ.d.mts.map → spaces-B20bgxF9.d.mts.map} +1 -1
- package/dist/{spaces-4qMOAYE9.mjs → spaces-BCZiAZQn.mjs} +7 -7
- package/dist/spaces-BCZiAZQn.mjs.map +1 -0
- package/dist/{verify-contract-spaces-DhJTb0zM-B62maCfE.mjs → verify-contract-spaces-CrxvgpwD-D5LLXGci.mjs} +7 -7
- package/dist/{verify-contract-spaces-DhJTb0zM-B62maCfE.mjs.map → verify-contract-spaces-CrxvgpwD-D5LLXGci.mjs.map} +1 -1
- package/dist/vite-plugin-contract-emit.d.mts +1 -1
- package/dist/vite-plugin-contract-emit.mjs +7 -7
- package/dist/vite-plugin-contract-emit.mjs.map +1 -1
- package/package.json +16 -16
- package/dist/aggregate-CPZB020V.mjs.map +0 -1
- package/dist/domain-type-generation-PkAb39ob-Ct8AGqow.d.mts.map +0 -1
- package/dist/domain-type-generation-bpSO3Y0L-jo2C7LlH.mjs.map +0 -1
- package/dist/errors-CXbGUWGu-CstQHPh6.mjs.map +0 -1
- package/dist/exports-8ZUN43ve.mjs.map +0 -1
- package/dist/exports-BCLg4CiV-05kuwcb0.mjs +0 -160
- package/dist/exports-BCLg4CiV-05kuwcb0.mjs.map +0 -1
- package/dist/exports-BZaG8_w_.mjs.map +0 -1
- package/dist/import-roots-CNFBPAT1.mjs.map +0 -1
- package/dist/index-DRs7L6N0.d.mts.map +0 -1
- package/dist/index-Dgwl8Tzs.d.mts.map +0 -1
- package/dist/ref-h6InR6dO-rGfl18Jv.mjs.map +0 -1
- package/dist/ref-resolution-COGOSL57.d.mts.map +0 -1
- package/dist/ref-resolution-HeNBXW53.mjs.map +0 -1
- package/dist/refs-WK86uYYp-gM8tvWQP.mjs.map +0 -1
- package/dist/shells-C4HbRAr5.mjs.map +0 -1
- package/dist/spaces-4qMOAYE9.mjs.map +0 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { r as getEmittedArtifactPaths } from "./exports-
|
|
1
|
+
import { r as getEmittedArtifactPaths } from "./exports-CE6OD63o-4Qpqr2W7.mjs";
|
|
2
|
+
import { t as MigrationToolsError } from "./errors-SoLLYLtw-DMxVbVs9.mjs";
|
|
2
3
|
import { t as EMPTY_CONTRACT_HASH } from "./constants-CM-w38DQ-Cz_EXbOc.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { n as
|
|
7
|
-
import {
|
|
4
|
+
import { r as readRef } from "./refs-BpSpzdYB-BcDelHGt.mjs";
|
|
5
|
+
import { c as spaceMigrationDirectory } from "./verify-contract-spaces-CrxvgpwD-D5LLXGci.mjs";
|
|
6
|
+
import { i as createScaffoldSpecifierResolver } from "./import-roots-BHOrDJbI.mjs";
|
|
7
|
+
import { $ as loadAggregateIntegrityViolations, A as errorMigrationPackageNotFound, At as runMigrationList, C as errorDatabaseConnectionRequired, D as errorHashMismatch, Dt as runCommandAction, E as errorFileNotFound, F as errorRuntime, G as executeMigrationPlanCommand, I as errorTargetMigrationNotSupported, J as executeRefListCommand, L as errorTargetMismatch, M as errorNoMigrations, Mt as statusForMigrationHash, N as errorPathUnreachable, Nt as targetSupportsMigrations, O as errorLegendHumanOnly, P as errorRunnerFailed, Pt as toDeclaredExtensionsFromRaw, Q as listRefsByContractHash, R as errorUnexpected, S as errorContractValidationFailed, St as resolveContractRefToSnapshot, T as errorDriverRequired, Tt as resolveRefAdvancementFields, U as executeMigrateShowPlan, W as executeMigrationNewCommand, X as findPackageByDirPath, Y as executeRefSetCommand, Z as hasMigrationPath, _ as enumerateCheckSpaces, _t as refusePackageCorruptionOnAggregate, b as errorConsentPlanMismatch, bt as resolveAppTargetPath, ct as originHashForStatus, d as closeQuietly, dt as readContractIR, et as loadContractRawSafely, ft as readMigrationRefs, gt as refuseMissingInvariantPath, ht as refuseMarkerOutsideGraph, i as appliedHashesFromLedger, it as mapContractAtError, j as errorMigrationPlanningFailed, jt as sanitizeErrorMessage, k as errorMarkerMissing, kt as runMigrationCheck, l as checkSingleTarget, lt as preflightRefAdvancement, m as deriveStatusEdgeAnnotations, n as advanceRefSafely, nt as looksLikePath, o as buildMigrationSpaceGraphEntries, ot as maskConnectionUrl, p as createControlClient, pt as refuseContractSpaceIntegrity, q as executeRefDeleteCommand, rt as mapCaughtMigrationError, s as buildReadAggregate, st as migrationSpaceListEntriesFromAggregate, t as CliStructuredError$1$1, tt as loadContractSpaceAggregateForCli, u as chooseAction, ut as readContractEnvelope, v as errorAdvanceRefArgConflict, vt as refuseUnknownInvariants, w as errorDestructiveChanges, wt as resolveMigrationRef, x as errorContractArgConflict, xt as resolveContractRef$1, y as errorConfigValidation$1, yt as requireLiveDatabase, z as executeContractEmit } from "./ref-DcqFmceq-QaUjgZeM.mjs";
|
|
8
|
+
import { n as buildNextSteps, t as InitOutputSchema } from "./output-D83nTTpC-XlvN30yS.mjs";
|
|
9
|
+
import { r as loadConfig, t as finalizeConfig } from "./exports-BXXeNWlj.mjs";
|
|
8
10
|
import { createRequire } from "node:module";
|
|
11
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
9
12
|
import { ifDefined } from "@prisma/orm-framework/utils/defined";
|
|
10
13
|
import { DOCS_BASE, docsUrlFor, isStructuredError, isStructuredErrorCode } from "@prisma/orm-framework/utils/structured-error";
|
|
11
14
|
import { keepInternalSpecifiers } from "@prisma/orm-framework/components/emission";
|
|
@@ -17,27 +20,26 @@ import { notOk, ok } from "@prisma/orm-framework/utils/result";
|
|
|
17
20
|
import { basename, dirname, extname, isAbsolute, join, normalize, relative, resolve } from "pathe";
|
|
18
21
|
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
19
22
|
import { type } from "arktype";
|
|
20
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
21
23
|
import { defineCommand, defineCommandFamily, defineConfigSection, defineServerCommand, flag, positional } from "@prisma/cli-engine";
|
|
22
24
|
import { CliStructuredError as CliStructuredError$1, notOk as notOk$1, ok as ok$1 } from "@prisma/cli-engine/protocol";
|
|
23
25
|
import { collectConfigIssues } from "@prisma/orm-framework/config/config-validation";
|
|
26
|
+
import { DEFAULT_CONTRACT_SOURCE_DIR } from "@prisma/orm-framework/config/config-types";
|
|
27
|
+
import { pathToFileURL } from "node:url";
|
|
24
28
|
import { printPsl } from "@prisma/orm-framework/psl-printer";
|
|
25
29
|
import { EOL, tmpdir } from "node:os";
|
|
26
30
|
import { format } from "@prisma/orm-framework/psl-parser/format";
|
|
27
|
-
import {
|
|
31
|
+
import { suppressIdleConnectionErrors } from "@prisma/orm-framework/utils/suppress-idle-connection-errors";
|
|
28
32
|
import { spawn } from "node:child_process";
|
|
29
33
|
import { detect } from "package-manager-detector/detect";
|
|
30
34
|
import { applyEdits, modify, parse, printParseErrorCode } from "jsonc-parser";
|
|
31
35
|
import stringWidth from "string-width";
|
|
32
36
|
import { bold, createColors, cyan, cyanBright, dim, green, yellow } from "colorette";
|
|
33
|
-
import { pathToFileURL } from "node:url";
|
|
34
37
|
import { build } from "esbuild";
|
|
35
|
-
//#region ../../../1-framework/3-tooling/cli/dist/load-config-
|
|
36
|
-
var version = "8.0.0-rc.1-dev.46";
|
|
38
|
+
//#region ../../../1-framework/3-tooling/cli/dist/load-config-Dg1SXbzd.mjs
|
|
37
39
|
const MISSING_CONFIG_ACTION = {
|
|
38
40
|
kind: "run-command",
|
|
39
41
|
label: "Create a config file",
|
|
40
|
-
command: "
|
|
42
|
+
command: "{bin} orm init"
|
|
41
43
|
};
|
|
42
44
|
function editConfigAction(field) {
|
|
43
45
|
return {
|
|
@@ -62,7 +64,7 @@ function sectionAbsentDiagnostic() {
|
|
|
62
64
|
return {
|
|
63
65
|
code: "CONFIG.FILE_NOT_FOUND",
|
|
64
66
|
severity: "error",
|
|
65
|
-
summary: "No Prisma
|
|
67
|
+
summary: "No Prisma ORM configuration was loaded",
|
|
66
68
|
why: `The orm config section is absent, so prisma.config.ts was never evaluated.`,
|
|
67
69
|
nextActions: [MISSING_CONFIG_ACTION]
|
|
68
70
|
};
|
|
@@ -71,7 +73,7 @@ function notAnObjectDiagnostic() {
|
|
|
71
73
|
return {
|
|
72
74
|
code: "CONFIG.VALIDATION_FAILED",
|
|
73
75
|
severity: "error",
|
|
74
|
-
summary: "Prisma
|
|
76
|
+
summary: "Prisma ORM configuration must be an object",
|
|
75
77
|
why: `The orm config section is not an object, so no section can be read from it.`,
|
|
76
78
|
nextActions: [{
|
|
77
79
|
kind: "edit-file",
|
|
@@ -83,7 +85,7 @@ function unreadableDiagnostic(error) {
|
|
|
83
85
|
return {
|
|
84
86
|
code: "CONFIG.VALIDATION_FAILED",
|
|
85
87
|
severity: "error",
|
|
86
|
-
summary: "Prisma
|
|
88
|
+
summary: "Prisma ORM configuration could not be inspected",
|
|
87
89
|
why: error instanceof Error ? error.message : String(error),
|
|
88
90
|
nextActions: [{
|
|
89
91
|
kind: "edit-file",
|
|
@@ -91,7 +93,7 @@ function unreadableDiagnostic(error) {
|
|
|
91
93
|
}]
|
|
92
94
|
};
|
|
93
95
|
}
|
|
94
|
-
function isRecord(value) {
|
|
96
|
+
function isRecord$1(value) {
|
|
95
97
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
96
98
|
}
|
|
97
99
|
/**
|
|
@@ -101,10 +103,10 @@ function isRecord(value) {
|
|
|
101
103
|
*/
|
|
102
104
|
function collectArtifactCollisionIssues(raw) {
|
|
103
105
|
const contract = raw["contract"];
|
|
104
|
-
if (!isRecord(contract)) return [];
|
|
106
|
+
if (!isRecord$1(contract)) return [];
|
|
105
107
|
const source = contract["source"];
|
|
106
108
|
const output = contract["output"];
|
|
107
|
-
if (!isRecord(source) || typeof output !== "string") return [];
|
|
109
|
+
if (!isRecord$1(source) || typeof output !== "string") return [];
|
|
108
110
|
const inputs = source["inputs"];
|
|
109
111
|
if (!Array.isArray(inputs)) return [];
|
|
110
112
|
let emitted;
|
|
@@ -130,7 +132,7 @@ function validate(raw) {
|
|
|
130
132
|
ok: false,
|
|
131
133
|
diagnostics: [sectionAbsentDiagnostic()]
|
|
132
134
|
};
|
|
133
|
-
if (!isRecord(raw)) return {
|
|
135
|
+
if (!isRecord$1(raw)) return {
|
|
134
136
|
ok: false,
|
|
135
137
|
diagnostics: [notAnObjectDiagnostic()]
|
|
136
138
|
};
|
|
@@ -246,15 +248,42 @@ function normalizeError(error) {
|
|
|
246
248
|
*
|
|
247
249
|
* An `InternalError` is the one thing this boundary does not convert. Its own contract says never
|
|
248
250
|
* to catch it outside the outermost boundary: it means an invariant broke, which is a bug in
|
|
249
|
-
* Prisma
|
|
251
|
+
* Prisma ORM rather than something the user did. Re-throwing lets the engine settle it as a bug
|
|
250
252
|
* at exit 1, where converting it would report the same number as a bad connection string.
|
|
251
253
|
*/
|
|
254
|
+
function isRecord(value) {
|
|
255
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Hands the handler a config whose paths are absolute. The engine's own
|
|
259
|
+
* loader evaluates `prisma.config.ts` without touching the paths inside it, so
|
|
260
|
+
* a command mounted in the unified host receives `contract.output` and
|
|
261
|
+
* `migrations.dir` exactly as authored — usually relative — while this repo's
|
|
262
|
+
* bin finalizes them in its loader. Anchoring here, on the section every ORM
|
|
263
|
+
* command reads, makes both hosts hand handlers the same absolute paths.
|
|
264
|
+
*
|
|
265
|
+
* The anchor is the working directory: the engine discovers the config in the
|
|
266
|
+
* working directory only, so that is the file's own directory. (A `--config`
|
|
267
|
+
* pointing into another directory is not visible from a command context; a
|
|
268
|
+
* relative path inside such a file resolves against the invocation directory,
|
|
269
|
+
* which is also what the file's author sees the command run from.)
|
|
270
|
+
* Finalization is idempotent — an already-absolute path resolves to itself —
|
|
271
|
+
* so a config that arrived finalized passes through unchanged.
|
|
272
|
+
*/
|
|
273
|
+
function finalizedConfigContext(ctx) {
|
|
274
|
+
if (!isRecord(ctx.config)) return ctx;
|
|
275
|
+
const config = blindCast(ctx.config);
|
|
276
|
+
return {
|
|
277
|
+
...ctx,
|
|
278
|
+
config: finalizeConfig(config, ctx.cwd)
|
|
279
|
+
};
|
|
280
|
+
}
|
|
252
281
|
function defineOrmCommand(def) {
|
|
253
282
|
return defineCommand({
|
|
254
283
|
...def,
|
|
255
284
|
handler: async (args, ctx) => {
|
|
256
285
|
try {
|
|
257
|
-
return await def.handler(args, ctx);
|
|
286
|
+
return await def.handler(args, finalizedConfigContext(ctx));
|
|
258
287
|
} catch (error) {
|
|
259
288
|
if (isInternalError(error)) throw error;
|
|
260
289
|
return notOk$1(normalizeError(error));
|
|
@@ -574,7 +603,7 @@ function mapDbInitFailure(failure) {
|
|
|
574
603
|
if (failure.code === "PLANNING_FAILED") return errorMigrationPlanningFailed({ conflicts: failure.conflicts ?? [] });
|
|
575
604
|
if (failure.code === "MIGRATION.MARKER_ORIGIN_MISMATCH") return errorRuntime("MIGRATION.MARKER_ORIGIN_MISMATCH", `Existing database signature does not match plan destination.${markerMismatchDetail(failure)}`, {
|
|
576
605
|
why: "Database has an existing signature (marker) that does not match the target contract",
|
|
577
|
-
fix: "If bootstrapping, drop/reset the database then re-run `
|
|
606
|
+
fix: "If bootstrapping, drop/reset the database then re-run `{bin} db init`; otherwise reconcile schema/marker using your migration workflow",
|
|
578
607
|
meta: {
|
|
579
608
|
...ifDefined("markerStorageHash", failure.marker?.storageHash),
|
|
580
609
|
...ifDefined("destinationStorageHash", failure.destination?.storageHash),
|
|
@@ -583,7 +612,7 @@ function mapDbInitFailure(failure) {
|
|
|
583
612
|
}
|
|
584
613
|
});
|
|
585
614
|
if (failure.code === "RUNNER_FAILED") {
|
|
586
|
-
const fix = (typeof failure.meta?.["runnerErrorCode"] === "string" ? failure.meta["runnerErrorCode"] : void 0) === "MIGRATION.LEGACY_MARKER_SHAPE" ? "Legacy marker-table shape detected. Drop `prisma_contract.marker` (Postgres) or `_prisma_marker` (SQLite) and re-run `
|
|
615
|
+
const fix = (typeof failure.meta?.["runnerErrorCode"] === "string" ? failure.meta["runnerErrorCode"] : void 0) === "MIGRATION.LEGACY_MARKER_SHAPE" ? "Legacy marker-table shape detected. Drop `prisma_contract.marker` (Postgres) or `_prisma_marker` (SQLite) and re-run `{bin} db init` to recreate it with the current per-space schema." : "Fix the schema mismatch (db init is additive-only), or drop/reset the database and re-run `{bin} db init`";
|
|
587
616
|
return errorRunnerFailed(failure.summary, {
|
|
588
617
|
why: failure.why ?? "Migration runner failed",
|
|
589
618
|
fix,
|
|
@@ -818,7 +847,7 @@ function migrationResultBlocks(result) {
|
|
|
818
847
|
}
|
|
819
848
|
/** Where the user goes next, as typed actions rather than trailing prose. */
|
|
820
849
|
function migrationResultNextActions(result, applyCommand) {
|
|
821
|
-
return result.mode === "plan" ? [runCommandAction("Apply the planned operations", applyCommand)] : [runCommandAction(result.perSpace !== void 0 && result.perSpace.length === 1 ? "Confirm the space is up to date" : "Confirm every space is up to date", "
|
|
850
|
+
return result.mode === "plan" ? [runCommandAction("Apply the planned operations", applyCommand)] : [runCommandAction(result.perSpace !== void 0 && result.perSpace.length === 1 ? "Confirm the space is up to date" : "Confirm every space is up to date", "{bin} migration status")];
|
|
822
851
|
}
|
|
823
852
|
/**
|
|
824
853
|
* Where migrations live for this project. Resolved against the invocation
|
|
@@ -873,7 +902,7 @@ async function readContractDocument(contractPath) {
|
|
|
873
902
|
} catch (error) {
|
|
874
903
|
return notOk$1(normalizeError(Reflect.get(Object(error), "code") === "ENOENT" ? errorFileNotFound(contractPath, {
|
|
875
904
|
why: `Contract file not found at ${contractPath}`,
|
|
876
|
-
fix: "Run `
|
|
905
|
+
fix: "Run `{bin} contract emit` to generate contract.json, or update `contract.output` in prisma.config.ts"
|
|
877
906
|
}) : errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}` })));
|
|
878
907
|
}
|
|
879
908
|
try {
|
|
@@ -939,7 +968,7 @@ function initPresentations$1(inputs) {
|
|
|
939
968
|
]
|
|
940
969
|
}, ...migrationResultBlocks(document)],
|
|
941
970
|
json: () => document,
|
|
942
|
-
next: () => migrationResultNextActions(document, "
|
|
971
|
+
next: () => migrationResultNextActions(document, "{bin} db init")
|
|
943
972
|
};
|
|
944
973
|
}
|
|
945
974
|
function initDocument(inputs) {
|
|
@@ -1271,13 +1300,15 @@ async function readEmittedContract(inputs) {
|
|
|
1271
1300
|
} catch (error) {
|
|
1272
1301
|
return notOk$1(normalizeError(Reflect.get(Object(error), "code") === "ENOENT" ? errorFileNotFound(path, {
|
|
1273
1302
|
why: `Contract file not found at ${path}`,
|
|
1274
|
-
fix: `Run \`
|
|
1303
|
+
fix: `Run \`{bin} contract emit\` to generate ${relativePath}, or update \`contract.output\` in prisma.config.ts`
|
|
1275
1304
|
}) : errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}` })));
|
|
1276
1305
|
}
|
|
1277
1306
|
const familyInstance = inputs.config.family.create(createControlStack(inputs.config));
|
|
1278
1307
|
try {
|
|
1308
|
+
const json = castAs(JSON.parse(content));
|
|
1279
1309
|
return ok$1({
|
|
1280
|
-
contract: familyInstance.deserializeContract(
|
|
1310
|
+
contract: familyInstance.deserializeContract(json),
|
|
1311
|
+
json,
|
|
1281
1312
|
path,
|
|
1282
1313
|
displayPath: relativePath
|
|
1283
1314
|
});
|
|
@@ -1294,7 +1325,7 @@ function requireVerifyConnection(inputs) {
|
|
|
1294
1325
|
if (typeof dbConnection !== "string" || dbConnection.length === 0) return notOk$1(normalizeError(errorDatabaseConnectionRequired({
|
|
1295
1326
|
why: `Database connection is required for ${inputs.invocation} (set db.connection in prisma.config.ts, or pass --db <url>)`,
|
|
1296
1327
|
missingFlags: ["--db"],
|
|
1297
|
-
retryCommand: `
|
|
1328
|
+
retryCommand: `{bin} ${inputs.invocation} --db <url>`
|
|
1298
1329
|
})));
|
|
1299
1330
|
if (inputs.config.driver === void 0) return notOk$1(normalizeError(errorDriverRequired({ why: `Config.driver is required for ${inputs.invocation}` })));
|
|
1300
1331
|
return ok$1(dbConnection);
|
|
@@ -1429,6 +1460,30 @@ function schemaVerdictDiagnostic(inputs) {
|
|
|
1429
1460
|
const FINDINGS_EXIT_CODE$2 = 4;
|
|
1430
1461
|
/** The config file this bin reads; the handler is not told which one was loaded. */
|
|
1431
1462
|
const CONFIG_DISPLAY_PATH = "prisma.config.ts";
|
|
1463
|
+
/**
|
|
1464
|
+
* The ref a signature checkpoints. Unlike `db init` / `db update`, `--db` does
|
|
1465
|
+
* not suppress the write: signing does not touch the schema, and adoption is
|
|
1466
|
+
* normally done against the real database via `--db`. Only `--no-advance-ref`
|
|
1467
|
+
* suppresses it.
|
|
1468
|
+
*/
|
|
1469
|
+
const DEFAULT_ADVANCE_REF = "db";
|
|
1470
|
+
const NO_PREVIOUS_HASH_CODES = /* @__PURE__ */ new Set([
|
|
1471
|
+
"MIGRATION.UNKNOWN_REF",
|
|
1472
|
+
"MIGRATION.INVALID_REF_FILE",
|
|
1473
|
+
"MIGRATION.INVALID_REF_NAME"
|
|
1474
|
+
]);
|
|
1475
|
+
/**
|
|
1476
|
+
* The hash the ref held before the signature, read from that one ref file so a
|
|
1477
|
+
* corrupt sibling cannot fail a signature already written.
|
|
1478
|
+
*/
|
|
1479
|
+
async function previousRefHash(refsDir, name) {
|
|
1480
|
+
try {
|
|
1481
|
+
return (await readRef(refsDir, name)).hash;
|
|
1482
|
+
} catch (error) {
|
|
1483
|
+
if (MigrationToolsError.is(error) && NO_PREVIOUS_HASH_CODES.has(error.code)) return;
|
|
1484
|
+
throw error;
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1432
1487
|
function headerBlock$1(inputs) {
|
|
1433
1488
|
return {
|
|
1434
1489
|
kind: "fields",
|
|
@@ -1442,6 +1497,41 @@ function headerBlock$1(inputs) {
|
|
|
1442
1497
|
}]
|
|
1443
1498
|
};
|
|
1444
1499
|
}
|
|
1500
|
+
function advancedRefSpans(advanced) {
|
|
1501
|
+
return [
|
|
1502
|
+
{ text: `Advanced ref "${advanced.name}" → ` },
|
|
1503
|
+
{
|
|
1504
|
+
text: advanced.hash,
|
|
1505
|
+
tone: "identifier"
|
|
1506
|
+
},
|
|
1507
|
+
...advanced.previousHash === void 0 ? [] : [
|
|
1508
|
+
{
|
|
1509
|
+
text: " (was ",
|
|
1510
|
+
tone: "muted"
|
|
1511
|
+
},
|
|
1512
|
+
{
|
|
1513
|
+
text: advanced.previousHash,
|
|
1514
|
+
tone: "identifier"
|
|
1515
|
+
},
|
|
1516
|
+
{
|
|
1517
|
+
text: ")",
|
|
1518
|
+
tone: "muted"
|
|
1519
|
+
}
|
|
1520
|
+
]
|
|
1521
|
+
];
|
|
1522
|
+
}
|
|
1523
|
+
function refOutcomeBlock(advanced) {
|
|
1524
|
+
return advanced === null ? {
|
|
1525
|
+
kind: "summary",
|
|
1526
|
+
status: "info",
|
|
1527
|
+
tone: "muted",
|
|
1528
|
+
text: `Left ref "${DEFAULT_ADVANCE_REF}" untouched (--no-advance-ref)`
|
|
1529
|
+
} : {
|
|
1530
|
+
kind: "summary",
|
|
1531
|
+
status: "ok",
|
|
1532
|
+
text: advancedRefSpans(advanced)
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1445
1535
|
function signPresentations(inputs) {
|
|
1446
1536
|
const marker = inputs.document.marker;
|
|
1447
1537
|
return {
|
|
@@ -1472,7 +1562,8 @@ function signPresentations(inputs) {
|
|
|
1472
1562
|
tone: "identifier"
|
|
1473
1563
|
}]
|
|
1474
1564
|
}]
|
|
1475
|
-
}
|
|
1565
|
+
},
|
|
1566
|
+
refOutcomeBlock(inputs.advanced)
|
|
1476
1567
|
],
|
|
1477
1568
|
json: () => inputs.document
|
|
1478
1569
|
};
|
|
@@ -1505,12 +1596,14 @@ function createDbSignCommand(createClient = createControlClient) {
|
|
|
1505
1596
|
return defineOrmCommand({
|
|
1506
1597
|
help: {
|
|
1507
1598
|
summary: "Sign the database with your contract so you can safely run queries",
|
|
1508
|
-
description: "Verifies that your database schema satisfies the emitted contract, and if\nso, writes or updates the database signature.
|
|
1599
|
+
description: "Verifies that your database schema satisfies the emitted contract, and if\nso, writes or updates the database signature. The signature records that\nthis database instance is aligned with a specific contract version.\nIdempotent. After signing, the db ref in the checkout is advanced to the\nsigned contract; pass --no-advance-ref to sign without touching any ref,\nwhich is what a CI or deployment pipeline usually wants.\nExit codes: 0 = signed, 2 = the command could not run (unresolvable\ncontract reference, no emitted contract, unreachable database),\n4 = schema verification failed and no signature was written.",
|
|
1509
1600
|
examples: [
|
|
1510
1601
|
"db sign",
|
|
1511
1602
|
"db sign --db $DATABASE_URL",
|
|
1512
1603
|
"db sign production --db $DATABASE_URL",
|
|
1513
|
-
"db sign --contract production --db $DATABASE_URL"
|
|
1604
|
+
"db sign --contract production --db $DATABASE_URL",
|
|
1605
|
+
"db sign --db $DATABASE_URL --advance-ref production",
|
|
1606
|
+
"db sign --db $DATABASE_URL --no-advance-ref"
|
|
1514
1607
|
]
|
|
1515
1608
|
},
|
|
1516
1609
|
args: {
|
|
@@ -1523,7 +1616,12 @@ function createDbSignCommand(createClient = createControlClient) {
|
|
|
1523
1616
|
contract: flag.string({
|
|
1524
1617
|
brief: "Contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)",
|
|
1525
1618
|
placeholder: "contract"
|
|
1526
|
-
})
|
|
1619
|
+
}),
|
|
1620
|
+
advanceRef: flag.string({
|
|
1621
|
+
brief: "Advance the named ref to the post-command contract hash",
|
|
1622
|
+
placeholder: "name"
|
|
1623
|
+
}),
|
|
1624
|
+
noAdvanceRef: flag.boolean({ brief: "Sign without advancing any ref (no ref file or snapshot is written)" })
|
|
1527
1625
|
}
|
|
1528
1626
|
},
|
|
1529
1627
|
needs: { config: ormConfigSection },
|
|
@@ -1536,23 +1634,47 @@ function createDbSignCommand(createClient = createControlClient) {
|
|
|
1536
1634
|
flag: flagContract
|
|
1537
1635
|
})));
|
|
1538
1636
|
const contractRef = positionalContract ?? flagContract;
|
|
1637
|
+
if (args.flags.noAdvanceRef && args.flags.advanceRef !== void 0) return notOk$1(normalizeError(errorAdvanceRefArgConflict({ advanceRef: args.flags.advanceRef })));
|
|
1539
1638
|
const emitted = await readEmittedContract({
|
|
1540
1639
|
config: ctx.config,
|
|
1541
1640
|
cwd: ctx.cwd,
|
|
1542
1641
|
commandName: "db sign"
|
|
1543
1642
|
});
|
|
1544
1643
|
if (!emitted.ok) return notOk$1(emitted.failure);
|
|
1644
|
+
const migrationsDir = migrationsDirFor(ctx.config, ctx.cwd);
|
|
1545
1645
|
let contractInput = emitted.value.contract;
|
|
1646
|
+
let signedSource;
|
|
1546
1647
|
if (contractRef !== void 0) {
|
|
1547
1648
|
const resolvedRef = await resolveContractRefToSnapshot({
|
|
1548
1649
|
config: ctx.config,
|
|
1549
|
-
migrationsDir
|
|
1650
|
+
migrationsDir,
|
|
1550
1651
|
refInput: contractRef,
|
|
1551
1652
|
contractPathAbsolute: emitted.value.path,
|
|
1552
1653
|
fallbackToEmitted: true
|
|
1553
1654
|
});
|
|
1554
1655
|
if (!resolvedRef.ok) return notOk$1(normalizeError(resolvedRef.failure));
|
|
1555
1656
|
contractInput = resolvedRef.value.contractJson;
|
|
1657
|
+
signedSource = {
|
|
1658
|
+
json: resolvedRef.value.contractJson,
|
|
1659
|
+
jsonPath: resolvedRef.value.contractJsonPath
|
|
1660
|
+
};
|
|
1661
|
+
} else signedSource = {
|
|
1662
|
+
json: emitted.value.json,
|
|
1663
|
+
jsonPath: emitted.value.path
|
|
1664
|
+
};
|
|
1665
|
+
const refName = args.flags.noAdvanceRef ? null : args.flags.advanceRef ?? DEFAULT_ADVANCE_REF;
|
|
1666
|
+
let advancement = null;
|
|
1667
|
+
if (refName !== null) {
|
|
1668
|
+
const preflight = await preflightRefAdvancement({
|
|
1669
|
+
name: refName,
|
|
1670
|
+
contractJson: signedSource.json,
|
|
1671
|
+
contractJsonPath: signedSource.jsonPath
|
|
1672
|
+
});
|
|
1673
|
+
if (!preflight.ok) return notOk$1(normalizeError(preflight.failure));
|
|
1674
|
+
advancement = {
|
|
1675
|
+
name: refName,
|
|
1676
|
+
contractIR: preflight.value
|
|
1677
|
+
};
|
|
1556
1678
|
}
|
|
1557
1679
|
const connection = requireVerifyConnection({
|
|
1558
1680
|
config: ctx.config,
|
|
@@ -1588,7 +1710,7 @@ function createDbSignCommand(createClient = createControlClient) {
|
|
|
1588
1710
|
diagnostics: [schemaVerdictDiagnostic({
|
|
1589
1711
|
result: verified,
|
|
1590
1712
|
space: void 0,
|
|
1591
|
-
nextActions: [runCommandAction("Bring the database up to the contract, then sign again", "
|
|
1713
|
+
nextActions: [runCommandAction("Bring the database up to the contract, then sign again", "{bin} db update")]
|
|
1592
1714
|
})]
|
|
1593
1715
|
}, refusedPresentations({
|
|
1594
1716
|
document,
|
|
@@ -1602,11 +1724,43 @@ function createDbSignCommand(createClient = createControlClient) {
|
|
|
1602
1724
|
onProgress
|
|
1603
1725
|
});
|
|
1604
1726
|
if (!signed.ok) throw new InternalError(`The family returned a sign result that did not sign: ${signed.summary}`);
|
|
1727
|
+
if (advancement === null) {
|
|
1728
|
+
const document = {
|
|
1729
|
+
...signed,
|
|
1730
|
+
advancedRef: null
|
|
1731
|
+
};
|
|
1732
|
+
return ok$1(ctx.present({
|
|
1733
|
+
data: document,
|
|
1734
|
+
exitCode: 0
|
|
1735
|
+
}, signPresentations({
|
|
1736
|
+
document,
|
|
1737
|
+
advanced: null,
|
|
1738
|
+
header
|
|
1739
|
+
})));
|
|
1740
|
+
}
|
|
1741
|
+
const refsDir = appRefsDirFor(ctx.config, ctx.cwd);
|
|
1742
|
+
const previousHash = await previousRefHash(refsDir, advancement.name);
|
|
1743
|
+
const advanced = await advanceRefSafely({
|
|
1744
|
+
refsDir,
|
|
1745
|
+
migrationsDir,
|
|
1746
|
+
name: advancement.name,
|
|
1747
|
+
hash: signed.contract.storageHash,
|
|
1748
|
+
contractIR: advancement.contractIR
|
|
1749
|
+
});
|
|
1750
|
+
if (!advanced.ok) return notOk$1(normalizeError(advanced.failure));
|
|
1751
|
+
const document = {
|
|
1752
|
+
...signed,
|
|
1753
|
+
advancedRef: advanced.value
|
|
1754
|
+
};
|
|
1605
1755
|
return ok$1(ctx.present({
|
|
1606
|
-
data:
|
|
1756
|
+
data: document,
|
|
1607
1757
|
exitCode: 0
|
|
1608
1758
|
}, signPresentations({
|
|
1609
|
-
document
|
|
1759
|
+
document,
|
|
1760
|
+
advanced: {
|
|
1761
|
+
...advanced.value,
|
|
1762
|
+
previousHash
|
|
1763
|
+
},
|
|
1610
1764
|
header
|
|
1611
1765
|
})));
|
|
1612
1766
|
} catch (error) {
|
|
@@ -1636,7 +1790,7 @@ const dbSignCommand = createDbSignCommand();
|
|
|
1636
1790
|
function mapDbUpdateFailure(failure) {
|
|
1637
1791
|
if (failure.code === "PLANNING_FAILED") return errorMigrationPlanningFailed({ conflicts: failure.conflicts ?? [] });
|
|
1638
1792
|
if (failure.code === "RUNNER_FAILED") {
|
|
1639
|
-
const fix = (typeof failure.meta?.["runnerErrorCode"] === "string" ? failure.meta["runnerErrorCode"] : void 0) === "MIGRATION.LEGACY_MARKER_SHAPE" ? "Legacy marker-table shape detected. Drop `prisma_contract.marker` (Postgres) or `_prisma_marker` (SQLite) and re-run `
|
|
1793
|
+
const fix = (typeof failure.meta?.["runnerErrorCode"] === "string" ? failure.meta["runnerErrorCode"] : void 0) === "MIGRATION.LEGACY_MARKER_SHAPE" ? "Legacy marker-table shape detected. Drop `prisma_contract.marker` (Postgres) or `_prisma_marker` (SQLite) and re-run `{bin} db init` to recreate it with the current per-space schema." : "Inspect the reported conflict, reconcile schema drift if needed, then re-run `{bin} db update`";
|
|
1640
1794
|
return errorRunnerFailed(failure.summary, {
|
|
1641
1795
|
why: failure.why ?? "Migration runner failed",
|
|
1642
1796
|
fix,
|
|
@@ -1649,7 +1803,7 @@ function mapDbUpdateFailure(failure) {
|
|
|
1649
1803
|
}
|
|
1650
1804
|
if (failure.code === "DESTRUCTIVE_CHANGES") return errorDestructiveChanges(failure.summary, {
|
|
1651
1805
|
...ifDefined("why", failure.why),
|
|
1652
|
-
fix: "Re-run `
|
|
1806
|
+
fix: "Re-run `{bin} db update` and type the database name when asked, or pass `--no-interactive --confirm <database>` where there is nobody to ask. Use `--dry-run` to preview the operations first.",
|
|
1653
1807
|
...failure.destructiveChanges ? { meta: {
|
|
1654
1808
|
destructiveOperations: failure.destructiveChanges.destructiveOperations,
|
|
1655
1809
|
databaseName: failure.destructiveChanges.databaseName,
|
|
@@ -1673,7 +1827,7 @@ function errorConsentTokenUnresolved(targetId) {
|
|
|
1673
1827
|
why: `The connected database reports no name, and the target id "${targetId}" yields none either, so the consent prompt has nothing to ask you to type and the destructive operations cannot be authorised.`,
|
|
1674
1828
|
nextActions: [{
|
|
1675
1829
|
kind: "user-choice",
|
|
1676
|
-
label: "Name the database in `db.connection` (or pass `--db <url>`) and run `
|
|
1830
|
+
label: "Name the database in `db.connection` (or pass `--db <url>`) and run `{bin} db update` again."
|
|
1677
1831
|
}]
|
|
1678
1832
|
});
|
|
1679
1833
|
}
|
|
@@ -1684,7 +1838,7 @@ function errorConsentOperationsMissing() {
|
|
|
1684
1838
|
nextActions: [{
|
|
1685
1839
|
kind: "run-command",
|
|
1686
1840
|
label: "Preview the plan",
|
|
1687
|
-
command: "
|
|
1841
|
+
command: "{bin} db update --dry-run"
|
|
1688
1842
|
}]
|
|
1689
1843
|
});
|
|
1690
1844
|
}
|
|
@@ -1720,7 +1874,7 @@ function updatePresentations(inputs) {
|
|
|
1720
1874
|
]
|
|
1721
1875
|
}, ...migrationResultBlocks(document)],
|
|
1722
1876
|
json: () => document,
|
|
1723
|
-
next: () => migrationResultNextActions(document, "
|
|
1877
|
+
next: () => migrationResultNextActions(document, "{bin} db update")
|
|
1724
1878
|
};
|
|
1725
1879
|
}
|
|
1726
1880
|
function updateDocument(inputs) {
|
|
@@ -1953,7 +2107,7 @@ function combineVerifyResults(perSpace, appSpaceId, strict, unclaimed) {
|
|
|
1953
2107
|
* diagnostics rather than an error.
|
|
1954
2108
|
*/
|
|
1955
2109
|
const FINDINGS_EXIT_CODE$1 = 4;
|
|
1956
|
-
const PUSH_THE_CONTRACT = runCommandAction("Push the contract to the database", "
|
|
2110
|
+
const PUSH_THE_CONTRACT = runCommandAction("Push the contract to the database", "{bin} db update");
|
|
1957
2111
|
const RECONCILE_BY_HAND = {
|
|
1958
2112
|
kind: "user-choice",
|
|
1959
2113
|
label: "Or reconcile the differences by hand and verify again"
|
|
@@ -2470,7 +2624,7 @@ function createFormatCommand(execute = executeFormat) {
|
|
|
2470
2624
|
help: {
|
|
2471
2625
|
summary: "Format your PSL contract source",
|
|
2472
2626
|
description: "Formats the Prisma schema (PSL) contract source declared in your config\n(contract.source.inputs[0]) in place. Only runs when contract.source.format\nis 'psl'; a TypeScript or unset source is left untouched. Indent and newline\nare read from the optional formatter config section, defaulting to two\nspaces and the system newline.",
|
|
2473
|
-
examples: ["format", "format --json"]
|
|
2627
|
+
examples: ["contract format", "contract format --json"]
|
|
2474
2628
|
},
|
|
2475
2629
|
needs: { config: ormConfigSection },
|
|
2476
2630
|
handler: async (_args, ctx) => {
|
|
@@ -2499,8 +2653,8 @@ const formatCommand = createFormatCommand();
|
|
|
2499
2653
|
*
|
|
2500
2654
|
* - We only inspect the unnamed top-level `catalog:` block. pnpm also
|
|
2501
2655
|
* supports `catalogs:` (plural — *named* catalogs referenced via
|
|
2502
|
-
* `catalog:foo` specifiers); those don't apply to
|
|
2503
|
-
* `pnpm add
|
|
2656
|
+
* `catalog:foo` specifiers); those don't apply to the vanilla
|
|
2657
|
+
* `pnpm add` invocations `init` runs, so we skip them.
|
|
2504
2658
|
* - We don't validate YAML syntax exhaustively. The file format pnpm
|
|
2505
2659
|
* ships is line-oriented and well-known; a minimal regex is more
|
|
2506
2660
|
* robust than depending on a YAML parser for one warning.
|
|
@@ -2615,7 +2769,7 @@ function errorInitMissingFlags(options) {
|
|
|
2615
2769
|
}).join(" ");
|
|
2616
2770
|
return new CliStructuredError$1$1("CLI.INIT_MISSING_FLAGS", "Missing required flags", {
|
|
2617
2771
|
why: `${options.why} Missing required flag(s): ${flagList}.`,
|
|
2618
|
-
fix: `Re-run with the missing flag(s) supplied, e.g. \`prisma
|
|
2772
|
+
fix: `Re-run with the missing flag(s) supplied, e.g. \`prisma orm init --yes ${fixList}\`. Use \`prisma orm init --help\` to see every flag.`,
|
|
2619
2773
|
docsUrl: docsUrlFor("CLI.INIT_MISSING_FLAGS"),
|
|
2620
2774
|
meta: { missingFlags: options.missing }
|
|
2621
2775
|
});
|
|
@@ -2657,15 +2811,13 @@ function errorInitAuthoringSchemaPathMismatch(options) {
|
|
|
2657
2811
|
}
|
|
2658
2812
|
/**
|
|
2659
2813
|
* The user cancelled an interactive prompt (Ctrl-C, escape, declined a
|
|
2660
|
-
* selection)
|
|
2661
|
-
* applies to non-interactive mode where the user was never given the
|
|
2662
|
-
* choice; this one is the generic "user said no" path. Maps to exit code
|
|
2814
|
+
* selection) — the generic "user said no" path. Maps to exit code
|
|
2663
2815
|
* 3 (USER_ABORTED).
|
|
2664
2816
|
*/
|
|
2665
2817
|
function errorInitUserAborted() {
|
|
2666
2818
|
return new CliStructuredError$1$1("CLI.INIT_USER_ABORTED", "Init cancelled", {
|
|
2667
2819
|
why: "The interactive prompt was cancelled before all required inputs were supplied. No files were modified.",
|
|
2668
|
-
fix: "Re-run `prisma
|
|
2820
|
+
fix: "Re-run `prisma orm init` and complete the prompts, or pass the required inputs as flags (see `--help`) for a non-interactive run.",
|
|
2669
2821
|
severity: "info"
|
|
2670
2822
|
});
|
|
2671
2823
|
}
|
|
@@ -2698,7 +2850,7 @@ function errorInitStrictProbeWithoutProbe() {
|
|
|
2698
2850
|
function errorInitInvalidManifest(options) {
|
|
2699
2851
|
return new CliStructuredError$1$1("CLI.INIT_INVALID_MANIFEST", `Failed to parse ${options.path}`, {
|
|
2700
2852
|
why: `\`${options.path}\` is not valid JSON: ${options.cause}`,
|
|
2701
|
-
fix: `Fix the JSON syntax in \`${options.path}\` (a missing comma or unbalanced brace is the most common cause), then re-run \`prisma
|
|
2853
|
+
fix: `Fix the JSON syntax in \`${options.path}\` (a missing comma or unbalanced brace is the most common cause), then re-run \`prisma orm init\`.`,
|
|
2702
2854
|
docsUrl: docsUrlFor("CLI.INIT_INVALID_MANIFEST"),
|
|
2703
2855
|
meta: {
|
|
2704
2856
|
path: options.path,
|
|
@@ -2723,7 +2875,7 @@ function errorInitInvalidManifest(options) {
|
|
|
2723
2875
|
function errorInitInvalidTsconfig(options) {
|
|
2724
2876
|
return new CliStructuredError$1$1("CLI.INIT_INVALID_TSCONFIG", `Failed to parse ${options.path}`, {
|
|
2725
2877
|
why: `\`${options.path}\` is not valid JSON or JSONC: ${options.cause}`,
|
|
2726
|
-
fix: `Fix the syntax in \`${options.path}\` and re-run \`prisma
|
|
2878
|
+
fix: `Fix the syntax in \`${options.path}\` and re-run \`prisma orm init\`. \`init\` accepts JSONC (comments and trailing commas) but cannot recover from unbalanced braces or missing commas.`,
|
|
2727
2879
|
docsUrl: docsUrlFor("CLI.INIT_INVALID_TSCONFIG"),
|
|
2728
2880
|
meta: {
|
|
2729
2881
|
path: options.path,
|
|
@@ -2767,7 +2919,7 @@ function errorInitProbeFailed(options) {
|
|
|
2767
2919
|
function errorInitWriteFailed(options) {
|
|
2768
2920
|
return new CliStructuredError$1$1("CLI.INIT_WRITE_FAILED", `Failed to write ${options.path}`, {
|
|
2769
2921
|
why: `\`${options.path}\` could not be written: ${options.cause}`,
|
|
2770
|
-
fix: "Fix what stopped the write — a directory sitting where the file goes, permissions, a full disk — then run `prisma
|
|
2922
|
+
fix: "Fix what stopped the write — a directory sitting where the file goes, permissions, a full disk — then run `prisma orm init` again. Interactive runs ask before replacing the files this run already wrote (listed in `meta.filesWritten`); non-interactive runs grant that consent with `--confirm <directory name>`.",
|
|
2771
2923
|
docsUrl: docsUrlFor("CLI.INIT_WRITE_FAILED"),
|
|
2772
2924
|
meta: {
|
|
2773
2925
|
path: options.path,
|
|
@@ -2811,7 +2963,7 @@ async function probeServerVersion(ctx, overrides = {}) {
|
|
|
2811
2963
|
minVersion,
|
|
2812
2964
|
meetsMinimum: null,
|
|
2813
2965
|
cause: err.message,
|
|
2814
|
-
message: `Skipped --probe-db: ${err.message}. (Run with install enabled, or install the driver yourself, then re-run \`prisma
|
|
2966
|
+
message: `Skipped --probe-db: ${err.message}. (Run with install enabled, or install the driver yourself, then re-run \`prisma orm init --probe-db\`.)`
|
|
2815
2967
|
};
|
|
2816
2968
|
const cause = redactDatabaseUrlSecrets(causeMessage$2(err));
|
|
2817
2969
|
return {
|
|
@@ -2886,9 +3038,9 @@ function redactDatabaseUrlSecrets(text) {
|
|
|
2886
3038
|
return text.replace(/([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)([^/@\s]+)@/g, "$1***@");
|
|
2887
3039
|
}
|
|
2888
3040
|
async function defaultProbePostgres(databaseUrl, baseDir, overrides) {
|
|
2889
|
-
const client = new (requirePeer("pg", baseDir, overrides)).Client({ connectionString: databaseUrl });
|
|
2890
|
-
await client.connect();
|
|
3041
|
+
const client = suppressIdleConnectionErrors(new (requirePeer("pg", baseDir, overrides)).Client({ connectionString: databaseUrl }));
|
|
2891
3042
|
try {
|
|
3043
|
+
await client.connect();
|
|
2892
3044
|
const result = await client.query("SELECT version() as version");
|
|
2893
3045
|
return { serverVersion: parsePostgresVersion(String(result?.rows?.[0]?.version ?? "")) };
|
|
2894
3046
|
} finally {
|
|
@@ -2942,168 +3094,6 @@ function requirePeer(moduleId, baseDir, overrides) {
|
|
|
2942
3094
|
}
|
|
2943
3095
|
}
|
|
2944
3096
|
/**
|
|
2945
|
-
* Default base for the GitHub-URL form `<owner>/<repo>` consumed by
|
|
2946
|
-
* upstream `skills add`. Each `SkillSource` joins this base with its
|
|
2947
|
-
* own subpath (and optional `#ref` for version-pinned clusters).
|
|
2948
|
-
*/
|
|
2949
|
-
const DEFAULT_SKILL_BASE = "prisma/prisma";
|
|
2950
|
-
const DEFAULT_SKILL_SOURCES = [
|
|
2951
|
-
{
|
|
2952
|
-
subpath: "skills",
|
|
2953
|
-
skill: "prisma-8",
|
|
2954
|
-
ref: "cli",
|
|
2955
|
-
description: "usage skill (version-locked to installed Prisma Next)"
|
|
2956
|
-
},
|
|
2957
|
-
{
|
|
2958
|
-
subpath: "skills",
|
|
2959
|
-
skill: "prisma-next-upgrade",
|
|
2960
|
-
ref: null,
|
|
2961
|
-
description: "upgrade skill (always tracks `main`)"
|
|
2962
|
-
},
|
|
2963
|
-
{
|
|
2964
|
-
subpath: "skills",
|
|
2965
|
-
skill: "prisma-8-extension-upgrade",
|
|
2966
|
-
ref: null,
|
|
2967
|
-
description: "extension-author upgrade skill (always tracks `main`)"
|
|
2968
|
-
}
|
|
2969
|
-
];
|
|
2970
|
-
/**
|
|
2971
|
-
* Test-only escape hatch for pinning the install base to a local
|
|
2972
|
-
* checkout. Production runs leave this unset, so installs always use
|
|
2973
|
-
* `DEFAULT_SKILL_BASE`.
|
|
2974
|
-
*
|
|
2975
|
-
* When set to an absolute filesystem path (typical for tests), the
|
|
2976
|
-
* `#ref` fragment is dropped — local-path mode in upstream's CLI does
|
|
2977
|
-
* not accept refs, and the local clone has whatever content the test
|
|
2978
|
-
* checked into it anyway. When set to anything else (e.g. a fork name
|
|
2979
|
-
* `myuser/prisma-next`), the ref policy is preserved.
|
|
2980
|
-
*/
|
|
2981
|
-
function resolveAgentSkillBase(env) {
|
|
2982
|
-
const override = env["PRISMA_NEXT_SKILLS_BASE"]?.trim();
|
|
2983
|
-
return override && override.length > 0 ? override : DEFAULT_SKILL_BASE;
|
|
2984
|
-
}
|
|
2985
|
-
function isLocalPath(base) {
|
|
2986
|
-
return base.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(base);
|
|
2987
|
-
}
|
|
2988
|
-
/**
|
|
2989
|
-
* Agents passed to every project-level init install. Upstream `skills add`
|
|
2990
|
-
* is the source of truth for per-agent install behaviour; the CLI lists
|
|
2991
|
-
* every supported runtime on one invocation and delegates the rest.
|
|
2992
|
-
*/
|
|
2993
|
-
const DEFAULT_SKILL_AGENTS = [
|
|
2994
|
-
"cursor",
|
|
2995
|
-
"claude-code",
|
|
2996
|
-
"codex",
|
|
2997
|
-
"windsurf"
|
|
2998
|
-
];
|
|
2999
|
-
/**
|
|
3000
|
-
* Build the `<base>/<subpath>[#ref]` URL the `skills` CLI will
|
|
3001
|
-
* resolve. Exported for unit tests so the per-source format can be
|
|
3002
|
-
* asserted without going through the full install loop.
|
|
3003
|
-
*/
|
|
3004
|
-
function formatSkillSourceUrl(source, env = process.env) {
|
|
3005
|
-
const base = resolveAgentSkillBase(env);
|
|
3006
|
-
const url = `${base}/${source.subpath}`;
|
|
3007
|
-
if (source.ref === null) return url;
|
|
3008
|
-
if (isLocalPath(base)) return url;
|
|
3009
|
-
if (source.ref === "cli") return `${url}#v${version}`;
|
|
3010
|
-
return url;
|
|
3011
|
-
}
|
|
3012
|
-
/**
|
|
3013
|
-
* The skill-install command for one source, formatted for the
|
|
3014
|
-
* project's detected package manager. `npx`/`pnpm dlx`/`bunx` are
|
|
3015
|
-
* interchangeable to the user; we pick the variant that matches the
|
|
3016
|
-
* rest of the install step so a single project consistently uses one
|
|
3017
|
-
* runner.
|
|
3018
|
-
*
|
|
3019
|
-
* `--agent` takes space-separated slugs on one flag; the explicit
|
|
3020
|
-
* `--skill <name>` and `-y` skip the multi-select prompts a
|
|
3021
|
-
* non-interactive scaffold step cannot show.
|
|
3022
|
-
*
|
|
3023
|
-
* Exported for unit tests so the per-PM dispatch can be asserted
|
|
3024
|
-
* without a live subprocess.
|
|
3025
|
-
*/
|
|
3026
|
-
function formatSkillInstallCommand(args) {
|
|
3027
|
-
const agents = args.agents ?? DEFAULT_SKILL_AGENTS;
|
|
3028
|
-
const cliArgs = [
|
|
3029
|
-
"skills@latest",
|
|
3030
|
-
"add",
|
|
3031
|
-
formatSkillSourceUrl(args.source, args.env),
|
|
3032
|
-
"--agent",
|
|
3033
|
-
...agents,
|
|
3034
|
-
"--skill",
|
|
3035
|
-
args.source.skill,
|
|
3036
|
-
"-y"
|
|
3037
|
-
];
|
|
3038
|
-
return formatPackageManagerCommand(args.pm, cliArgs);
|
|
3039
|
-
}
|
|
3040
|
-
/**
|
|
3041
|
-
* Ordered skill-install commands for one init run. This is both what the
|
|
3042
|
-
* commander shell runs and what either shell tells the user to run when the
|
|
3043
|
-
* install is skipped or fails — the commands need no scaffold and no `init`.
|
|
3044
|
-
*/
|
|
3045
|
-
function resolveProjectSkillInstallCommands(pm, env) {
|
|
3046
|
-
return DEFAULT_SKILL_SOURCES.map((source) => formatSkillInstallCommand({
|
|
3047
|
-
pm,
|
|
3048
|
-
source,
|
|
3049
|
-
...ifDefined("env", env)
|
|
3050
|
-
}));
|
|
3051
|
-
}
|
|
3052
|
-
function formatPackageManagerCommand(pm, args) {
|
|
3053
|
-
switch (pm) {
|
|
3054
|
-
case "pnpm": return `pnpm dlx ${args.join(" ")}`;
|
|
3055
|
-
case "yarn": return `yarn dlx ${args.join(" ")}`;
|
|
3056
|
-
case "bun": return `bunx ${args.join(" ")}`;
|
|
3057
|
-
case "deno": return `deno run -A npm:${args.join(" ")}`;
|
|
3058
|
-
case "npm": return `npx ${args.join(" ")}`;
|
|
3059
|
-
}
|
|
3060
|
-
}
|
|
3061
|
-
/**
|
|
3062
|
-
* Skill directories that predate the consolidated `prisma-8` skill:
|
|
3063
|
-
* the per-workflow usage cluster (including the renamed
|
|
3064
|
-
* `prisma-8-migration-review` spelling it briefly shipped under), the
|
|
3065
|
-
* pre-rename spellings of the consolidated skill and the
|
|
3066
|
-
* extension-author upgrade skill, and any hand-rolled `prisma-next`
|
|
3067
|
-
* stub. Projects initialised before the consolidation carry these as
|
|
3068
|
-
* sibling directories in each agent's install root; left in place
|
|
3069
|
-
* they compete with the current skills for activation, so init
|
|
3070
|
-
* removes them on every run.
|
|
3071
|
-
*/
|
|
3072
|
-
const RETIRED_SKILL_NAMES = [
|
|
3073
|
-
"prisma-next",
|
|
3074
|
-
"prisma-next-quickstart",
|
|
3075
|
-
"prisma-next-contract",
|
|
3076
|
-
"prisma-next-migrations",
|
|
3077
|
-
"prisma-next-migration-review",
|
|
3078
|
-
"prisma-8-migration-review",
|
|
3079
|
-
"prisma-next-queries",
|
|
3080
|
-
"prisma-next-runtime",
|
|
3081
|
-
"prisma-next-build",
|
|
3082
|
-
"prisma-next-supabase",
|
|
3083
|
-
"prisma-next-debug",
|
|
3084
|
-
"prisma-next-feedback",
|
|
3085
|
-
"prisma-next-extension-upgrade"
|
|
3086
|
-
];
|
|
3087
|
-
/**
|
|
3088
|
-
* Project-level install roots the upstream `skills` CLI uses for the
|
|
3089
|
-
* agents in `DEFAULT_SKILL_AGENTS`: cursor and codex install into
|
|
3090
|
-
* `.agents/skills`, claude-code into `.claude/skills`, windsurf into
|
|
3091
|
-
* `.windsurf/skills`.
|
|
3092
|
-
*/
|
|
3093
|
-
const AGENT_SKILL_ROOTS = [
|
|
3094
|
-
".agents/skills",
|
|
3095
|
-
".claude/skills",
|
|
3096
|
-
".windsurf/skills"
|
|
3097
|
-
];
|
|
3098
|
-
/**
|
|
3099
|
-
* Every directory a retired per-workflow skill may occupy in a
|
|
3100
|
-
* consumer project. Init deletes each (recursively) before running the
|
|
3101
|
-
* skill install.
|
|
3102
|
-
*/
|
|
3103
|
-
function legacySkillDirs() {
|
|
3104
|
-
return AGENT_SKILL_ROOTS.flatMap((root) => RETIRED_SKILL_NAMES.map((name) => `${root}/${name}`));
|
|
3105
|
-
}
|
|
3106
|
-
/**
|
|
3107
3097
|
* The resolver a scaffold for `target` is written against.
|
|
3108
3098
|
*
|
|
3109
3099
|
* A scaffold is always on the facade root: `init` writes an application around
|
|
@@ -3155,13 +3145,13 @@ function starterSchema(target, authoring, resolveImportSpecifier = keepInternalS
|
|
|
3155
3145
|
return target === "mongo" ? starterSchemaPslMongo() : starterSchemaPslPostgres();
|
|
3156
3146
|
}
|
|
3157
3147
|
/**
|
|
3158
|
-
* Renders a short authoring-appropriate schema sample
|
|
3159
|
-
*
|
|
3148
|
+
* Renders a short authoring-appropriate schema sample for embedding in
|
|
3149
|
+
* `prisma-8.md`. Returns a complete fenced markdown code block.
|
|
3160
3150
|
*
|
|
3161
3151
|
* The sample intentionally shows just one model: it's illustrative, not
|
|
3162
3152
|
* a substitute for the full scaffolded contract file. The TS samples use
|
|
3163
|
-
* the same outer shape as `starterSchemaTs*`
|
|
3164
|
-
* the
|
|
3153
|
+
* the same outer shape as `starterSchemaTs*` so a user reading the doc and
|
|
3154
|
+
* the file side-by-side sees the same structure.
|
|
3165
3155
|
*/
|
|
3166
3156
|
function schemaSample(target, authoring, resolveImportSpecifier = keepInternalSpecifiers) {
|
|
3167
3157
|
if (authoring === "typescript") {
|
|
@@ -3235,7 +3225,7 @@ export const contract = defineContract(
|
|
|
3235
3225
|
\`\`\``;
|
|
3236
3226
|
}
|
|
3237
3227
|
function starterSchemaPslPostgres() {
|
|
3238
|
-
return `// use prisma-
|
|
3228
|
+
return `// use prisma-8
|
|
3239
3229
|
|
|
3240
3230
|
model User {
|
|
3241
3231
|
id Int @id @default(autoincrement())
|
|
@@ -3243,8 +3233,8 @@ model User {
|
|
|
3243
3233
|
username String?
|
|
3244
3234
|
name String?
|
|
3245
3235
|
posts Post[]
|
|
3246
|
-
createdAt
|
|
3247
|
-
updatedAt temporal.
|
|
3236
|
+
createdAt TimestamptzString @default(now())
|
|
3237
|
+
updatedAt temporal.updatedAtString()
|
|
3248
3238
|
}
|
|
3249
3239
|
|
|
3250
3240
|
model Post {
|
|
@@ -3253,13 +3243,13 @@ model Post {
|
|
|
3253
3243
|
content String?
|
|
3254
3244
|
author User @relation(fields: [authorId], references: [id])
|
|
3255
3245
|
authorId Int
|
|
3256
|
-
createdAt
|
|
3257
|
-
updatedAt temporal.
|
|
3246
|
+
createdAt TimestamptzString @default(now())
|
|
3247
|
+
updatedAt temporal.updatedAtString()
|
|
3258
3248
|
}
|
|
3259
3249
|
`;
|
|
3260
3250
|
}
|
|
3261
3251
|
function starterSchemaPslMongo() {
|
|
3262
|
-
return `// use prisma-
|
|
3252
|
+
return `// use prisma-8
|
|
3263
3253
|
|
|
3264
3254
|
model User {
|
|
3265
3255
|
id ObjectId @id @map("_id")
|
|
@@ -3283,40 +3273,40 @@ model Post {
|
|
|
3283
3273
|
function starterSchemaTsPostgres(builder) {
|
|
3284
3274
|
return `import { defineContract } from '${builder}';
|
|
3285
3275
|
|
|
3286
|
-
export const contract = defineContract(
|
|
3287
|
-
{
|
|
3288
|
-
|
|
3276
|
+
export const contract = defineContract({}, ({ field, model, rel }) => {
|
|
3277
|
+
const User = model('User', {
|
|
3278
|
+
fields: {
|
|
3279
|
+
id: field.id.uuidv7String(),
|
|
3280
|
+
email: field.text().unique(),
|
|
3281
|
+
username: field.text().optional(),
|
|
3282
|
+
name: field.text().optional(),
|
|
3283
|
+
createdAt: field.temporal.createdAtString(),
|
|
3284
|
+
updatedAt: field.temporal.updatedAtString(),
|
|
3285
|
+
},
|
|
3286
|
+
});
|
|
3287
|
+
|
|
3288
|
+
const Post = model('Post', {
|
|
3289
|
+
fields: {
|
|
3290
|
+
id: field.id.uuidv7String(),
|
|
3291
|
+
title: field.text(),
|
|
3292
|
+
content: field.text().optional(),
|
|
3293
|
+
authorId: field.uuidString(),
|
|
3294
|
+
createdAt: field.temporal.createdAtString(),
|
|
3295
|
+
updatedAt: field.temporal.updatedAtString(),
|
|
3296
|
+
},
|
|
3297
|
+
});
|
|
3298
|
+
|
|
3299
|
+
return {
|
|
3289
3300
|
models: {
|
|
3290
|
-
User:
|
|
3291
|
-
|
|
3292
|
-
id: field.id.uuidv7String(),
|
|
3293
|
-
email: field.text().unique(),
|
|
3294
|
-
username: field.text().optional(),
|
|
3295
|
-
name: field.text().optional(),
|
|
3296
|
-
createdAt: field.temporal.createdAt(),
|
|
3297
|
-
updatedAt: field.temporal.updatedAt(),
|
|
3298
|
-
},
|
|
3299
|
-
relations: {
|
|
3300
|
-
posts: rel.hasMany('Post', { by: 'authorId' }),
|
|
3301
|
-
},
|
|
3301
|
+
User: User.relations({
|
|
3302
|
+
posts: rel.hasMany(Post, { by: 'authorId' }),
|
|
3302
3303
|
}),
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
fields: {
|
|
3306
|
-
id: field.id.uuidv7String(),
|
|
3307
|
-
title: field.text(),
|
|
3308
|
-
content: field.text().optional(),
|
|
3309
|
-
authorId: field.uuidString(),
|
|
3310
|
-
createdAt: field.temporal.createdAt(),
|
|
3311
|
-
updatedAt: field.temporal.updatedAt(),
|
|
3312
|
-
},
|
|
3313
|
-
relations: {
|
|
3314
|
-
author: rel.belongsTo('User', { from: 'authorId', to: 'id' }),
|
|
3315
|
-
},
|
|
3304
|
+
Post: Post.relations({
|
|
3305
|
+
author: rel.belongsTo(User, { from: 'authorId', to: 'id' }),
|
|
3316
3306
|
}),
|
|
3317
3307
|
},
|
|
3318
|
-
}
|
|
3319
|
-
);
|
|
3308
|
+
};
|
|
3309
|
+
});
|
|
3320
3310
|
`;
|
|
3321
3311
|
}
|
|
3322
3312
|
function starterSchemaTsMongo(builder) {
|
|
@@ -3358,10 +3348,10 @@ export const contract = defineContract(
|
|
|
3358
3348
|
}
|
|
3359
3349
|
function configFile(target, contractPath, resolveImportSpecifier = keepInternalSpecifiers) {
|
|
3360
3350
|
return `import 'dotenv/config';
|
|
3361
|
-
import {
|
|
3351
|
+
import { definePrismaConfig } from '@prisma/cli-engine';
|
|
3362
3352
|
import { defineConfig as ormConfig } from '${targetEntrypoint(target, "config", resolveImportSpecifier)}';
|
|
3363
3353
|
|
|
3364
|
-
export default
|
|
3354
|
+
export default definePrismaConfig({
|
|
3365
3355
|
orm: ormConfig({
|
|
3366
3356
|
contract: ${JSON.stringify(contractPath)},
|
|
3367
3357
|
db: {
|
|
@@ -3373,7 +3363,8 @@ export default defineConfig({
|
|
|
3373
3363
|
}
|
|
3374
3364
|
function dbFile(target, resolveImportSpecifier = keepInternalSpecifiers) {
|
|
3375
3365
|
const runtime = targetEntrypoint(target, "runtime", resolveImportSpecifier);
|
|
3376
|
-
if (target === "postgres") return `import
|
|
3366
|
+
if (target === "postgres") return `import 'dotenv/config';
|
|
3367
|
+
import postgres from '${runtime}';
|
|
3377
3368
|
import type { Contract } from './contract.d';
|
|
3378
3369
|
import contractJson from './contract.json' with { type: 'json' };
|
|
3379
3370
|
|
|
@@ -3382,7 +3373,8 @@ export const db = postgres<Contract>({
|
|
|
3382
3373
|
url: process.env['DATABASE_URL']!,
|
|
3383
3374
|
});
|
|
3384
3375
|
`;
|
|
3385
|
-
return `import
|
|
3376
|
+
return `import 'dotenv/config';
|
|
3377
|
+
import mongo from '${runtime}';
|
|
3386
3378
|
import type { Contract } from './contract.d';
|
|
3387
3379
|
import contractJson from './contract.json' with { type: 'json' };
|
|
3388
3380
|
|
|
@@ -3402,7 +3394,7 @@ export const db = mongo<Contract>({
|
|
|
3402
3394
|
* Bumping a value here in isolation is **not** safe: edit the
|
|
3403
3395
|
* corresponding target package's `package.json` first, then mirror
|
|
3404
3396
|
* here. The scaffold's `.env.example` and the "Requirements" section
|
|
3405
|
-
* of `prisma-
|
|
3397
|
+
* of `prisma-8.md` both read from this constant, so a stale value
|
|
3406
3398
|
* lies to every freshly initialised user.
|
|
3407
3399
|
*/
|
|
3408
3400
|
const MIN_SERVER_VERSION = {
|
|
@@ -3466,7 +3458,7 @@ function envFileContent(target) {
|
|
|
3466
3458
|
return envPlaceholderBody(target);
|
|
3467
3459
|
}
|
|
3468
3460
|
/** The invocation that finishes what a failed `init` phase started. */
|
|
3469
|
-
const EMIT_COMMAND = "prisma
|
|
3461
|
+
const EMIT_COMMAND = "prisma contract emit";
|
|
3470
3462
|
/**
|
|
3471
3463
|
* The command's own record of a phase that failed after the scaffold was
|
|
3472
3464
|
* written. The scaffold is on disk and the run has a result to report, so each
|
|
@@ -3510,22 +3502,6 @@ function emitFailedFinding(cause, filesWritten) {
|
|
|
3510
3502
|
}
|
|
3511
3503
|
});
|
|
3512
3504
|
}
|
|
3513
|
-
/**
|
|
3514
|
-
* An agent-skill install failed; the project itself is complete without it.
|
|
3515
|
-
* The remedy is the skill-install commands themselves, which run against any
|
|
3516
|
-
* directory — advising a re-run of `init` would put the user's schema at risk
|
|
3517
|
-
* to fix something `init` no longer needs to be involved in.
|
|
3518
|
-
*/
|
|
3519
|
-
function skillInstallFailedFinding(failure, filesWritten, skillCommands) {
|
|
3520
|
-
return initFinding("CLI.INIT_SKILL_INSTALL_FAILED", "Failed to install Prisma Next skills", {
|
|
3521
|
-
why: failure.why ?? failure.message,
|
|
3522
|
-
nextActions: [...failure.nextActions, ...skillCommands.map((command) => runCommandAction("Install the Prisma Next skills", command))],
|
|
3523
|
-
meta: {
|
|
3524
|
-
filesWritten,
|
|
3525
|
-
skillInstall: failure.meta ?? {}
|
|
3526
|
-
}
|
|
3527
|
-
});
|
|
3528
|
-
}
|
|
3529
3505
|
function fileNodes(paths) {
|
|
3530
3506
|
return paths.map((path) => ({
|
|
3531
3507
|
label: path,
|
|
@@ -3569,11 +3545,11 @@ function buildInitNextActions(inputs) {
|
|
|
3569
3545
|
kind: "edit-file",
|
|
3570
3546
|
label: `Edit your schema at ${inputs.schemaPath}, then emit again`
|
|
3571
3547
|
});
|
|
3572
|
-
actions.push(chooseAction("Open prisma-
|
|
3573
|
-
|
|
3548
|
+
actions.push(chooseAction("Open prisma-8.md for a quick reference on writing your first typed query"));
|
|
3549
|
+
actions.push(runCommandAction("Set up the Prisma agent skills for your coding agent", "prisma init"));
|
|
3574
3550
|
return actions;
|
|
3575
3551
|
}
|
|
3576
|
-
const DONE_TEXT = "Done. Open prisma-
|
|
3552
|
+
const DONE_TEXT = "Done. Open prisma-8.md to get started.";
|
|
3577
3553
|
const INCOMPLETE_TEXT = "Scaffold written. Finish the steps above to complete setup.";
|
|
3578
3554
|
/**
|
|
3579
3555
|
* `init` writes files rather than data another program reads, so it supplies
|
|
@@ -3634,7 +3610,7 @@ function redactSecrets(stderr) {
|
|
|
3634
3610
|
}
|
|
3635
3611
|
/**
|
|
3636
3612
|
* Emits the contract for the project `init` has just scaffolded, by spawning
|
|
3637
|
-
* the project-local `prisma
|
|
3613
|
+
* the project-local `prisma` binary the install step put into
|
|
3638
3614
|
* `node_modules`. That binary and the installed `defineConfig` come from the
|
|
3639
3615
|
* same registry release, so the config loader that evaluates
|
|
3640
3616
|
* `prisma.config.ts` always matches the config format it was written
|
|
@@ -3652,26 +3628,26 @@ async function emitScaffoldedContract(ctx, overrides = {}) {
|
|
|
3652
3628
|
if (result.exitCode !== 0) {
|
|
3653
3629
|
const output = result.stderr.trim().length > 0 ? result.stderr : result.stdout;
|
|
3654
3630
|
const cause = result.exitCode === null ? `was killed by signal ${result.signal ?? "unknown"}` : `exited with code ${result.exitCode}`;
|
|
3655
|
-
throw new Error(`\`prisma
|
|
3631
|
+
throw new Error(`\`prisma contract emit\` ${cause}: ${redactSecrets(tail(output))}`);
|
|
3656
3632
|
}
|
|
3657
3633
|
}
|
|
3658
3634
|
function resolveProjectBin(cwd, overrides) {
|
|
3659
3635
|
const resolveFromBaseDir = overrides.resolveFromBaseDir ?? ((baseDir, specifier) => createRequire(join(baseDir, "package.json")).resolve(specifier));
|
|
3660
3636
|
let manifestPath;
|
|
3661
3637
|
try {
|
|
3662
|
-
manifestPath = resolveFromBaseDir(cwd, "
|
|
3638
|
+
manifestPath = resolveFromBaseDir(cwd, "prisma/package.json");
|
|
3663
3639
|
} catch (error) {
|
|
3664
|
-
throw new Error(
|
|
3640
|
+
throw new Error(`\`prisma\` is not installed in this project (resolved from ${cwd}; cause: ${causeMessage$1(error)})`);
|
|
3665
3641
|
}
|
|
3666
3642
|
let manifest;
|
|
3667
3643
|
try {
|
|
3668
3644
|
manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
3669
3645
|
} catch (error) {
|
|
3670
|
-
throw new Error(`the installed
|
|
3646
|
+
throw new Error(`the installed prisma manifest at ${manifestPath} is not valid JSON: ${causeMessage$1(error)}`);
|
|
3671
3647
|
}
|
|
3672
3648
|
const bin = manifest !== null && typeof manifest === "object" ? Reflect.get(manifest, "bin") : void 0;
|
|
3673
|
-
const binEntry = typeof bin === "string" ? bin : bin !== null && typeof bin === "object" ? Reflect.get(bin, "prisma
|
|
3674
|
-
if (typeof binEntry !== "string") throw new Error(`the installed
|
|
3649
|
+
const binEntry = typeof bin === "string" ? bin : bin !== null && typeof bin === "object" ? Reflect.get(bin, "prisma") : void 0;
|
|
3650
|
+
if (typeof binEntry !== "string") throw new Error(`the installed prisma package at ${dirname(manifestPath)} declares no \`prisma\` bin`);
|
|
3675
3651
|
return join(dirname(manifestPath), binEntry);
|
|
3676
3652
|
}
|
|
3677
3653
|
function runCaptured(file, args, cwd) {
|
|
@@ -3693,7 +3669,7 @@ function runCaptured(file, args, cwd) {
|
|
|
3693
3669
|
stderr += chunk.toString("utf-8");
|
|
3694
3670
|
});
|
|
3695
3671
|
child.on("error", (error) => {
|
|
3696
|
-
reject(/* @__PURE__ */ new Error(`could not run the project-local prisma
|
|
3672
|
+
reject(/* @__PURE__ */ new Error(`could not run the project-local prisma binary: ${error.message}`));
|
|
3697
3673
|
});
|
|
3698
3674
|
child.on("close", (code, signal) => {
|
|
3699
3675
|
resolve({
|
|
@@ -3791,7 +3767,7 @@ function formatRunScriptCommand(pm, scriptName) {
|
|
|
3791
3767
|
* [`.gitattributes`](../../../../../../../../.gitattributes):
|
|
3792
3768
|
*
|
|
3793
3769
|
* - **Today**: `contract.json`, `contract.d.ts` are emitted on every
|
|
3794
|
-
* `prisma
|
|
3770
|
+
* `prisma contract emit`. Marking them `linguist-generated`
|
|
3795
3771
|
* keeps GitHub's diff stats honest and collapses the file in code
|
|
3796
3772
|
* review by default.
|
|
3797
3773
|
* - **Forward-looking**: `ops.json`, `migration.json` are not yet emitted
|
|
@@ -3863,7 +3839,7 @@ function mergeGitattributes(existing, required) {
|
|
|
3863
3839
|
return `${existing}${existing.length === 0 || existing.endsWith("\n") ? "" : "\n"}${missing.join("\n")}\n`;
|
|
3864
3840
|
}
|
|
3865
3841
|
/**
|
|
3866
|
-
* The minimal `.gitignore` lines a Prisma
|
|
3842
|
+
* The minimal `.gitignore` lines a Prisma ORM scaffold needs (FR3.3).
|
|
3867
3843
|
* Order matches what Node tooling typically writes today.
|
|
3868
3844
|
*
|
|
3869
3845
|
* `node_modules/` first because it's the byte-largest miss; `dist/`
|
|
@@ -3902,7 +3878,7 @@ function mergeGitignore(existing) {
|
|
|
3902
3878
|
}
|
|
3903
3879
|
const REQUIRED_SCRIPTS = [{
|
|
3904
3880
|
name: "contract:emit",
|
|
3905
|
-
command: "prisma
|
|
3881
|
+
command: "prisma contract emit"
|
|
3906
3882
|
}];
|
|
3907
3883
|
/**
|
|
3908
3884
|
* Idempotent `package.json#scripts` merge with collision detection
|
|
@@ -3937,7 +3913,7 @@ function mergePackageScripts(existing, required = REQUIRED_SCRIPTS) {
|
|
|
3937
3913
|
mutated = true;
|
|
3938
3914
|
continue;
|
|
3939
3915
|
}
|
|
3940
|
-
if (existingValue !== command) warnings.push(`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\`.`);
|
|
3916
|
+
if (existingValue !== command) warnings.push(`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 \`orm init\`.`);
|
|
3941
3917
|
}
|
|
3942
3918
|
if (!mutated) return {
|
|
3943
3919
|
content: null,
|
|
@@ -4073,6 +4049,51 @@ function removeDependency(existing, depName) {
|
|
|
4073
4049
|
const trailingNewline = existing.endsWith("\n") ? "\n" : "";
|
|
4074
4050
|
return `${JSON.stringify(parsed, null, 2)}${trailingNewline}`;
|
|
4075
4051
|
}
|
|
4052
|
+
/**
|
|
4053
|
+
* Skill directories that predate the consolidated `prisma-8` skill: the
|
|
4054
|
+
* per-workflow usage cluster (including the renamed
|
|
4055
|
+
* `prisma-8-migration-review` spelling it briefly shipped under), the
|
|
4056
|
+
* pre-rename spellings of the consolidated skill and the extension-author
|
|
4057
|
+
* upgrade skill, any hand-rolled `prisma-next` stub, and the two standalone
|
|
4058
|
+
* upgrade skills that folded into the `prisma-8` router. Projects initialised
|
|
4059
|
+
* before those changes carry these as sibling directories in each agent's
|
|
4060
|
+
* install root; left in place they compete with the current skill for
|
|
4061
|
+
* activation, so init removes them on every run.
|
|
4062
|
+
*/
|
|
4063
|
+
const RETIRED_SKILL_NAMES = [
|
|
4064
|
+
"prisma-next",
|
|
4065
|
+
"prisma-next-quickstart",
|
|
4066
|
+
"prisma-next-contract",
|
|
4067
|
+
"prisma-next-migrations",
|
|
4068
|
+
"prisma-next-migration-review",
|
|
4069
|
+
"prisma-8-migration-review",
|
|
4070
|
+
"prisma-next-queries",
|
|
4071
|
+
"prisma-next-runtime",
|
|
4072
|
+
"prisma-next-build",
|
|
4073
|
+
"prisma-next-supabase",
|
|
4074
|
+
"prisma-next-debug",
|
|
4075
|
+
"prisma-next-feedback",
|
|
4076
|
+
"prisma-next-extension-upgrade",
|
|
4077
|
+
"prisma-next-upgrade",
|
|
4078
|
+
"prisma-8-extension-upgrade"
|
|
4079
|
+
];
|
|
4080
|
+
/**
|
|
4081
|
+
* The project-level skill directories the agent harnesses read: Claude Code,
|
|
4082
|
+
* Cursor, Codex (`.agents`), and Windsurf.
|
|
4083
|
+
*/
|
|
4084
|
+
const AGENT_SKILL_ROOTS = [
|
|
4085
|
+
".claude/skills",
|
|
4086
|
+
".cursor/skills",
|
|
4087
|
+
".agents/skills",
|
|
4088
|
+
".windsurf/skills"
|
|
4089
|
+
];
|
|
4090
|
+
/**
|
|
4091
|
+
* Every directory a retired skill may occupy in a consumer project. Init
|
|
4092
|
+
* deletes each (recursively) on every run.
|
|
4093
|
+
*/
|
|
4094
|
+
function legacySkillDirs() {
|
|
4095
|
+
return AGENT_SKILL_ROOTS.flatMap((root) => RETIRED_SKILL_NAMES.map((name) => `${root}/${name}`));
|
|
4096
|
+
}
|
|
4076
4097
|
function renderTemplate(templateFile, variableNames, vars) {
|
|
4077
4098
|
let result = readFileSync(join(import.meta.dirname, templateFile), "utf-8");
|
|
4078
4099
|
for (const key of variableNames) {
|
|
@@ -4103,12 +4124,12 @@ function quickReferenceMd(target, authoring, schemaPath, pkgRun, resolveImportSp
|
|
|
4103
4124
|
pkg,
|
|
4104
4125
|
configEntrypoint: targetEntrypoint(target, "config", resolveImportSpecifier),
|
|
4105
4126
|
schemaSample: schemaSample(target, authoring, resolveImportSpecifier),
|
|
4106
|
-
requirements: requirementsBlock(target)
|
|
4127
|
+
requirements: requirementsBlock(target, pkgRun)
|
|
4107
4128
|
};
|
|
4108
4129
|
return renderTemplate(`quick-reference-${target}.md`, variables, vars);
|
|
4109
4130
|
}
|
|
4110
4131
|
/**
|
|
4111
|
-
* Renders the FR8.2 "Requirements" block injected into `prisma-
|
|
4132
|
+
* Renders the FR8.2 "Requirements" block injected into `prisma-8.md`
|
|
4112
4133
|
* (the user-facing quick reference). Sources the minimum server
|
|
4113
4134
|
* version from `MIN_SERVER_VERSION` — itself mirrored from each
|
|
4114
4135
|
* target package's `package.json#prismaNext.minServerVersion`
|
|
@@ -4118,12 +4139,12 @@ function quickReferenceMd(target, authoring, schemaPath, pkgRun, resolveImportSp
|
|
|
4118
4139
|
* shouldn't ship Mongo's `db.runCommand` (and vice versa) just because
|
|
4119
4140
|
* we couldn't be bothered to branch.
|
|
4120
4141
|
*/
|
|
4121
|
-
function requirementsBlock(target) {
|
|
4142
|
+
function requirementsBlock(target, pkgRun) {
|
|
4122
4143
|
return [
|
|
4123
4144
|
"## Requirements",
|
|
4124
4145
|
"",
|
|
4125
4146
|
`- **${TARGET_LABEL[target]} ${MIN_SERVER_VERSION[target]} or newer.** Older servers are not supported. Run ${target === "postgres" ? "`SELECT version()`" : "`db.runCommand({ buildInfo: 1 })`"} against your server to verify.`,
|
|
4126
|
-
|
|
4147
|
+
`- The CLI never connects to your database without explicit consent. Pass \`--probe-db\` to \`${pkgRun} orm init\` if you want \`init\` to verify the server version itself.`
|
|
4127
4148
|
].join("\n");
|
|
4128
4149
|
}
|
|
4129
4150
|
const sharedVariables = [
|
|
@@ -4317,7 +4338,7 @@ function mergeTypesArray(existing) {
|
|
|
4317
4338
|
return result;
|
|
4318
4339
|
}
|
|
4319
4340
|
const CONFIG_FILE = "prisma.config.ts";
|
|
4320
|
-
const QUICK_REFERENCE_FILE = "prisma-
|
|
4341
|
+
const QUICK_REFERENCE_FILE = "prisma-8.md";
|
|
4321
4342
|
const ENV_EXAMPLE_FILE = ".env.example";
|
|
4322
4343
|
/**
|
|
4323
4344
|
* The generated files a run replaces outright, in the order it writes them.
|
|
@@ -4326,7 +4347,7 @@ const ENV_EXAMPLE_FILE = ".env.example";
|
|
|
4326
4347
|
* one of these is the destructive act consent is asked for.
|
|
4327
4348
|
*
|
|
4328
4349
|
* `.env.example` is written the same way but deliberately left out: it is a
|
|
4329
|
-
* conventional filename in projects that have never seen Prisma
|
|
4350
|
+
* conventional filename in projects that have never seen Prisma ORM, and a
|
|
4330
4351
|
* consent token demanded for it would fire on first runs. The scaffold warns
|
|
4331
4352
|
* when it replaces one instead.
|
|
4332
4353
|
*/
|
|
@@ -4408,7 +4429,7 @@ function planScaffold(ctx) {
|
|
|
4408
4429
|
const warnings = [];
|
|
4409
4430
|
const schemaDir = dirname(inputs.schemaPath);
|
|
4410
4431
|
const configContractPath = isAbsolute(inputs.schemaPath) ? inputs.schemaPath : `./${inputs.schemaPath}`;
|
|
4411
|
-
const runPrefix = formatRunCommand(packageManager, "prisma
|
|
4432
|
+
const runPrefix = formatRunCommand(packageManager, "prisma", "").trimEnd();
|
|
4412
4433
|
const files = [
|
|
4413
4434
|
{
|
|
4414
4435
|
path: inputs.schemaPath,
|
|
@@ -4431,7 +4452,7 @@ function planScaffold(ctx) {
|
|
|
4431
4452
|
content: envExampleContent(inputs.target)
|
|
4432
4453
|
}
|
|
4433
4454
|
];
|
|
4434
|
-
if (existsSync(join(cwd, ENV_EXAMPLE_FILE))) warnings.push(`${ENV_EXAMPLE_FILE} already existed and was replaced with the Prisma
|
|
4455
|
+
if (existsSync(join(cwd, ENV_EXAMPLE_FILE))) warnings.push(`${ENV_EXAMPLE_FILE} already existed and was replaced with the Prisma ORM template.`);
|
|
4435
4456
|
const filesToDelete = inputs.reinit ? [...findStaleArtifacts(cwd, schemaDir)] : [];
|
|
4436
4457
|
const dirsToDelete = legacySkillDirs().filter((rel) => existsSync(join(cwd, rel)));
|
|
4437
4458
|
if (inputs.writeEnv) if (existsSync(join(cwd, ".env"))) warnings.push(".env already exists; leaving it untouched. Compare with .env.example for any new keys.");
|
|
@@ -4497,7 +4518,7 @@ function planScaffold(ctx) {
|
|
|
4497
4518
|
changed = true;
|
|
4498
4519
|
}
|
|
4499
4520
|
}
|
|
4500
|
-
const { content: withScripts, warnings: scriptWarnings } = mergePackageScripts(working
|
|
4521
|
+
const { content: withScripts, warnings: scriptWarnings } = mergePackageScripts(working);
|
|
4501
4522
|
if (withScripts !== null) {
|
|
4502
4523
|
working = withScripts;
|
|
4503
4524
|
changed = true;
|
|
@@ -4728,8 +4749,7 @@ async function resolveInitInputs(ctx) {
|
|
|
4728
4749
|
probeDb: flags.probeDb,
|
|
4729
4750
|
strictProbe: flags.strictProbe,
|
|
4730
4751
|
reinit,
|
|
4731
|
-
removePreviousFacade
|
|
4732
|
-
installProjectSkill: !flags.skipSkills
|
|
4752
|
+
removePreviousFacade
|
|
4733
4753
|
};
|
|
4734
4754
|
}
|
|
4735
4755
|
/**
|
|
@@ -4770,7 +4790,7 @@ function pnpmLeakedASpecifier(failure) {
|
|
|
4770
4790
|
function fallbackWarning(failure) {
|
|
4771
4791
|
const firstLine = redactSecrets(metaString(failure, "stderrTail")).trim().split("\n")[0] ?? "";
|
|
4772
4792
|
return [
|
|
4773
|
-
"pnpm could not install: a published Prisma
|
|
4793
|
+
"pnpm could not install: a published Prisma ORM dependency leaked a `workspace:*` or `catalog:` specifier.",
|
|
4774
4794
|
"Falling back to npm so init can complete.",
|
|
4775
4795
|
firstLine === "" ? "" : ` pnpm error: ${firstLine}`,
|
|
4776
4796
|
"Both installs ran under npm, which writes a package-lock.json beside the pnpm lockfile — delete whichever of the two you do not want to keep.",
|
|
@@ -4788,6 +4808,28 @@ function retriedWarning(failure) {
|
|
|
4788
4808
|
* command, and this decides — from the stderr it returned — that another
|
|
4789
4809
|
* manager is worth a try.
|
|
4790
4810
|
*/
|
|
4811
|
+
/**
|
|
4812
|
+
* The engine dependency spec a fresh scaffold installs. The scaffolded
|
|
4813
|
+
* `prisma.config.ts` imports `defineConfig` from `@prisma/cli-engine`, and the
|
|
4814
|
+
* installed `prisma` names the exact engine version it runs against — so
|
|
4815
|
+
* the spec is read from the manifest the install just placed, never guessed
|
|
4816
|
+
* from a dist-tag (whose `latest` has lagged that version before and broken
|
|
4817
|
+
* the very next command). A CLI without a readable engine entry falls back to
|
|
4818
|
+
* the `next` tag, the release train the CLI itself publishes under.
|
|
4819
|
+
*/
|
|
4820
|
+
function engineDevDependencySpec(cwd) {
|
|
4821
|
+
try {
|
|
4822
|
+
const manifest = JSON.parse(readFileSync(join(cwd, "node_modules", "prisma", "package.json"), "utf-8"));
|
|
4823
|
+
if (typeof manifest === "object" && manifest !== null) for (const field of ["dependencies", "peerDependencies"]) {
|
|
4824
|
+
const block = Reflect.get(manifest, field);
|
|
4825
|
+
if (typeof block === "object" && block !== null) {
|
|
4826
|
+
const engine = Reflect.get(block, "@prisma/cli-engine");
|
|
4827
|
+
if (typeof engine === "string" && engine.length > 0) return `@prisma/cli-engine@${engine}`;
|
|
4828
|
+
}
|
|
4829
|
+
}
|
|
4830
|
+
} catch {}
|
|
4831
|
+
return "@prisma/cli-engine@latest";
|
|
4832
|
+
}
|
|
4791
4833
|
async function installProjectDependencies(ctx) {
|
|
4792
4834
|
const pair = async (manager) => {
|
|
4793
4835
|
const runtimeDeps = await ctx.packages.install({
|
|
@@ -4827,38 +4869,10 @@ async function installProjectDependencies(ctx) {
|
|
|
4827
4869
|
warnings: [fallbackWarning(failure)]
|
|
4828
4870
|
};
|
|
4829
4871
|
}
|
|
4830
|
-
function skillArgs(url, skill) {
|
|
4831
|
-
return [
|
|
4832
|
-
"add",
|
|
4833
|
-
url,
|
|
4834
|
-
"--agent",
|
|
4835
|
-
...DEFAULT_SKILL_AGENTS,
|
|
4836
|
-
"--skill",
|
|
4837
|
-
skill,
|
|
4838
|
-
"-y"
|
|
4839
|
-
];
|
|
4840
|
-
}
|
|
4841
|
-
/**
|
|
4842
|
-
* Registers every Prisma Next skill with the agent runtimes, in order. The
|
|
4843
|
-
* first failure stops the loop: the user opted into Prisma Next by running
|
|
4844
|
-
* `init`, and a half-installed skill set leaves the project ambiguous.
|
|
4845
|
-
*/
|
|
4846
|
-
async function installAgentSkills(ctx) {
|
|
4847
|
-
for (const source of DEFAULT_SKILL_SOURCES) {
|
|
4848
|
-
const result = await ctx.packages.run({
|
|
4849
|
-
package: "skills@latest",
|
|
4850
|
-
args: skillArgs(formatSkillSourceUrl(source, ctx.env), source.skill),
|
|
4851
|
-
cwd: ctx.cwd,
|
|
4852
|
-
...ifDefined("manager", ctx.manager)
|
|
4853
|
-
});
|
|
4854
|
-
if (!result.ok) return result.failure;
|
|
4855
|
-
}
|
|
4856
|
-
}
|
|
4857
4872
|
/** The scaffold is on disk from here on, so each of these is a finding. */
|
|
4858
4873
|
const INIT_EXIT_CODES = {
|
|
4859
4874
|
4: "scaffold written; dependency install failed",
|
|
4860
|
-
5: "scaffold written and installed; contract emit failed"
|
|
4861
|
-
6: "scaffold complete; agent-skill install failed"
|
|
4875
|
+
5: "scaffold written and installed; contract emit failed"
|
|
4862
4876
|
};
|
|
4863
4877
|
function probeWarning(outcome, strictProbe) {
|
|
4864
4878
|
switch (outcome.kind) {
|
|
@@ -4886,15 +4900,14 @@ function causeMessage(error) {
|
|
|
4886
4900
|
}
|
|
4887
4901
|
const createInitCommand = (injected) => defineOrmCommand({
|
|
4888
4902
|
help: {
|
|
4889
|
-
summary: "Initialize a new Prisma
|
|
4903
|
+
summary: "Initialize a new Prisma ORM project",
|
|
4890
4904
|
description: "Scaffolds config, schema, and runtime files, installs dependencies,\nand emits the contract. Gets you from zero to typed queries in one step.\n\nRun it interactively for a guided setup, or supply --target and --authoring\nfor a fully scriptable run (CI, AI coding agents, automation).",
|
|
4891
4905
|
examples: [
|
|
4892
|
-
"init",
|
|
4893
|
-
"init --target postgres --authoring psl",
|
|
4894
|
-
"init --target mongodb --authoring typescript --json",
|
|
4895
|
-
"init --skip-install",
|
|
4896
|
-
"init --
|
|
4897
|
-
"init --target postgres --keep-previous-facade"
|
|
4906
|
+
"orm init",
|
|
4907
|
+
"orm init --target postgres --authoring psl",
|
|
4908
|
+
"orm init --target mongodb --authoring typescript --json",
|
|
4909
|
+
"orm init --skip-install",
|
|
4910
|
+
"orm init --target postgres --keep-previous-facade"
|
|
4898
4911
|
]
|
|
4899
4912
|
},
|
|
4900
4913
|
args: { flags: {
|
|
@@ -4914,7 +4927,6 @@ const createInitCommand = (injected) => defineOrmCommand({
|
|
|
4914
4927
|
probeDb: flag.boolean({ brief: "Connect to DATABASE_URL once and check the server version" }),
|
|
4915
4928
|
strictProbe: flag.boolean({ brief: "Treat a failed --probe-db as fatal" }),
|
|
4916
4929
|
skipInstall: flag.boolean({ brief: "Skip dependency installation and contract emission" }),
|
|
4917
|
-
skipSkills: flag.boolean({ brief: "Skip the Prisma Next agent-skill install" }),
|
|
4918
4930
|
keepPreviousFacade: flag.boolean({ brief: "Keep the previous target package in package.json when switching targets" })
|
|
4919
4931
|
} },
|
|
4920
4932
|
exitCodes: INIT_EXIT_CODES,
|
|
@@ -4950,14 +4962,12 @@ const createInitCommand = (injected) => defineOrmCommand({
|
|
|
4950
4962
|
text: note
|
|
4951
4963
|
});
|
|
4952
4964
|
const deps = [targetPackageName(inputs.target, scaffold.resolveImportSpecifier), "dotenv"];
|
|
4953
|
-
const cliDevDeps = ["
|
|
4965
|
+
const cliDevDeps = ["prisma@latest"];
|
|
4954
4966
|
const devDeps = scaffold.hasTypesNode ? cliDevDeps : [...cliDevDeps, "@types/node"];
|
|
4955
4967
|
const findings = [];
|
|
4956
4968
|
const extraActions = [];
|
|
4957
|
-
let installedManager;
|
|
4958
4969
|
let packagesInstalled = "skipped";
|
|
4959
4970
|
let contractEmitted = false;
|
|
4960
|
-
let skillRegistered = false;
|
|
4961
4971
|
const settle = (exitCode) => {
|
|
4962
4972
|
const installed = packagesInstalled === "installed";
|
|
4963
4973
|
const document = {
|
|
@@ -4978,15 +4988,14 @@ const createInitCommand = (injected) => defineOrmCommand({
|
|
|
4978
4988
|
packagesInstalled,
|
|
4979
4989
|
contractEmitted,
|
|
4980
4990
|
emitCommand: EMIT_COMMAND,
|
|
4981
|
-
schemaPath: inputs.schemaPath
|
|
4982
|
-
skillRegistered
|
|
4991
|
+
schemaPath: inputs.schemaPath
|
|
4983
4992
|
}),
|
|
4984
4993
|
warnings
|
|
4985
4994
|
};
|
|
4986
4995
|
const validated = InitOutputSchema(document);
|
|
4987
4996
|
if (validated instanceof type.errors) return notOk$1(new CliStructuredError$1("CLI.INIT_INVALID_OUTPUT_DOCUMENT", "Init produced an invalid output document", {
|
|
4988
4997
|
why: `The success document failed schema validation: ${String(validated)}`,
|
|
4989
|
-
nextActions: [chooseAction("This is a bug in Prisma
|
|
4998
|
+
nextActions: [chooseAction("This is a bug in Prisma ORM. Please report it with `-v` output.")],
|
|
4990
4999
|
docsUrl: docsUrlFor("CLI.INIT_INVALID_OUTPUT_DOCUMENT")
|
|
4991
5000
|
}));
|
|
4992
5001
|
return ok$1(ctx.present({
|
|
@@ -4998,8 +5007,7 @@ const createInitCommand = (injected) => defineOrmCommand({
|
|
|
4998
5007
|
complete: exitCode === 0,
|
|
4999
5008
|
nextActions: [...extraActions, ...buildInitNextActions({
|
|
5000
5009
|
contractEmitted,
|
|
5001
|
-
schemaPath: inputs.schemaPath
|
|
5002
|
-
skillRegistered
|
|
5010
|
+
schemaPath: inputs.schemaPath
|
|
5003
5011
|
})]
|
|
5004
5012
|
})));
|
|
5005
5013
|
};
|
|
@@ -5017,8 +5025,20 @@ const createInitCommand = (injected) => defineOrmCommand({
|
|
|
5017
5025
|
findings.push(installFailedFinding(outcome.failure, scaffold.filesWritten));
|
|
5018
5026
|
return settle(4);
|
|
5019
5027
|
}
|
|
5028
|
+
const engineSpec = engineDevDependencySpec(ctx.cwd);
|
|
5029
|
+
const engineInstall = await ctx.packages.install({
|
|
5030
|
+
packages: [engineSpec],
|
|
5031
|
+
dev: true,
|
|
5032
|
+
cwd: ctx.cwd,
|
|
5033
|
+
...ifDefined("manager", outcome.manager)
|
|
5034
|
+
});
|
|
5035
|
+
if (!engineInstall.ok) {
|
|
5036
|
+
packagesInstalled = "failed";
|
|
5037
|
+
findings.push(installFailedFinding(engineInstall.failure, scaffold.filesWritten));
|
|
5038
|
+
return settle(4);
|
|
5039
|
+
}
|
|
5040
|
+
devDeps.push(engineSpec);
|
|
5020
5041
|
packagesInstalled = "installed";
|
|
5021
|
-
installedManager = outcome.manager;
|
|
5022
5042
|
const emitStep = "Emit the contract";
|
|
5023
5043
|
ctx.report({
|
|
5024
5044
|
kind: "step-started",
|
|
@@ -5041,7 +5061,7 @@ const createInitCommand = (injected) => defineOrmCommand({
|
|
|
5041
5061
|
findings.push(emitFailedFinding(causeMessage(error), scaffold.filesWritten));
|
|
5042
5062
|
return settle(5);
|
|
5043
5063
|
}
|
|
5044
|
-
} else extraActions.push(chooseAction(`Install the project dependencies with your package manager: ${deps.join(", ")} (and ${devDeps.join(", ")} as development dependencies)`));
|
|
5064
|
+
} else extraActions.push(chooseAction(`Install the project dependencies with your package manager: ${deps.join(", ")} (and ${devDeps.join(", ")} plus @prisma/cli-engine at the version prisma declares as its dependency, as development dependencies)`));
|
|
5045
5065
|
if (inputs.probeDb) {
|
|
5046
5066
|
const probe = probeWarning(await probeServerVersion({
|
|
5047
5067
|
baseDir: ctx.cwd,
|
|
@@ -5055,20 +5075,6 @@ const createInitCommand = (injected) => defineOrmCommand({
|
|
|
5055
5075
|
filesWritten: scaffold.filesWritten
|
|
5056
5076
|
})));
|
|
5057
5077
|
}
|
|
5058
|
-
const skillCommands = resolveProjectSkillInstallCommands(installedManager ?? packageManager, ctx.env);
|
|
5059
|
-
if (inputs.installProjectSkill) {
|
|
5060
|
-
const failure = await installAgentSkills({
|
|
5061
|
-
packages: ctx.packages,
|
|
5062
|
-
cwd: ctx.cwd,
|
|
5063
|
-
env: ctx.env,
|
|
5064
|
-
manager: installedManager
|
|
5065
|
-
});
|
|
5066
|
-
if (failure !== void 0) {
|
|
5067
|
-
findings.push(skillInstallFailedFinding(failure, scaffold.filesWritten, skillCommands));
|
|
5068
|
-
return settle(6);
|
|
5069
|
-
}
|
|
5070
|
-
skillRegistered = true;
|
|
5071
|
-
} else warn(`Skipped the Prisma Next agent-skill install (--skip-skills). To install them later, run: ${skillCommands.map((command) => `\`${command}\``).join(" && ")}`);
|
|
5072
5078
|
return settle(0);
|
|
5073
5079
|
}
|
|
5074
5080
|
});
|
|
@@ -5087,8 +5093,8 @@ function signalExitCode(reason) {
|
|
|
5087
5093
|
}
|
|
5088
5094
|
const lspCommand = defineServerCommand({
|
|
5089
5095
|
help: {
|
|
5090
|
-
summary: "Start the Prisma
|
|
5091
|
-
description: "Launches a Language Server Protocol server that publishes PSL parse diagnostics\nand handles whole-document PSL formatting for the schema inputs declared in\nyour config (contract.source.inputs). Formatting uses the Prisma
|
|
5096
|
+
summary: "Start the Prisma ORM language server",
|
|
5097
|
+
description: "Launches a Language Server Protocol server that publishes PSL parse diagnostics\nand handles whole-document PSL formatting for the schema inputs declared in\nyour config (contract.source.inputs). Formatting uses the Prisma ORM PSL\nformatter and the formatter block from the project config.\nCommunicates over stdio; intended to be spawned by an\neditor, not run interactively. The server keeps running until the editor client\ndisconnects.",
|
|
5092
5098
|
examples: ["lsp"]
|
|
5093
5099
|
},
|
|
5094
5100
|
args: { flags: {
|
|
@@ -5100,7 +5106,7 @@ const lspCommand = defineServerCommand({
|
|
|
5100
5106
|
} },
|
|
5101
5107
|
handler: async (args, io) => {
|
|
5102
5108
|
const exitCode = await withoutClientProcessIdInArgv(async () => {
|
|
5103
|
-
const { startServer } = await import("./exports-
|
|
5109
|
+
const { startServer } = await import("./exports-CYa2di3d.mjs");
|
|
5104
5110
|
return startServer({
|
|
5105
5111
|
stdin: io.stdin,
|
|
5106
5112
|
stdout: io.stdout,
|
|
@@ -7337,12 +7343,12 @@ function mapMigrateFailure(failure) {
|
|
|
7337
7343
|
if (failure.code === "MIGRATION_PATH_NOT_FOUND") return errorPathUnreachable(failure);
|
|
7338
7344
|
return errorRunnerFailed(failure.summary, {
|
|
7339
7345
|
why: failure.why ?? "Migration runner failed",
|
|
7340
|
-
fix: "Fix the issue and re-run `
|
|
7346
|
+
fix: "Fix the issue and re-run `{bin} db migrate --to <contract>` — previously applied migrations are preserved.",
|
|
7341
7347
|
meta: failure.meta ?? {},
|
|
7342
7348
|
...ifDefined("cause", failure.cause)
|
|
7343
7349
|
});
|
|
7344
7350
|
}
|
|
7345
|
-
const STATUS_ACTION = runCommandAction("Check every space against the database", "
|
|
7351
|
+
const STATUS_ACTION = runCommandAction("Check every space against the database", "{bin} migration status");
|
|
7346
7352
|
/**
|
|
7347
7353
|
* The route the migration will take. The graph is a drawing — the engine cannot
|
|
7348
7354
|
* derive a lane gutter — and the ordered list under it is drawn with the same
|
|
@@ -7474,11 +7480,11 @@ function createMigrateCommand(createClient) {
|
|
|
7474
7480
|
summary: "Apply planned migrations to advance the database",
|
|
7475
7481
|
description: "Walks every contract space (app + extensions) and applies pending on-disk\nmigrations in canonical order (extensions alphabetically, then app). It\nreplays the on-disk migration graph and never invents an edge. Use --to to\ntarget a specific contract (hash, ref name, or migration directory) and\n--show for a read-only preview of the route it would take.",
|
|
7476
7482
|
examples: [
|
|
7477
|
-
"migrate",
|
|
7478
|
-
"migrate --db $DATABASE_URL",
|
|
7479
|
-
"migrate --to production",
|
|
7480
|
-
"migrate --show",
|
|
7481
|
-
"migrate --show --from @contract --to production"
|
|
7483
|
+
"db migrate",
|
|
7484
|
+
"db migrate --db $DATABASE_URL",
|
|
7485
|
+
"db migrate --to production",
|
|
7486
|
+
"db migrate --show",
|
|
7487
|
+
"db migrate --show --from @contract --to production"
|
|
7482
7488
|
]
|
|
7483
7489
|
},
|
|
7484
7490
|
args: { flags: {
|
|
@@ -7539,7 +7545,7 @@ function createMigrateCommand(createClient) {
|
|
|
7539
7545
|
config: ctx.config,
|
|
7540
7546
|
cwd: ctx.cwd,
|
|
7541
7547
|
db: args.flags.db,
|
|
7542
|
-
commandName: "migrate",
|
|
7548
|
+
commandName: "db migrate",
|
|
7543
7549
|
createClient
|
|
7544
7550
|
});
|
|
7545
7551
|
if (!prepared.ok) return notOk$1(prepared.failure);
|
|
@@ -7563,7 +7569,7 @@ function createMigrateCommand(createClient) {
|
|
|
7563
7569
|
const integrityFailure = refuseContractSpaceIntegrity(aggregate, {
|
|
7564
7570
|
declaredExtensions: toDeclaredExtensionsFromRaw(castAs(ctx.config.extensions ?? [])),
|
|
7565
7571
|
checkContracts: true
|
|
7566
|
-
});
|
|
7572
|
+
}, migrationsDir);
|
|
7567
7573
|
if (integrityFailure) return notOk$1(normalizeError(integrityFailure));
|
|
7568
7574
|
const target = resolveRequestedTarget(args.flags.to, aggregate.app.refs, aggregate.app.graph());
|
|
7569
7575
|
if (!target.ok) return notOk$1(target.failure);
|
|
@@ -7720,7 +7726,7 @@ function integrityViolationToCheckFailure(violation, migrationsDir) {
|
|
|
7720
7726
|
code: "MIGRATION.CHECK_DECLARED_BUT_UNMIGRATED",
|
|
7721
7727
|
where: spaceRelative(violation.spaceId),
|
|
7722
7728
|
why: `Extension "${violation.spaceId}" is declared in \`extensions\` but has no on-disk migrations directory.`,
|
|
7723
|
-
nextActions: [runCommandAction("Re-emit the extension contract-space artefacts, then plan its migrations", "
|
|
7729
|
+
nextActions: [runCommandAction("Re-emit the extension contract-space artefacts, then plan its migrations", "{bin} contract emit"), chooseAction("Or remove the extension from `extensions` if it is unused")]
|
|
7724
7730
|
};
|
|
7725
7731
|
case "headRefMissing": return {
|
|
7726
7732
|
space: violation.spaceId,
|
|
@@ -7762,7 +7768,7 @@ function integrityViolationToCheckFailure(violation, migrationsDir) {
|
|
|
7762
7768
|
code: "MIGRATION.CHECK_CONTRACT_UNREADABLE",
|
|
7763
7769
|
where: migrationFileRelative(join(migrationsDir, violation.spaceId), "contract.json"),
|
|
7764
7770
|
why: `Contract for space "${violation.spaceId}" is unreadable: ${violation.detail}`,
|
|
7765
|
-
nextActions: [runCommandAction("Re-emit the extension contract artefacts", "
|
|
7771
|
+
nextActions: [runCommandAction("Re-emit the extension contract artefacts", "{bin} contract emit"), chooseAction("Or fix the descriptor producing the invalid contract")]
|
|
7766
7772
|
};
|
|
7767
7773
|
case "duplicateMigrationHash": return {
|
|
7768
7774
|
space: violation.spaceId,
|
|
@@ -7979,7 +7985,10 @@ function renderMigrationGraphDot(graph) {
|
|
|
7979
7985
|
}
|
|
7980
7986
|
/**
|
|
7981
7987
|
* The tree is a drawing for a reader; the DOT document is a graph description
|
|
7982
|
-
* for another program, so it is the
|
|
7988
|
+
* for another program, so it is also the stdout payload. It appears in both
|
|
7989
|
+
* surfaces because the engine treats the payload as a mirror of the human
|
|
7990
|
+
* output: on one shared screen it suppresses the stdout copy, so the human
|
|
7991
|
+
* block is what keeps `--dot` visible there, while split sinks receive both.
|
|
7983
7992
|
*/
|
|
7984
7993
|
function graphPresentations(inputs) {
|
|
7985
7994
|
const { tree, dot, legend } = inputs;
|
|
@@ -8002,6 +8011,10 @@ function graphPresentations(inputs) {
|
|
|
8002
8011
|
kind: "drawing",
|
|
8003
8012
|
lines: toneDrawing(tree)
|
|
8004
8013
|
}],
|
|
8014
|
+
...dot === void 0 ? [] : [{
|
|
8015
|
+
kind: "drawing",
|
|
8016
|
+
lines: dot.split("\n")
|
|
8017
|
+
}],
|
|
8005
8018
|
...legend === void 0 ? [] : [{
|
|
8006
8019
|
kind: "drawing",
|
|
8007
8020
|
lines: toneDrawing(legend)
|
|
@@ -8486,6 +8499,15 @@ function previewBlocks$1(result) {
|
|
|
8486
8499
|
lines: statements
|
|
8487
8500
|
}];
|
|
8488
8501
|
}
|
|
8502
|
+
function originNoticeBlocks(result) {
|
|
8503
|
+
if (result.fromDefaulted !== true) return [];
|
|
8504
|
+
return [{
|
|
8505
|
+
kind: "summary",
|
|
8506
|
+
status: "info",
|
|
8507
|
+
tone: "muted",
|
|
8508
|
+
text: "No db ref set — planning from an empty database. Run db init, db update, or db sign if a database already exists."
|
|
8509
|
+
}];
|
|
8510
|
+
}
|
|
8489
8511
|
function planBlocks(result, migrationsRelative) {
|
|
8490
8512
|
const outcome = outcomeFields(result, migrationsRelative);
|
|
8491
8513
|
if (result.noOp) return [{
|
|
@@ -8493,17 +8515,22 @@ function planBlocks(result, migrationsRelative) {
|
|
|
8493
8515
|
status: "ok",
|
|
8494
8516
|
text: "No changes detected"
|
|
8495
8517
|
}, outcome];
|
|
8496
|
-
if (result.pendingPlaceholders === true) return [
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8518
|
+
if (result.pendingPlaceholders === true) return [
|
|
8519
|
+
{
|
|
8520
|
+
kind: "summary",
|
|
8521
|
+
status: "warn",
|
|
8522
|
+
text: result.summary
|
|
8523
|
+
},
|
|
8524
|
+
...originNoticeBlocks(result),
|
|
8525
|
+
outcome
|
|
8526
|
+
];
|
|
8501
8527
|
return [
|
|
8502
8528
|
{
|
|
8503
8529
|
kind: "summary",
|
|
8504
8530
|
status: "ok",
|
|
8505
8531
|
text: result.summary
|
|
8506
8532
|
},
|
|
8533
|
+
...originNoticeBlocks(result),
|
|
8507
8534
|
...operationBlocks$1(result),
|
|
8508
8535
|
outcome,
|
|
8509
8536
|
...previewBlocks$1(result)
|
|
@@ -8526,7 +8553,7 @@ function planNextActions(result, migrationsRelative) {
|
|
|
8526
8553
|
return [{
|
|
8527
8554
|
kind: "edit-file",
|
|
8528
8555
|
label: `Review ${written.join(" and ")}`
|
|
8529
|
-
}, runCommandAction("Apply the migration", "
|
|
8556
|
+
}, runCommandAction("Apply the migration", "{bin} db migrate")];
|
|
8530
8557
|
}
|
|
8531
8558
|
function planPresentations(inputs) {
|
|
8532
8559
|
return {
|
|
@@ -8578,7 +8605,7 @@ const migrationPlanCommand = defineOrmCommand({
|
|
|
8578
8605
|
placeholder: "slug"
|
|
8579
8606
|
}),
|
|
8580
8607
|
from: flag.string({
|
|
8581
|
-
brief: "Starting contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)",
|
|
8608
|
+
brief: "Starting contract reference (hash, prefix, ref name, migration dir name, <dir>^, @empty, or ./path)",
|
|
8582
8609
|
placeholder: "contract"
|
|
8583
8610
|
}),
|
|
8584
8611
|
to: flag.string({
|
|
@@ -8803,7 +8830,7 @@ const migrationShowCommand = defineOrmCommand({
|
|
|
8803
8830
|
} catch (error) {
|
|
8804
8831
|
return notOk$1(normalizeError(Reflect.get(Object(error), "code") === "ENOENT" ? errorFileNotFound(contractPath, {
|
|
8805
8832
|
why: `Contract file not found at ${contractPath}`,
|
|
8806
|
-
fix: `Run \`
|
|
8833
|
+
fix: `Run \`{bin} contract emit\` to generate ${relative(ctx.cwd, contractPath)}`
|
|
8807
8834
|
}) : errorUnexpected(error instanceof Error ? error.message : String(error), { why: "Failed to read contract file" })));
|
|
8808
8835
|
}
|
|
8809
8836
|
const familyInstance = ctx.config.family.create(createControlStack(ctx.config));
|
|
@@ -8869,7 +8896,7 @@ const migrationShowCommand = defineOrmCommand({
|
|
|
8869
8896
|
})));
|
|
8870
8897
|
}
|
|
8871
8898
|
});
|
|
8872
|
-
const EMIT_CONTRACT = runCommandAction("Regenerate the contract", "
|
|
8899
|
+
const EMIT_CONTRACT = runCommandAction("Regenerate the contract", "{bin} contract emit");
|
|
8873
8900
|
function contractUnreadableFinding(reason) {
|
|
8874
8901
|
const message = `Could not read contract: ${reason}`;
|
|
8875
8902
|
return {
|
|
@@ -8877,7 +8904,7 @@ function contractUnreadableFinding(reason) {
|
|
|
8877
8904
|
code: "CONTRACT.UNREADABLE",
|
|
8878
8905
|
severity: "warn",
|
|
8879
8906
|
message,
|
|
8880
|
-
hints: ["Run '
|
|
8907
|
+
hints: ["Run '{bin} contract emit' to generate a valid contract"]
|
|
8881
8908
|
},
|
|
8882
8909
|
diagnostic: {
|
|
8883
8910
|
code: "CONTRACT.UNREADABLE",
|
|
@@ -8895,7 +8922,7 @@ function markerNotInHistoryFinding(space) {
|
|
|
8895
8922
|
code: "MIGRATION.MARKER_NOT_IN_HISTORY",
|
|
8896
8923
|
severity: "warn",
|
|
8897
8924
|
message,
|
|
8898
|
-
hints: ["Run '
|
|
8925
|
+
hints: ["Run '{bin} db sign' to overwrite the marker if the database already matches the contract", "Run '{bin} db update' to push the current contract to the database"]
|
|
8899
8926
|
},
|
|
8900
8927
|
diagnostic: {
|
|
8901
8928
|
code: "MIGRATION.MARKER_NOT_IN_HISTORY",
|
|
@@ -8903,7 +8930,7 @@ function markerNotInHistoryFinding(space) {
|
|
|
8903
8930
|
summary: message,
|
|
8904
8931
|
why: "The marker the database carries names no contract in the on-disk migration graph.",
|
|
8905
8932
|
meta: { space },
|
|
8906
|
-
nextActions: [runCommandAction("Overwrite the marker if the database already matches the contract", "
|
|
8933
|
+
nextActions: [runCommandAction("Overwrite the marker if the database already matches the contract", "{bin} db sign"), runCommandAction("Or push the current contract to the database", "{bin} db update")]
|
|
8907
8934
|
}
|
|
8908
8935
|
};
|
|
8909
8936
|
}
|
|
@@ -8922,7 +8949,7 @@ function missingInvariantsFinding(inputs) {
|
|
|
8922
8949
|
severity: "warn",
|
|
8923
8950
|
summary: message,
|
|
8924
8951
|
why: inputs.refName === void 0 ? "The database marker does not carry every invariant the target requires." : `The database marker does not carry every invariant \`${inputs.refName}\` requires.`,
|
|
8925
|
-
nextActions: [runCommandAction("Apply the migrations that provide them", "
|
|
8952
|
+
nextActions: [runCommandAction("Apply the migrations that provide them", "{bin} db migrate")],
|
|
8926
8953
|
meta: {
|
|
8927
8954
|
invariants: [...inputs.missing],
|
|
8928
8955
|
...ifDefined("ref", inputs.refName)
|
|
@@ -8958,13 +8985,13 @@ async function readDatabaseState(inputs) {
|
|
|
8958
8985
|
function buildNoPathSummary(args) {
|
|
8959
8986
|
const markerPart = args.markerHash !== void 0 ? `the database state (${shortDisplayHash(args.markerHash)})` : "the database state";
|
|
8960
8987
|
const targetShort = shortDisplayHash(args.targetHash);
|
|
8961
|
-
if (!args.explicitTarget) return `No migration path from ${markerPart} to the application's contract (${targetShort}). Run \`
|
|
8962
|
-
return `No migration path from ${markerPart} to ${args.refName !== void 0 ? `the target (${targetShort} via \`${args.refName}\`)` : `the target (${targetShort})`}. Run \`
|
|
8988
|
+
if (!args.explicitTarget) return `No migration path from ${markerPart} to the application's contract (${targetShort}). Run \`{bin} migration plan --name <name>\` to author one.`;
|
|
8989
|
+
return `No migration path from ${markerPart} to ${args.refName !== void 0 ? `the target (${targetShort} via \`${args.refName}\`)` : `the target (${targetShort})`}. Run \`{bin} migration plan --name <name>\` to author one, or pass \`--to <contract>\` to pick a reachable target.`;
|
|
8963
8990
|
}
|
|
8964
8991
|
function buildStatusHeadline(args) {
|
|
8965
8992
|
if (args.markerDiverged && args.markerHash !== void 0) return `Database marker ${shortDisplayHash(args.markerHash)} is not in the on-disk migration graph`;
|
|
8966
8993
|
if (args.pendingCount === 0) return "Up to date";
|
|
8967
|
-
return `${args.pendingCount} pending — run \`
|
|
8994
|
+
return `${args.pendingCount} pending — run \`{bin} db migrate --to ${shortDisplayHash(args.targetHash)}\``;
|
|
8968
8995
|
}
|
|
8969
8996
|
/**
|
|
8970
8997
|
* One space's section: its heading, where more than one space is in scope, on
|
|
@@ -9068,7 +9095,7 @@ const migrationStatusCommand = defineOrmCommand({
|
|
|
9068
9095
|
dbConnection,
|
|
9069
9096
|
hasDriver,
|
|
9070
9097
|
why: "migration status needs a database connection to read the marker and ledger (or pass --from for an offline path preview)",
|
|
9071
|
-
retryCommand: "
|
|
9098
|
+
retryCommand: "{bin} migration status --from <contract>"
|
|
9072
9099
|
});
|
|
9073
9100
|
if (missingDb !== null) return notOk$1(normalizeError(missingDb));
|
|
9074
9101
|
}
|
|
@@ -9086,7 +9113,7 @@ const migrationStatusCommand = defineOrmCommand({
|
|
|
9086
9113
|
findings.push(contractUnreadableFinding(error instanceof Error ? error.message : "unknown error"));
|
|
9087
9114
|
}
|
|
9088
9115
|
if (await loadContractRawSafely(contractConfig) !== null) {
|
|
9089
|
-
const corruption = refusePackageCorruptionOnAggregate(aggregate);
|
|
9116
|
+
const corruption = refusePackageCorruptionOnAggregate(aggregate, migrationsDir);
|
|
9090
9117
|
if (corruption) return notOk$1(normalizeError(corruption));
|
|
9091
9118
|
}
|
|
9092
9119
|
const appGraph = aggregate.app.graph();
|
|
@@ -9315,7 +9342,7 @@ function createRefDeleteCommand(execute = executeRefDeleteCommand) {
|
|
|
9315
9342
|
help: {
|
|
9316
9343
|
summary: "Delete a ref",
|
|
9317
9344
|
description: "Removes migrations/app/refs/<name>.json. The contract the ref pointed at\nis untouched: a ref is a pointer, and its target survives the deletion.",
|
|
9318
|
-
examples: ["ref delete staging", "ref delete staging --json"]
|
|
9345
|
+
examples: ["migration ref delete staging", "migration ref delete staging --json"]
|
|
9319
9346
|
},
|
|
9320
9347
|
args: { positionals: { name: positional.string({
|
|
9321
9348
|
brief: "Ref name to delete",
|
|
@@ -9381,7 +9408,7 @@ function createRefListCommand(execute = executeRefListCommand) {
|
|
|
9381
9408
|
help: {
|
|
9382
9409
|
summary: "List every named ref",
|
|
9383
9410
|
description: "Reads migrations/app/refs/ and reports each ref with the contract hash it\npoints at and the invariants recorded against it. Offline — does not\nconsult the database.",
|
|
9384
|
-
examples: ["ref list", "ref list --json"]
|
|
9411
|
+
examples: ["migration ref list", "migration ref list --json"]
|
|
9385
9412
|
},
|
|
9386
9413
|
needs: { config: ormConfigSection },
|
|
9387
9414
|
handler: async (_args, ctx) => {
|
|
@@ -9424,9 +9451,9 @@ function createRefSetCommand(execute = executeRefSetCommand) {
|
|
|
9424
9451
|
summary: "Point a ref at a contract",
|
|
9425
9452
|
description: "Writes migrations/app/refs/<name>.json so a logical environment name\nresolves to a contract hash. The contract is given as a hash or prefix,\nanother ref name, a migration directory name, or <dir>^ for that\nmigration's source contract. Offline — the contract must already be a\nnode of the on-disk migration graph, with its snapshot present.",
|
|
9426
9453
|
examples: [
|
|
9427
|
-
"ref set staging 4cb4256",
|
|
9428
|
-
"ref set production 20260101T1000_add_user",
|
|
9429
|
-
"ref set staging production --json"
|
|
9454
|
+
"migration ref set staging 4cb4256",
|
|
9455
|
+
"migration ref set production 20260101T1000_add_user",
|
|
9456
|
+
"migration ref set staging production --json"
|
|
9430
9457
|
]
|
|
9431
9458
|
},
|
|
9432
9459
|
args: { positionals: {
|
|
@@ -9465,40 +9492,35 @@ const ormCommandFamily = defineCommandFamily({
|
|
|
9465
9492
|
configSection: ormConfigSection,
|
|
9466
9493
|
commands: {
|
|
9467
9494
|
"contract emit": contractEmitCommand,
|
|
9495
|
+
"contract format": formatCommand,
|
|
9468
9496
|
"contract infer": contractInferCommand,
|
|
9469
9497
|
"db init": dbInitCommand,
|
|
9498
|
+
"db migrate": migrateCommand,
|
|
9470
9499
|
"db schema": dbSchemaCommand,
|
|
9471
9500
|
"db sign": dbSignCommand,
|
|
9472
9501
|
"db update": dbUpdateCommand,
|
|
9473
9502
|
"db verify": dbVerifyCommand,
|
|
9474
|
-
format: formatCommand,
|
|
9475
|
-
init: initCommand,
|
|
9476
9503
|
lsp: lspCommand,
|
|
9477
|
-
migrate: migrateCommand,
|
|
9478
9504
|
"migration check": migrationCheckCommand,
|
|
9479
9505
|
"migration graph": migrationGraphCommand,
|
|
9480
9506
|
"migration list": migrationListCommand,
|
|
9481
9507
|
"migration log": migrationLogCommand,
|
|
9482
9508
|
"migration new": migrationNewCommand,
|
|
9483
9509
|
"migration plan": migrationPlanCommand,
|
|
9510
|
+
"migration ref delete": refDeleteCommand,
|
|
9511
|
+
"migration ref list": refListCommand,
|
|
9512
|
+
"migration ref set": refSetCommand,
|
|
9484
9513
|
"migration show": migrationShowCommand,
|
|
9485
9514
|
"migration status": migrationStatusCommand,
|
|
9486
|
-
"
|
|
9487
|
-
"ref list": refListCommand,
|
|
9488
|
-
"ref set": refSetCommand
|
|
9515
|
+
"orm init": initCommand
|
|
9489
9516
|
},
|
|
9490
9517
|
docsBaseUrl: DOCS_BASE_URL,
|
|
9491
9518
|
redirects: [
|
|
9492
9519
|
{
|
|
9493
9520
|
from: "migration apply",
|
|
9494
|
-
replacement: "{bin} migrate --to <contract>",
|
|
9521
|
+
replacement: "{bin} db migrate --to <contract>",
|
|
9495
9522
|
reason: "Applying a migration is a move to a target contract, not a verb of its own."
|
|
9496
9523
|
},
|
|
9497
|
-
{
|
|
9498
|
-
from: "migration ref",
|
|
9499
|
-
replacement: "{bin} ref set|list|delete",
|
|
9500
|
-
reason: "Refs are managed by their own command, for every space rather than migrations alone."
|
|
9501
|
-
},
|
|
9502
9524
|
{
|
|
9503
9525
|
from: "migration status",
|
|
9504
9526
|
flag: "graph",
|
|
@@ -9527,37 +9549,32 @@ const ormCommandFamily = defineCommandFamily({
|
|
|
9527
9549
|
});
|
|
9528
9550
|
/** The file the ORM's loader reads when `--config` names none. */
|
|
9529
9551
|
const ORM_CONFIG_FILENAME = "prisma.config.ts";
|
|
9530
|
-
/** The pre-consolidation filename, still read as a deprecated fallback. */
|
|
9531
|
-
const DEPRECATED_ORM_CONFIG_FILENAME = "prisma-next.config.ts";
|
|
9532
9552
|
/**
|
|
9533
9553
|
* Builds the engine's `Runtime.config` from `prisma.config.ts`.
|
|
9534
9554
|
*
|
|
9535
9555
|
* The engine ships its own synchronous loader, but the bin owns the load: the
|
|
9536
9556
|
* ORM's c12 loader evaluates the module asynchronously and finalizes paths
|
|
9537
9557
|
* against the config file's own directory. It reads the same shape the engine
|
|
9538
|
-
* does — defineConfig from `@prisma/cli-engine` with the whole Prisma
|
|
9539
|
-
* configuration nested as the single `orm` section
|
|
9540
|
-
* deprecated `prisma-next.config.ts` filename and flat shape, surfacing each
|
|
9541
|
-
* through `warn`.
|
|
9558
|
+
* does — defineConfig from `@prisma/cli-engine` with the whole Prisma ORM
|
|
9559
|
+
* configuration nested as the single `orm` section.
|
|
9542
9560
|
*
|
|
9543
9561
|
* Only failures that prevent evaluation entirely are diagnostics here, and
|
|
9544
9562
|
* they carry `section: null` so they fail exactly the commands that read
|
|
9545
9563
|
* config. Structural verdicts belong to the section validator.
|
|
9546
9564
|
*/
|
|
9547
9565
|
async function loadOrmConfig(options) {
|
|
9566
|
+
const path = resolve(options.cwd, options.configPath ?? ORM_CONFIG_FILENAME);
|
|
9548
9567
|
const loaded = await loadConfig(options.configPath, { cwd: options.cwd });
|
|
9549
9568
|
if (!loaded.ok) return {
|
|
9550
|
-
path
|
|
9569
|
+
path,
|
|
9551
9570
|
sections: {},
|
|
9552
9571
|
diagnostics: [{
|
|
9553
9572
|
section: null,
|
|
9554
9573
|
diagnostic: toEngineDiagnostic(loaded.failure)
|
|
9555
9574
|
}]
|
|
9556
9575
|
};
|
|
9557
|
-
for (const deprecation of loaded.value.deprecations) options.warn?.(deprecation.message);
|
|
9558
|
-
const filename = loaded.value.deprecations.some((deprecation) => deprecation.code === "CONFIG.DEPRECATED_FILENAME") ? DEPRECATED_ORM_CONFIG_FILENAME : ORM_CONFIG_FILENAME;
|
|
9559
9576
|
return {
|
|
9560
|
-
path
|
|
9577
|
+
path,
|
|
9561
9578
|
sections: { ["orm"]: loaded.value.config },
|
|
9562
9579
|
diagnostics: []
|
|
9563
9580
|
};
|
|
@@ -9674,7 +9691,7 @@ function createImportAllowlistPlugin(allowlist, entryPath, collected) {
|
|
|
9674
9691
|
async function loadContractFromTs(entryPath, options) {
|
|
9675
9692
|
const allowlist = options?.allowlist ?? DEFAULT_ALLOWLIST;
|
|
9676
9693
|
if (!existsSync(entryPath)) throw new CliStructuredError("CLI.FILE_NOT_FOUND", `Contract file not found: ${entryPath}`, { where: { path: entryPath } });
|
|
9677
|
-
const tempFile = join(tmpdir(), `prisma-
|
|
9694
|
+
const tempFile = join(tmpdir(), `prisma-8-contract-${Date.now()}-${Math.random().toString(36).slice(2)}.mjs`);
|
|
9678
9695
|
const disallowedFromEntry = /* @__PURE__ */ new Set();
|
|
9679
9696
|
try {
|
|
9680
9697
|
const result = await build({
|