@prisma/cli 8.0.0-rc.1 → 8.0.0-rc.2

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.
Files changed (110) hide show
  1. package/dist/cli.js +15115 -16
  2. package/dist/deploy-framework-C7bQM00A.js +23 -0
  3. package/dist/{v8/sender.js → sender.js} +2 -2
  4. package/package.json +11 -15
  5. package/dist/adapters/git.js +0 -54
  6. package/dist/adapters/local-state.js +0 -155
  7. package/dist/auth/client.js +0 -30
  8. package/dist/auth/errors.js +0 -50
  9. package/dist/auth/guard.js +0 -39
  10. package/dist/auth/login.js +0 -471
  11. package/dist/auth/operations.js +0 -208
  12. package/dist/auth/recipient.js +0 -42
  13. package/dist/auth/token-storage.js +0 -439
  14. package/dist/auth/workspaces.js +0 -171
  15. package/dist/cli-command.js +0 -14
  16. package/dist/cli-name.js +0 -12
  17. package/dist/cli2.js +0 -136
  18. package/dist/command-arguments.js +0 -12
  19. package/dist/commands/agent/index.js +0 -60
  20. package/dist/commands/app/index.js +0 -350
  21. package/dist/commands/auth/index.js +0 -95
  22. package/dist/commands/branch/index.js +0 -27
  23. package/dist/commands/bucket/index.js +0 -123
  24. package/dist/commands/build/index.js +0 -29
  25. package/dist/commands/database/index.js +0 -249
  26. package/dist/commands/env.js +0 -99
  27. package/dist/commands/feedback/index.js +0 -20
  28. package/dist/commands/git/index.js +0 -36
  29. package/dist/commands/init/index.js +0 -33
  30. package/dist/commands/project/index.js +0 -118
  31. package/dist/commands/version/index.js +0 -18
  32. package/dist/controllers/agent-setup.js +0 -52
  33. package/dist/controllers/agent.js +0 -228
  34. package/dist/controllers/app-env-api.js +0 -55
  35. package/dist/controllers/app-env-file.js +0 -181
  36. package/dist/controllers/app-env.js +0 -502
  37. package/dist/controllers/app.js +0 -2508
  38. package/dist/controllers/auth.js +0 -124
  39. package/dist/controllers/branch.js +0 -92
  40. package/dist/controllers/bucket.js +0 -184
  41. package/dist/controllers/build.js +0 -88
  42. package/dist/controllers/database.js +0 -463
  43. package/dist/controllers/feedback.js +0 -90
  44. package/dist/controllers/init.js +0 -814
  45. package/dist/controllers/project.js +0 -892
  46. package/dist/controllers/select-prompt-port.js +0 -13
  47. package/dist/controllers/version.js +0 -12
  48. package/dist/errors.js +0 -102
  49. package/dist/lib/agent/cli-command.js +0 -20
  50. package/dist/lib/agent/constants.js +0 -12
  51. package/dist/lib/agent/package-manager.js +0 -99
  52. package/dist/lib/agent/setup-status.js +0 -83
  53. package/dist/lib/app/app-provider.js +0 -617
  54. package/dist/lib/app/branch-database-api.js +0 -102
  55. package/dist/lib/app/branch-database-deploy.js +0 -353
  56. package/dist/lib/app/branch-database.js +0 -234
  57. package/dist/lib/app/build-settings.js +0 -98
  58. package/dist/lib/app/build.js +0 -82
  59. package/dist/lib/app/bun-project.js +0 -45
  60. package/dist/lib/app/compute-config.js +0 -145
  61. package/dist/lib/app/deploy-output.js +0 -24
  62. package/dist/lib/app/deploy-plan.js +0 -59
  63. package/dist/lib/app/deploy-progress.js +0 -100
  64. package/dist/lib/app/domain-guidance.js +0 -14
  65. package/dist/lib/app/env-config.js +0 -67
  66. package/dist/lib/app/env-file.js +0 -82
  67. package/dist/lib/app/env-vars.js +0 -50
  68. package/dist/lib/app/local-dev.js +0 -109
  69. package/dist/lib/app/production-deploy-gate.js +0 -162
  70. package/dist/lib/app/read-branch.js +0 -30
  71. package/dist/lib/bucket/provider.js +0 -139
  72. package/dist/lib/database/provider.js +0 -385
  73. package/dist/lib/diagnostics.js +0 -16
  74. package/dist/lib/feedback.js +0 -15
  75. package/dist/lib/fs/home-path.js +0 -24
  76. package/dist/lib/git/local-branch.js +0 -53
  77. package/dist/lib/git/local-status.js +0 -57
  78. package/dist/lib/project/interactive-setup.js +0 -57
  79. package/dist/lib/project/local-pin.js +0 -200
  80. package/dist/lib/project/provider.js +0 -93
  81. package/dist/lib/project/resolution.js +0 -389
  82. package/dist/lib/project/setup.js +0 -138
  83. package/dist/lib/version.js +0 -56
  84. package/dist/lib/workspace-id.js +0 -18
  85. package/dist/output/patterns.js +0 -90
  86. package/dist/presenters/agent.js +0 -74
  87. package/dist/presenters/app-env.js +0 -265
  88. package/dist/presenters/app.js +0 -672
  89. package/dist/presenters/auth.js +0 -184
  90. package/dist/presenters/branch.js +0 -46
  91. package/dist/presenters/bucket.js +0 -174
  92. package/dist/presenters/database.js +0 -462
  93. package/dist/presenters/feedback.js +0 -26
  94. package/dist/presenters/init.js +0 -30
  95. package/dist/presenters/project.js +0 -268
  96. package/dist/presenters/verbose-context.js +0 -64
  97. package/dist/presenters/version.js +0 -29
  98. package/dist/shell/cli-command.js +0 -2
  99. package/dist/shell/command-meta.js +0 -923
  100. package/dist/shell/command-runner.js +0 -119
  101. package/dist/shell/diagnostics-output.js +0 -57
  102. package/dist/shell/global-flags.js +0 -37
  103. package/dist/shell/help.js +0 -90
  104. package/dist/shell/output.js +0 -144
  105. package/dist/shell/prompt.js +0 -48
  106. package/dist/shell/runtime.js +0 -38
  107. package/dist/shell/ui.js +0 -116
  108. package/dist/state-dir.js +0 -12
  109. package/dist/update-check.js +0 -248
  110. package/dist/v8/cli.js +0 -14699
@@ -1,200 +0,0 @@
1
- import path from "node:path";
2
- import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
3
- import { Result, TaggedError, UnhandledException } from "better-result";
4
- //#region src/lib/project/local-pin.ts
5
- const LOCAL_RESOLUTION_PIN_RELATIVE_PATH = ".prisma/local.json";
6
- var LocalResolutionPinInvalidJsonError = class extends TaggedError("LocalResolutionPinInvalidJsonError")() {
7
- constructor(cause) {
8
- super({
9
- message: `${LOCAL_RESOLUTION_PIN_RELATIVE_PATH} contains invalid JSON.`,
10
- cause,
11
- pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH
12
- });
13
- }
14
- };
15
- var LocalResolutionPinInvalidShapeError = class extends TaggedError("LocalResolutionPinInvalidShapeError")() {
16
- constructor() {
17
- super({
18
- message: `${LOCAL_RESOLUTION_PIN_RELATIVE_PATH} must contain workspaceId and projectId string fields only.`,
19
- pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH
20
- });
21
- }
22
- };
23
- var LocalResolutionPinReadAbortedError = class extends TaggedError("LocalResolutionPinReadAbortedError")() {
24
- constructor(cause) {
25
- super({
26
- message: `Reading ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH} was aborted.`,
27
- cause,
28
- pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH
29
- });
30
- }
31
- };
32
- var LocalResolutionPinSerializationError = class extends TaggedError("LocalResolutionPinSerializationError")() {
33
- constructor(cause) {
34
- super({
35
- message: `Could not serialize ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH}.`,
36
- cause,
37
- pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH
38
- });
39
- }
40
- };
41
- var LocalResolutionPinWriteAbortedError = class extends TaggedError("LocalResolutionPinWriteAbortedError")() {
42
- constructor(cause) {
43
- super({
44
- message: `Writing ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH} was aborted.`,
45
- cause,
46
- pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH
47
- });
48
- }
49
- };
50
- var LocalResolutionPinWriteFailedError = class extends TaggedError("LocalResolutionPinWriteFailedError")() {
51
- constructor(operation, cause) {
52
- super({
53
- message: `Could not write ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH}.`,
54
- cause,
55
- operation,
56
- pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH
57
- });
58
- }
59
- };
60
- var LocalResolutionPinGitignoreUpdateAbortedError = class extends TaggedError("LocalResolutionPinGitignoreUpdateAbortedError")() {
61
- constructor(cause) {
62
- super({
63
- message: "Updating .gitignore for the local Project binding was aborted.",
64
- cause,
65
- gitignorePath: ".gitignore"
66
- });
67
- }
68
- };
69
- var LocalResolutionPinGitignoreUpdateFailedError = class extends TaggedError("LocalResolutionPinGitignoreUpdateFailedError")() {
70
- constructor(operation, cause) {
71
- super({
72
- message: "Could not update .gitignore for the local Project binding.",
73
- cause,
74
- operation,
75
- gitignorePath: ".gitignore"
76
- });
77
- }
78
- };
79
- async function readLocalResolutionPin(cwd, signal) {
80
- return Result.gen(async function* () {
81
- yield* ensureLocalResolutionPinReadNotAborted(signal);
82
- const file = yield* Result.await(readLocalResolutionPinFile(cwd, signal));
83
- if (file.kind === "missing") return Result.ok({ kind: "missing" });
84
- const parsed = yield* parseLocalResolutionPin(file.raw);
85
- if (!isLocalResolutionPin(parsed)) return Result.err(new LocalResolutionPinInvalidShapeError());
86
- return Result.ok({
87
- kind: "present",
88
- pin: parsed
89
- });
90
- });
91
- }
92
- function ensureLocalResolutionPinReadNotAborted(signal) {
93
- return Result.try({
94
- try: () => signal?.throwIfAborted(),
95
- catch: (cause) => new LocalResolutionPinReadAbortedError(cause)
96
- });
97
- }
98
- async function readLocalResolutionPinFile(cwd, signal) {
99
- const readResult = await Result.tryPromise({
100
- try: () => readFile(path.join(cwd, LOCAL_RESOLUTION_PIN_RELATIVE_PATH), {
101
- encoding: "utf8",
102
- signal
103
- }),
104
- catch: (cause) => signal?.aborted ? new LocalResolutionPinReadAbortedError(cause) : new UnhandledException({ cause })
105
- });
106
- if (readResult.isErr()) {
107
- if (readResult.error instanceof UnhandledException && readResult.error.cause.code === "ENOENT") return Result.ok({ kind: "missing" });
108
- return Result.err(readResult.error);
109
- }
110
- return Result.ok({
111
- kind: "present",
112
- raw: readResult.value
113
- });
114
- }
115
- function parseLocalResolutionPin(raw) {
116
- return Result.try({
117
- try: () => JSON.parse(raw),
118
- catch: (cause) => cause instanceof SyntaxError ? new LocalResolutionPinInvalidJsonError(cause) : new UnhandledException({ cause })
119
- });
120
- }
121
- async function writeLocalResolutionPin(cwd, pin, signal) {
122
- return Result.gen(async function* () {
123
- const prismaDir = path.join(cwd, ".prisma");
124
- yield* ensureLocalResolutionPinWriteNotAborted(signal);
125
- yield* Result.await(writeLocalResolutionPinBoundary(() => mkdir(prismaDir, { recursive: true }), "create-directory", signal));
126
- const pinPath = path.join(cwd, LOCAL_RESOLUTION_PIN_RELATIVE_PATH);
127
- const tmpPath = path.join(prismaDir, `local.${process.pid}.${Date.now()}.tmp`);
128
- const serialized = yield* serializeLocalResolutionPin(pin);
129
- yield* Result.await(writeLocalResolutionPinBoundary(() => writeFile(tmpPath, serialized, {
130
- encoding: "utf8",
131
- signal
132
- }), "write-temp-file", signal));
133
- yield* ensureLocalResolutionPinWriteNotAborted(signal);
134
- yield* Result.await(writeLocalResolutionPinBoundary(() => rename(tmpPath, pinPath), "rename-temp-file", signal));
135
- return Result.ok(void 0);
136
- });
137
- }
138
- async function ensureLocalResolutionPinGitignore(cwd, signal) {
139
- const gitignorePath = path.join(cwd, ".gitignore");
140
- let existing = null;
141
- const notAborted = ensureLocalResolutionPinGitignoreUpdateNotAborted(signal);
142
- if (notAborted.isErr()) return Result.err(notAborted.error);
143
- const existingResult = await Result.tryPromise({
144
- try: () => readFile(gitignorePath, {
145
- encoding: "utf8",
146
- signal
147
- }),
148
- catch: (cause) => signal?.aborted ? new LocalResolutionPinGitignoreUpdateAbortedError(cause) : new LocalResolutionPinGitignoreUpdateFailedError("read", cause)
149
- });
150
- if (existingResult.isErr()) if (existingResult.error instanceof LocalResolutionPinGitignoreUpdateFailedError && existingResult.error.cause.code === "ENOENT") existing = null;
151
- else return Result.err(existingResult.error);
152
- else existing = existingResult.value;
153
- if (existing === null) return writeLocalResolutionPinGitignore(gitignorePath, ".prisma/\n", signal);
154
- if (existing.split(/\r?\n/).map((line) => line.trim()).some((line) => line === ".prisma/" || line === ".prisma/local.json")) return Result.ok(void 0);
155
- return writeLocalResolutionPinGitignore(gitignorePath, existing.endsWith("\n") ? `${existing}.prisma/\n` : `${existing}\n.prisma/\n`, signal);
156
- }
157
- function ensureLocalResolutionPinWriteNotAborted(signal) {
158
- return Result.try({
159
- try: () => signal?.throwIfAborted(),
160
- catch: (cause) => new LocalResolutionPinWriteAbortedError(cause)
161
- });
162
- }
163
- function serializeLocalResolutionPin(pin) {
164
- return Result.try({
165
- try: () => `${JSON.stringify(pin, null, 2)}\n`,
166
- catch: (cause) => new LocalResolutionPinSerializationError(cause)
167
- });
168
- }
169
- function writeLocalResolutionPinBoundary(run, operation, signal) {
170
- return Result.tryPromise({
171
- try: async () => {
172
- await run();
173
- },
174
- catch: (cause) => signal?.aborted ? new LocalResolutionPinWriteAbortedError(cause) : new LocalResolutionPinWriteFailedError(operation, cause)
175
- });
176
- }
177
- function ensureLocalResolutionPinGitignoreUpdateNotAborted(signal) {
178
- return Result.try({
179
- try: () => signal?.throwIfAborted(),
180
- catch: (cause) => new LocalResolutionPinGitignoreUpdateAbortedError(cause)
181
- });
182
- }
183
- function writeLocalResolutionPinGitignore(gitignorePath, contents, signal) {
184
- return Result.tryPromise({
185
- try: () => writeFile(gitignorePath, contents, {
186
- encoding: "utf8",
187
- signal
188
- }),
189
- catch: (cause) => signal?.aborted ? new LocalResolutionPinGitignoreUpdateAbortedError(cause) : new LocalResolutionPinGitignoreUpdateFailedError("write", cause)
190
- });
191
- }
192
- function isLocalResolutionPin(value) {
193
- if (!value || typeof value !== "object") return false;
194
- const keys = Object.keys(value);
195
- if (keys.length !== 2 || !keys.includes("workspaceId") || !keys.includes("projectId")) return false;
196
- const candidate = value;
197
- return typeof candidate.workspaceId === "string" && candidate.workspaceId.trim().length > 0 && typeof candidate.projectId === "string" && candidate.projectId.trim().length > 0;
198
- }
199
- //#endregion
200
- export { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, ensureLocalResolutionPinGitignore, readLocalResolutionPin, writeLocalResolutionPin };
@@ -1,93 +0,0 @@
1
- import { formatPrismaCliCommand } from "../../cli-command.js";
2
- import { CliError } from "../../errors.js";
3
- import "../../shell/cli-command.js";
4
- //#region src/lib/project/provider.ts
5
- function createManagementProjectProvider(client) {
6
- return {
7
- async renameProject(options) {
8
- const result = await client.PATCH("/v1/projects/{id}", {
9
- params: { path: { id: options.projectId } },
10
- body: { name: options.name },
11
- signal: options.signal
12
- });
13
- const status = result.response?.status ?? 0;
14
- if (status === 400 || status === 422) throw projectRenameFailedError(options.name, result.error);
15
- if (result.error || !result.data) throw projectApiError("Failed to rename project", result.response, result.error);
16
- const project = result.data.data;
17
- return {
18
- id: project.id,
19
- name: project.name,
20
- ...project.url ? { url: project.url } : {}
21
- };
22
- },
23
- async removeProject(options) {
24
- const result = await client.DELETE("/v1/projects/{id}", {
25
- params: { path: { id: options.projectId } },
26
- signal: options.signal
27
- });
28
- if (result.response?.status === 400) throw projectRemoveBlockedError(options.projectId, result.error);
29
- if (result.error) throw projectApiError("Failed to remove project", result.response, result.error);
30
- },
31
- async transferProject(options) {
32
- const result = await client.POST("/v1/projects/{id}/transfer", {
33
- params: { path: { id: options.projectId } },
34
- body: { recipientAccessToken: options.recipientAccessToken },
35
- signal: options.signal
36
- });
37
- if (result.response?.status === 400) throw projectTransferRejectedError(options.projectId, result.error);
38
- if (result.error) throw projectApiError("Failed to transfer project", result.response, result.error);
39
- }
40
- };
41
- }
42
- function projectRenameFailedError(name, error) {
43
- return new CliError({
44
- code: "PROJECT_RENAME_FAILED",
45
- domain: "project",
46
- summary: "Project rename failed",
47
- why: error?.error?.message ?? `The platform rejected the name "${name}".`,
48
- fix: error?.error?.hint ?? "Pass a different project name and retry the rename.",
49
- exitCode: 1,
50
- nextSteps: []
51
- });
52
- }
53
- function projectRemoveBlockedError(projectId, error) {
54
- return new CliError({
55
- code: "PROJECT_REMOVE_BLOCKED",
56
- domain: "project",
57
- summary: "Project cannot be removed yet",
58
- why: error?.error?.message ?? `Project "${projectId}" still has active deployments.`,
59
- fix: "Remove the project's apps first, then retry the removal.",
60
- exitCode: 1,
61
- nextSteps: [formatPrismaCliCommand([
62
- "app",
63
- "remove",
64
- "--app",
65
- "<name>"
66
- ])]
67
- });
68
- }
69
- function projectTransferRejectedError(projectId, error) {
70
- return new CliError({
71
- code: "PROJECT_TRANSFER_REJECTED",
72
- domain: "project",
73
- summary: "Project transfer was rejected",
74
- why: error?.error?.message ?? `The platform rejected the transfer of project "${projectId}", for example because the recipient token is invalid or expired.`,
75
- fix: "Check the recipient workspace session or token and retry the transfer.",
76
- exitCode: 1,
77
- nextSteps: []
78
- });
79
- }
80
- function projectApiError(summary, response, error) {
81
- const status = response?.status ?? 0;
82
- return new CliError({
83
- code: error?.error?.code ?? "PROJECT_API_ERROR",
84
- domain: "project",
85
- summary,
86
- why: error?.error?.message ?? `The Management API returned status ${status || "unknown"}.`,
87
- fix: error?.error?.hint ?? "Re-run with --trace for the underlying API response details.",
88
- exitCode: 1,
89
- nextSteps: []
90
- });
91
- }
92
- //#endregion
93
- export { createManagementProjectProvider, projectApiError };
@@ -1,389 +0,0 @@
1
- import { formatCommandArgument } from "../../command-arguments.js";
2
- import { CliError } from "../../errors.js";
3
- import { sameWorkspaceId } from "../workspace-id.js";
4
- import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, readLocalResolutionPin } from "./local-pin.js";
5
- import path from "node:path";
6
- import { readFile } from "node:fs/promises";
7
- import { Result, TaggedError, matchError } from "better-result";
8
- //#region src/lib/project/resolution.ts
9
- var ProjectNotFoundError = class extends TaggedError("ProjectNotFoundError")() {
10
- constructor(projectRef, workspace) {
11
- super({
12
- message: `Project "${projectRef}" was not found in workspace "${workspace.name}".`,
13
- projectRef,
14
- workspace
15
- });
16
- }
17
- };
18
- var ProjectAmbiguousError = class extends TaggedError("ProjectAmbiguousError")() {
19
- constructor(projectRef, matches) {
20
- super({
21
- message: projectRef ? `Multiple projects matched "${projectRef}".` : "Multiple projects matched the current directory context.",
22
- projectRef,
23
- matches
24
- });
25
- }
26
- };
27
- var LocalStateStaleError = class extends TaggedError("LocalStateStaleError")() {
28
- constructor() {
29
- super({
30
- message: `The target recorded in ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH} is no longer available in the selected workspace.`,
31
- pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH
32
- });
33
- }
34
- };
35
- var LocalProjectWorkspaceMismatchError = class extends TaggedError("LocalProjectWorkspaceMismatchError")() {
36
- constructor(options) {
37
- super({
38
- message: `${LOCAL_RESOLUTION_PIN_RELATIVE_PATH} links this directory to project ${options.pinnedProjectId} in workspace ${options.pinnedWorkspaceId}, but the active workspace is "${options.activeWorkspace.name}" (${options.activeWorkspace.id}).`,
39
- pinnedWorkspaceId: options.pinnedWorkspaceId,
40
- pinnedProjectId: options.pinnedProjectId,
41
- activeWorkspace: options.activeWorkspace
42
- });
43
- }
44
- };
45
- var ProjectSetupRequiredError = class extends TaggedError("ProjectSetupRequiredError")() {
46
- constructor(options) {
47
- const commandLabel = options.commandName ? `prisma-cli ${options.commandName}` : "this command";
48
- super({
49
- message: `This directory is not linked to a Prisma Project, and ${commandLabel} will not choose one from package or directory names.`,
50
- commandName: options.commandName,
51
- suggestion: options.suggestion
52
- });
53
- }
54
- };
55
- async function resolveProjectTarget(options) {
56
- return Result.gen(async function* () {
57
- const localPin = yield* Result.await(readImplicitLocalPin(options, { allowEnvProjectId: true }));
58
- const projects = await options.listProjects();
59
- const target = yield* Result.await(resolveBoundProjectTarget(options, projects, {
60
- allowEnvProjectId: true,
61
- localPin
62
- }));
63
- if (target) return Result.ok(target);
64
- return Result.err(await projectSetupRequiredError({
65
- cwd: options.context.runtime.cwd,
66
- projects,
67
- commandName: options.commandName,
68
- signal: options.context.runtime.signal
69
- }));
70
- });
71
- }
72
- async function inspectProjectBinding(options) {
73
- return Result.gen(async function* () {
74
- const localPin = yield* Result.await(readImplicitLocalPin(options, { allowEnvProjectId: false }));
75
- const projects = await options.listProjects();
76
- const target = yield* Result.await(resolveBoundProjectTarget(options, projects, {
77
- allowEnvProjectId: false,
78
- localPin
79
- }));
80
- if (target) return Result.ok(target);
81
- return Result.ok({
82
- workspace: options.workspace,
83
- project: null,
84
- localBinding: { status: "not-linked" },
85
- resolution: { projectSource: "unbound" },
86
- ...await buildProjectSetupSuggestion({
87
- cwd: options.context.runtime.cwd,
88
- projects,
89
- commandName: options.commandName ?? "project show",
90
- signal: options.context.runtime.signal
91
- })
92
- });
93
- });
94
- }
95
- function projectNotFoundError(projectRef, workspace) {
96
- return projectResolutionErrorToCliError(new ProjectNotFoundError(projectRef, workspace));
97
- }
98
- function projectNotFoundCliError(projectRef, workspace) {
99
- return new CliError({
100
- code: "PROJECT_NOT_FOUND",
101
- domain: "project",
102
- summary: "Project not found",
103
- why: `The project "${projectRef}" does not exist in workspace "${workspace.name}" or is not accessible.`,
104
- fix: "Pass a project id or name from prisma-cli project list.",
105
- exitCode: 1,
106
- nextSteps: ["prisma-cli project list"]
107
- });
108
- }
109
- function projectAmbiguousError(projectRef, matches) {
110
- return projectResolutionErrorToCliError(new ProjectAmbiguousError(projectRef, matches));
111
- }
112
- function projectAmbiguousCliError(projectRef, matches) {
113
- const firstMatch = matches[0];
114
- const nextSteps = ["prisma-cli project list"];
115
- if (firstMatch) nextSteps.push(`prisma-cli app deploy --project ${firstMatch.id}`);
116
- return new CliError({
117
- code: "PROJECT_AMBIGUOUS",
118
- domain: "project",
119
- summary: "Project resolution is ambiguous",
120
- why: projectRef ? `Multiple projects matched "${projectRef}".` : "Multiple projects matched the current directory context.",
121
- fix: "Pass --project <id-or-name> to choose the project explicitly.",
122
- meta: { matches: matches.map((project) => ({
123
- id: project.id,
124
- name: project.name
125
- })) },
126
- exitCode: 1,
127
- nextSteps
128
- });
129
- }
130
- function localStateStaleCliError() {
131
- return new CliError({
132
- code: "LOCAL_STATE_STALE",
133
- domain: "project",
134
- summary: "Local project binding is stale",
135
- why: `The target recorded in ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH} is no longer available in the selected workspace.`,
136
- fix: `Delete ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH}, then choose a Project explicitly.`,
137
- meta: { pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH },
138
- exitCode: 1,
139
- nextSteps: ["prisma-cli project list", "prisma-cli project link <id-or-name>"]
140
- });
141
- }
142
- function localProjectWorkspaceMismatchError(options) {
143
- return projectResolutionErrorToCliError(new LocalProjectWorkspaceMismatchError(options));
144
- }
145
- function localProjectWorkspaceMismatchCliError(options) {
146
- return new CliError({
147
- code: "LOCAL_PROJECT_WORKSPACE_MISMATCH",
148
- domain: "project",
149
- summary: "Project link uses another workspace",
150
- why: `${LOCAL_RESOLUTION_PIN_RELATIVE_PATH} links this directory to project ${options.pinnedProjectId} in workspace ${options.pinnedWorkspaceId}, but your current CLI session is workspace "${options.activeWorkspace.name}" (${options.activeWorkspace.id}).`,
151
- fix: "Switch to the linked workspace, or relink this directory to a project in the current workspace.",
152
- meta: {
153
- pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH,
154
- pinnedWorkspaceId: options.pinnedWorkspaceId,
155
- pinnedProjectId: options.pinnedProjectId,
156
- activeWorkspaceId: options.activeWorkspace.id,
157
- activeWorkspaceName: options.activeWorkspace.name
158
- },
159
- exitCode: 1,
160
- nextSteps: [
161
- `prisma-cli auth workspace use ${options.pinnedWorkspaceId}`,
162
- "prisma-cli project list",
163
- "prisma-cli project link <id-or-name>"
164
- ]
165
- });
166
- }
167
- /**
168
- * Converts expected project-resolution variants to command-boundary CliErrors.
169
- * `LocalResolutionPinReadAbortedError` and `UnhandledException` intentionally
170
- * propagate as exceptions; callers such as `resolveProjectShowInRealMode`
171
- * throw this helper's result, so passthrough variants should keep bubbling.
172
- */
173
- function projectResolutionErrorToCliError(error) {
174
- return matchError(error, {
175
- ProjectNotFoundError: (error) => projectNotFoundCliError(error.projectRef, error.workspace),
176
- ProjectAmbiguousError: (error) => projectAmbiguousCliError(error.projectRef, error.matches),
177
- ProjectSetupRequiredError: (error) => projectSetupRequiredCliError(error),
178
- LocalStateStaleError: () => localStateStaleCliError(),
179
- LocalProjectWorkspaceMismatchError: (error) => localProjectWorkspaceMismatchCliError({
180
- pinnedWorkspaceId: error.pinnedWorkspaceId,
181
- pinnedProjectId: error.pinnedProjectId,
182
- activeWorkspace: error.activeWorkspace
183
- }),
184
- LocalResolutionPinReadAbortedError: (error) => {
185
- throw error;
186
- },
187
- UnhandledException: (error) => {
188
- throw error;
189
- }
190
- });
191
- }
192
- async function buildProjectSetupSuggestion(options) {
193
- const suggestedName = await inferTargetName(options.cwd, options.signal);
194
- const candidates = sortProjects(options.projects.filter((project) => projectMatchesSuggestedName(project, suggestedName.name))).map(toProjectSummary);
195
- return {
196
- suggestedProjectName: suggestedName.name,
197
- suggestedProjectNameSource: suggestedName.source,
198
- candidates,
199
- recoveryCommands: buildProjectRecoveryCommands(options.commandName)
200
- };
201
- }
202
- async function projectSetupRequiredError(options) {
203
- const suggestion = await buildProjectSetupSuggestion(options);
204
- return new ProjectSetupRequiredError({
205
- commandName: options.commandName,
206
- suggestion
207
- });
208
- }
209
- function projectSetupRequiredCliError(error) {
210
- const suggestion = error.suggestion;
211
- return new CliError({
212
- code: "PROJECT_SETUP_REQUIRED",
213
- domain: "project",
214
- summary: "Choose a Project before running this command",
215
- why: error.message,
216
- fix: "Link the directory to an existing Project, or pass --project <id-or-name> for this command.",
217
- meta: { ...suggestion },
218
- exitCode: 1,
219
- nextSteps: ["prisma-cli project list", ...suggestion.recoveryCommands],
220
- nextActions: buildProjectSetupNextActions({
221
- commandName: error.commandName,
222
- suggestedProjectName: suggestion.suggestedProjectName
223
- })
224
- });
225
- }
226
- function buildProjectSetupNextActions(options = {}) {
227
- const recoveryCommands = buildProjectRecoveryCommands(options.commandName);
228
- const linkCommand = recoveryCommands[0] ?? "prisma-cli project link <id-or-name>";
229
- const retryCommand = recoveryCommands[1];
230
- const actions = [{
231
- kind: "user-choice",
232
- journey: "project-setup",
233
- label: "Ask the user whether to link an existing Project or create a new one",
234
- commands: ["prisma-cli project list", ...recoveryCommands],
235
- reason: options.reason ?? "This directory is not linked to a Prisma Project. Package and directory names are suggestions only, not a safe Project selection."
236
- }, {
237
- kind: "run-command",
238
- journey: "project-setup",
239
- label: "Link the chosen Project",
240
- command: linkCommand,
241
- reason: "Linking writes the durable local Project binding for this directory."
242
- }];
243
- const createCommand = options.createCommand ?? (options.suggestedProjectName ? `prisma-cli project create ${formatCommandArgument(options.suggestedProjectName)}` : void 0);
244
- if (createCommand) actions.push({
245
- kind: "run-command",
246
- journey: "project-setup",
247
- label: "Create and link a new Project",
248
- command: createCommand,
249
- reason: "Use this when the user wants a new Prisma Project instead of an existing one."
250
- });
251
- if (options.commandName) actions.push({
252
- kind: "run-command",
253
- journey: "recover",
254
- label: "Retry with an explicit Project",
255
- command: retryCommand ?? `prisma-cli ${options.commandName} --project <id-or-name>`
256
- });
257
- return actions;
258
- }
259
- async function readPackageName(cwd, signal) {
260
- signal?.throwIfAborted();
261
- try {
262
- const raw = await readFile(path.join(cwd, "package.json"), {
263
- encoding: "utf8",
264
- signal
265
- });
266
- const parsed = JSON.parse(raw);
267
- if (!parsed || typeof parsed !== "object") return null;
268
- const packageName = "name" in parsed ? parsed.name : null;
269
- return typeof packageName === "string" && packageName.trim().length > 0 ? packageName.trim() : null;
270
- } catch (error) {
271
- if (error.code === "ENOENT") return null;
272
- if (error instanceof SyntaxError) return null;
273
- throw error;
274
- }
275
- }
276
- async function inferTargetName(cwd, signal) {
277
- const packageName = await readPackageName(cwd, signal);
278
- if (packageName && isValidInferredTargetName(packageName)) return {
279
- name: packageName,
280
- source: "package-name"
281
- };
282
- return {
283
- name: path.basename(cwd),
284
- source: "directory-name"
285
- };
286
- }
287
- const INFERRED_TARGET_NAME = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
288
- function isValidInferredTargetName(value) {
289
- return INFERRED_TARGET_NAME.test(value);
290
- }
291
- function sortProjects(projects) {
292
- return projects.slice().sort((left, right) => left.name.localeCompare(right.name) || left.id.localeCompare(right.id));
293
- }
294
- function resolveExplicitProject(projectRef, projects, workspace) {
295
- const matches = projects.filter((project) => project.id === projectRef || project.name === projectRef);
296
- if (matches.length === 1) return Result.ok(matches[0]);
297
- if (matches.length > 1) return Result.err(new ProjectAmbiguousError(projectRef, matches));
298
- return Result.err(new ProjectNotFoundError(projectRef, workspace));
299
- }
300
- function projectMatchesSuggestedName(project, suggestedName) {
301
- return project.id === suggestedName || project.name === suggestedName || project.slug === suggestedName;
302
- }
303
- async function resolveDurablePlatformMapping() {
304
- return null;
305
- }
306
- async function resolveBoundProjectTarget(options, projects, settings) {
307
- if (options.explicitProject) {
308
- const projectResult = resolveExplicitProject(options.explicitProject, projects, options.workspace);
309
- if (projectResult.isErr()) return Result.err(projectResult.error);
310
- return Result.ok(resolvedTarget(options.workspace, projectResult.value, "explicit", {
311
- targetName: options.explicitProject,
312
- targetNameSource: "explicit"
313
- }));
314
- }
315
- if (settings.allowEnvProjectId && options.envProjectId) {
316
- const project = projects.find((candidate) => candidate.id === options.envProjectId);
317
- if (!project) return Result.err(new ProjectNotFoundError(options.envProjectId, options.workspace));
318
- return Result.ok(resolvedTarget(options.workspace, project, "env", {
319
- targetName: options.envProjectId,
320
- targetNameSource: "env"
321
- }));
322
- }
323
- const localPin = settings.localPin;
324
- if (!localPin) return Result.ok(null);
325
- if (localPin.kind === "present") {
326
- if (!sameWorkspaceId(localPin.pin.workspaceId, options.workspace.id)) return Result.err(new LocalProjectWorkspaceMismatchError({
327
- pinnedWorkspaceId: localPin.pin.workspaceId,
328
- pinnedProjectId: localPin.pin.projectId,
329
- activeWorkspace: options.workspace
330
- }));
331
- const project = projects.find((candidate) => candidate.id === localPin.pin.projectId);
332
- if (!project) return Result.err(new LocalStateStaleError());
333
- return Result.ok(resolvedTarget(options.workspace, project, "local-pin", {
334
- targetName: project.name,
335
- targetNameSource: "local-pin"
336
- }));
337
- }
338
- const platformMapping = await resolveDurablePlatformMapping();
339
- if (platformMapping && sameWorkspaceId(platformMapping.workspace.id, options.workspace.id)) return Result.ok(resolvedTarget(options.workspace, platformMapping, "platform-mapping", {
340
- targetName: platformMapping.name,
341
- targetNameSource: "platform-mapping"
342
- }));
343
- return Result.ok(null);
344
- }
345
- async function readImplicitLocalPin(options, settings) {
346
- if (options.explicitProject || settings.allowEnvProjectId && options.envProjectId) return Result.ok(null);
347
- const localPinResult = await readLocalResolutionPin(options.projectDir ?? options.context.runtime.cwd, options.context.runtime.signal);
348
- if (localPinResult.isErr()) return Result.err(localPinReadErrorToProjectError(localPinResult.error));
349
- const localPin = localPinResult.value;
350
- if (localPin.kind === "present" && !sameWorkspaceId(localPin.pin.workspaceId, options.workspace.id)) return Result.err(new LocalProjectWorkspaceMismatchError({
351
- pinnedWorkspaceId: localPin.pin.workspaceId,
352
- pinnedProjectId: localPin.pin.projectId,
353
- activeWorkspace: options.workspace
354
- }));
355
- return Result.ok(localPin);
356
- }
357
- function localPinReadErrorToProjectError(error) {
358
- return matchError(error, {
359
- LocalResolutionPinInvalidJsonError: () => new LocalStateStaleError(),
360
- LocalResolutionPinInvalidShapeError: () => new LocalStateStaleError(),
361
- LocalResolutionPinReadAbortedError: (error) => error,
362
- UnhandledException: (error) => error
363
- });
364
- }
365
- function resolvedTarget(workspace, project, projectSource, resolutionDetails) {
366
- return {
367
- workspace,
368
- project: toProjectSummary(project),
369
- resolution: {
370
- projectSource,
371
- ...resolutionDetails
372
- }
373
- };
374
- }
375
- function buildProjectRecoveryCommands(commandName) {
376
- const commands = ["prisma-cli project link <id-or-name>"];
377
- if (commandName) commands.push(`prisma-cli ${commandName} --project <id-or-name>`);
378
- return commands;
379
- }
380
- function toProjectSummary(project) {
381
- return {
382
- id: project.id,
383
- name: project.name,
384
- ...project.url ? { url: project.url } : {},
385
- ...project.defaultRegion != null ? { defaultRegion: project.defaultRegion } : {}
386
- };
387
- }
388
- //#endregion
389
- export { buildProjectSetupNextActions, inferTargetName, inspectProjectBinding, localProjectWorkspaceMismatchError, projectAmbiguousError, projectNotFoundError, projectResolutionErrorToCliError, resolveDurablePlatformMapping, resolveProjectTarget, sortProjects };