@prisma/cli 3.0.0-beta.1 → 3.0.0-beta.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.
Files changed (61) hide show
  1. package/README.md +5 -3
  2. package/dist/adapters/git.js +8 -3
  3. package/dist/adapters/local-state.js +12 -4
  4. package/dist/adapters/mock-api.js +81 -2
  5. package/dist/adapters/token-storage.js +63 -22
  6. package/dist/cli.js +17 -2
  7. package/dist/cli2.js +7 -3
  8. package/dist/commands/app/index.js +22 -10
  9. package/dist/commands/branch/index.js +2 -27
  10. package/dist/commands/database/index.js +159 -0
  11. package/dist/commands/env.js +8 -4
  12. package/dist/controllers/app-env-api.js +54 -0
  13. package/dist/controllers/app-env-file.js +181 -0
  14. package/dist/controllers/app-env.js +283 -129
  15. package/dist/controllers/app.js +247 -106
  16. package/dist/controllers/auth.js +8 -8
  17. package/dist/controllers/branch.js +78 -48
  18. package/dist/controllers/database.js +318 -0
  19. package/dist/controllers/project.js +153 -82
  20. package/dist/lib/app/branch-database-deploy.js +373 -0
  21. package/dist/lib/app/branch-database.js +316 -0
  22. package/dist/lib/app/bun-project.js +12 -5
  23. package/dist/lib/app/deploy-output.js +10 -1
  24. package/dist/lib/app/env-config.js +1 -1
  25. package/dist/lib/app/env-file.js +82 -0
  26. package/dist/lib/app/env-vars.js +28 -2
  27. package/dist/lib/app/local-dev.js +34 -18
  28. package/dist/lib/app/preview-branch-database.js +102 -0
  29. package/dist/lib/app/preview-build-settings.js +385 -0
  30. package/dist/lib/app/preview-build.js +272 -81
  31. package/dist/lib/app/preview-provider.js +163 -54
  32. package/dist/lib/app/production-deploy-gate.js +161 -0
  33. package/dist/lib/auth/auth-ops.js +30 -21
  34. package/dist/lib/auth/guard.js +3 -2
  35. package/dist/lib/auth/login.js +109 -14
  36. package/dist/lib/database/provider.js +167 -0
  37. package/dist/lib/diagnostics.js +15 -0
  38. package/dist/lib/git/local-branch.js +41 -0
  39. package/dist/lib/git/local-status.js +57 -0
  40. package/dist/lib/project/interactive-setup.js +1 -1
  41. package/dist/lib/project/local-pin.js +182 -33
  42. package/dist/lib/project/resolution.js +203 -49
  43. package/dist/lib/project/setup.js +59 -15
  44. package/dist/presenters/app-env.js +149 -14
  45. package/dist/presenters/app.js +170 -20
  46. package/dist/presenters/branch.js +37 -102
  47. package/dist/presenters/database.js +274 -0
  48. package/dist/presenters/project.js +63 -39
  49. package/dist/presenters/verbose-context.js +64 -0
  50. package/dist/shell/command-meta.js +103 -13
  51. package/dist/shell/command-runner.js +34 -6
  52. package/dist/shell/diagnostics-output.js +63 -0
  53. package/dist/shell/errors.js +12 -1
  54. package/dist/shell/output.js +10 -1
  55. package/dist/shell/runtime.js +3 -3
  56. package/dist/shell/ui.js +23 -1
  57. package/dist/shell/update-check.js +247 -0
  58. package/dist/use-cases/branch.js +20 -68
  59. package/dist/use-cases/create-cli-gateways.js +2 -17
  60. package/dist/use-cases/project.js +2 -1
  61. package/package.json +12 -10
@@ -11,32 +11,32 @@ function isRealMode(context) {
11
11
  async function runAuthLogin(context, options) {
12
12
  let result;
13
13
  if (isRealMode(context)) {
14
- await performLogin(context.runtime.env);
15
- result = await readAuthState(context.runtime.env);
14
+ await performLogin(context.runtime.env, context.runtime.signal);
15
+ result = await readAuthState(context.runtime.env, context.runtime.signal);
16
16
  } else result = await loginWithSelectionFlow(context, createAuthUseCases(createCliUseCaseGateways(context)), options);
17
17
  return createAuthSuccess("auth.login", result, ["prisma-cli auth whoami", "prisma-cli project list"]);
18
18
  }
19
19
  async function runAuthLogout(context) {
20
20
  let result;
21
21
  if (isRealMode(context)) {
22
- await performLogout(context.runtime.env);
23
- result = await readAuthState(context.runtime.env);
22
+ await performLogout(context.runtime.env, context.runtime.signal);
23
+ result = await readAuthState(context.runtime.env, context.runtime.signal);
24
24
  } else result = await createAuthUseCases(createCliUseCaseGateways(context)).logout();
25
25
  return createAuthSuccess("auth.logout", result, ["prisma-cli auth login"]);
26
26
  }
27
27
  async function runAuthWhoAmI(context) {
28
28
  let result;
29
- if (isRealMode(context)) result = await readAuthState(context.runtime.env);
29
+ if (isRealMode(context)) result = await readAuthState(context.runtime.env, context.runtime.signal);
30
30
  else result = await createAuthUseCases(createCliUseCaseGateways(context)).whoami();
31
31
  return createAuthSuccess("auth.whoami", result, result.authenticated ? [] : ["prisma-cli auth login"]);
32
32
  }
33
33
  async function requireAuthenticatedAuthState(context) {
34
34
  if (isRealMode(context)) {
35
- const current = await readAuthState(context.runtime.env);
35
+ const current = await readAuthState(context.runtime.env, context.runtime.signal);
36
36
  if (current.authenticated) return current;
37
37
  if (!canPrompt(context)) throw authRequiredError();
38
- await performLogin(context.runtime.env);
39
- return readAuthState(context.runtime.env);
38
+ await performLogin(context.runtime.env, context.runtime.signal);
39
+ return readAuthState(context.runtime.env, context.runtime.signal);
40
40
  }
41
41
  const useCases = createAuthUseCases(createCliUseCaseGateways(context));
42
42
  const current = await useCases.whoami();
@@ -1,73 +1,103 @@
1
- import { featureUnavailableError, usageError } from "../shell/errors.js";
2
- import { canPrompt } from "../shell/runtime.js";
1
+ import { CliError, authRequiredError, workspaceRequiredError } from "../shell/errors.js";
2
+ import { requireComputeAuth } from "../lib/auth/guard.js";
3
+ import { projectResolutionErrorToCliError, resolveProjectTarget } from "../lib/project/resolution.js";
3
4
  import { createCliUseCaseGateways } from "../use-cases/create-cli-gateways.js";
4
- import { createSelectPromptPort } from "./select-prompt-port.js";
5
+ import { requireAuthenticatedAuthState } from "./auth.js";
6
+ import { listRealWorkspaceProjects } from "./project.js";
5
7
  import { createBranchUseCases } from "../use-cases/branch.js";
6
8
  //#region src/controllers/branch.ts
7
- const PREVIEW_BRANCH_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
8
9
  function isRealMode(context) {
9
10
  return !context.runtime.fixturePath && !context.runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
10
11
  }
11
12
  async function runBranchList(context) {
12
- if (isRealMode(context)) throw branchCommandsUnavailableError();
13
- return {
13
+ if (isRealMode(context)) return {
14
14
  command: "branch.list",
15
- result: await createBranchUseCases(createCliUseCaseGateways(context)).list(),
15
+ result: await listRealBranches(context),
16
16
  warnings: [],
17
17
  nextSteps: []
18
18
  };
19
- }
20
- async function runBranchShow(context) {
21
- if (isRealMode(context)) throw branchCommandsUnavailableError();
22
- const result = await createBranchUseCases(createCliUseCaseGateways(context)).show();
23
19
  return {
24
- command: "branch.show",
25
- result,
20
+ command: "branch.list",
21
+ result: await createBranchUseCases(createCliUseCaseGateways(context)).list(),
26
22
  warnings: [],
27
- nextSteps: result.branch.kind === "preview" && !result.branch.remoteState ? ["prisma-cli app deploy"] : []
23
+ nextSteps: []
28
24
  };
29
25
  }
30
- async function runBranchUse(context, branchName) {
31
- if (isRealMode(context)) throw branchCommandsUnavailableError();
32
- const useCases = createBranchUseCases(createCliUseCaseGateways(context));
33
- const resolvedBranchName = await resolveBranchNameForUse(context, useCases, branchName);
34
- validateBranchName(resolvedBranchName);
35
- const result = await useCases.use(resolvedBranchName);
26
+ async function listRealBranches(context) {
27
+ const authState = await requireAuthenticatedAuthState(context);
28
+ const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
29
+ if (!client) throw authRequiredError(["prisma-cli auth login"]);
30
+ const workspace = authState.workspace;
31
+ if (!workspace) throw workspaceRequiredError();
32
+ const targetResult = await resolveProjectTarget({
33
+ context,
34
+ workspace,
35
+ listProjects: () => listRealWorkspaceProjects(client, workspace, context.runtime.signal)
36
+ });
37
+ if (targetResult.isErr()) throw projectResolutionErrorToCliError(targetResult.error);
38
+ const target = targetResult.value;
39
+ const branches = await listBranches(client, target.project.id, context.runtime.signal);
36
40
  return {
37
- command: "branch.use",
38
- result,
39
- warnings: result.branch.kind === "production" ? ["Production is protected and durable. Use with care."] : [],
40
- nextSteps: result.branch.kind === "preview" && !result.branch.remoteState ? ["prisma-cli branch show", "prisma-cli app deploy"] : ["prisma-cli branch show"]
41
+ projectId: target.project.id,
42
+ projectName: target.project.name,
43
+ verboseContext: {
44
+ workspace,
45
+ project: target.project,
46
+ resolution: target.resolution
47
+ },
48
+ branches: sortBranches(branches.map(toBranchSummary))
41
49
  };
42
50
  }
43
- async function resolveBranchNameForUse(context, useCases, branchName) {
44
- if (branchName) return branchName;
45
- if (!canPrompt(context)) throw branchSelectionRequiredError();
46
- const result = await useCases.list();
47
- return createSelectPromptPort(context).select({
48
- message: "Select a branch",
49
- choices: result.branches.map((branch) => ({
50
- label: renderBranchChoiceLabel(branch),
51
- value: branch.name
52
- }))
51
+ function sortBranches(branches) {
52
+ return branches.slice().sort((left, right) => {
53
+ const leftRank = branchOrder(left);
54
+ const rightRank = branchOrder(right);
55
+ if (leftRank !== rightRank) return leftRank - rightRank;
56
+ return left.name.localeCompare(right.name);
53
57
  });
54
58
  }
55
- function renderBranchChoiceLabel(branch) {
56
- const markers = [];
57
- if (branch.active) markers.push("active");
58
- if (!branch.remoteState) markers.push("not created yet");
59
- return markers.length > 0 ? `${branch.name} (${markers.join(", ")})` : branch.name;
59
+ function branchOrder(branch) {
60
+ return branch.role === "production" ? 0 : 1;
60
61
  }
61
- function validateBranchName(branchName) {
62
- if (branchName === "production") return;
63
- if (PREVIEW_BRANCH_PATTERN.test(branchName)) return;
64
- throw usageError("Branch name must use the documented form", "Branch names must be production or a lowercase preview slug such as preview or feat-auth.", "Use production or a lowercase preview branch name with letters, numbers, and hyphens.", ["prisma-cli branch list"], "branch");
62
+ async function listBranches(client, projectId, signal) {
63
+ const collected = [];
64
+ let cursor;
65
+ while (true) {
66
+ const query = {};
67
+ if (cursor !== void 0) query.cursor = cursor;
68
+ const { data, error, response } = await client.GET("/v1/projects/{projectId}/branches", {
69
+ params: {
70
+ path: { projectId },
71
+ query
72
+ },
73
+ signal
74
+ });
75
+ if (error || !data) throw branchApiError("Failed to list branches", response, error);
76
+ collected.push(...data.data);
77
+ if (!data.pagination.hasMore || !data.pagination.nextCursor) break;
78
+ cursor = data.pagination.nextCursor;
79
+ }
80
+ return collected;
65
81
  }
66
- function branchSelectionRequiredError() {
67
- return usageError("Branch use requires a target in non-interactive mode", "This command cannot prompt for branch selection in the current mode.", "Re-run prisma-cli branch use in a TTY, or pass a branch name explicitly.", ["prisma-cli branch list"], "branch");
82
+ function toBranchSummary(branch) {
83
+ return {
84
+ id: branch.id,
85
+ name: branch.gitName,
86
+ role: branch.role,
87
+ envMap: branch.role
88
+ };
68
89
  }
69
- function branchCommandsUnavailableError() {
70
- return featureUnavailableError("Branch commands are not available in this preview", "The current preview cannot resolve or change remote branch context yet.", "Use prisma-cli app deploy for preview app deployment workflows.", ["prisma-cli app deploy --app <name>"], "branch");
90
+ function branchApiError(summary, response, error) {
91
+ const status = response?.status ?? 0;
92
+ return new CliError({
93
+ code: error?.error?.code ?? "BRANCH_API_ERROR",
94
+ domain: "branch",
95
+ summary,
96
+ why: error?.error?.message ?? `The Management API returned status ${status || "unknown"}.`,
97
+ fix: error?.error?.hint ?? "Re-run with --trace for the underlying API response details.",
98
+ exitCode: 1,
99
+ nextSteps: []
100
+ });
71
101
  }
72
102
  //#endregion
73
- export { runBranchList, runBranchShow, runBranchUse };
103
+ export { runBranchList };
@@ -0,0 +1,318 @@
1
+ import { CliError, authRequiredError, usageError, workspaceRequiredError } from "../shell/errors.js";
2
+ import { requireComputeAuth } from "../lib/auth/guard.js";
3
+ import { projectResolutionErrorToCliError, resolveProjectTarget } from "../lib/project/resolution.js";
4
+ import { requireAuthenticatedAuthState } from "./auth.js";
5
+ import { listFixtureWorkspaceProjects, listRealWorkspaceProjects } from "./project.js";
6
+ import { createManagementDatabaseProvider, normalizeConnection, normalizeDatabase } from "../lib/database/provider.js";
7
+ import { randomBytes } from "node:crypto";
8
+ //#region src/controllers/database.ts
9
+ function isRealMode(context) {
10
+ return !context.runtime.fixturePath && !context.runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
11
+ }
12
+ async function runDatabaseList(context, flags) {
13
+ const { provider, target } = await requireDatabaseContext(context, flags, "database list");
14
+ const databases = sortDatabases(await provider.listDatabases({
15
+ projectId: target.project.id,
16
+ branchName: flags.branchName,
17
+ signal: context.runtime.signal
18
+ }));
19
+ return {
20
+ command: "database.list",
21
+ result: {
22
+ projectId: target.project.id,
23
+ projectName: target.project.name,
24
+ branchName: flags.branchName ?? null,
25
+ verboseContext: target,
26
+ databases
27
+ },
28
+ warnings: [],
29
+ nextSteps: []
30
+ };
31
+ }
32
+ async function runDatabaseShow(context, databaseRef, flags) {
33
+ const { provider, target } = await requireDatabaseContext(context, flags, "database show");
34
+ const database = await resolveDatabase(provider, target, databaseRef, flags.branchName, context.runtime.signal);
35
+ const connections = await provider.listConnections(database.id, { signal: context.runtime.signal });
36
+ return {
37
+ command: "database.show",
38
+ result: {
39
+ projectId: target.project.id,
40
+ projectName: target.project.name,
41
+ verboseContext: target,
42
+ database,
43
+ connections
44
+ },
45
+ warnings: [],
46
+ nextSteps: []
47
+ };
48
+ }
49
+ async function runDatabaseCreate(context, name, flags) {
50
+ const databaseName = name.trim();
51
+ if (!databaseName) throw usageError("Database name required", "Database create needs a non-empty name.", "Pass a database name.", ["prisma-cli database create <name>"], "database");
52
+ const { provider, target } = await requireDatabaseContext(context, flags, "database create");
53
+ const created = await provider.createDatabase({
54
+ projectId: target.project.id,
55
+ name: databaseName,
56
+ branchName: flags.branchName,
57
+ region: flags.region,
58
+ signal: context.runtime.signal
59
+ });
60
+ return {
61
+ command: "database.create",
62
+ result: {
63
+ projectId: target.project.id,
64
+ projectName: target.project.name,
65
+ verboseContext: target,
66
+ database: ensureProjectId(created.database, target.project.id),
67
+ connection: created.connection,
68
+ connectionString: created.connectionString
69
+ },
70
+ warnings: [],
71
+ nextSteps: []
72
+ };
73
+ }
74
+ async function runDatabaseRemove(context, databaseRef, flags) {
75
+ const { provider, target } = await requireDatabaseContext(context, flags, "database remove");
76
+ const database = await resolveDatabase(provider, target, databaseRef, flags.branchName, context.runtime.signal);
77
+ requireExactConfirmation({
78
+ resourceName: "database",
79
+ commandName: "database remove",
80
+ id: database.id,
81
+ confirm: flags.confirm
82
+ });
83
+ await provider.removeDatabase(database.id, { signal: context.runtime.signal });
84
+ return {
85
+ command: "database.remove",
86
+ result: {
87
+ projectId: target.project.id,
88
+ projectName: target.project.name,
89
+ verboseContext: target,
90
+ database
91
+ },
92
+ warnings: [],
93
+ nextSteps: []
94
+ };
95
+ }
96
+ async function runDatabaseConnectionList(context, databaseRef, flags) {
97
+ const { provider, target } = await requireDatabaseContext(context, flags, "database connection list");
98
+ const database = await resolveDatabase(provider, target, databaseRef, flags.branchName, context.runtime.signal);
99
+ const connections = await provider.listConnections(database.id, { signal: context.runtime.signal });
100
+ return {
101
+ command: "database.connection.list",
102
+ result: {
103
+ projectId: target.project.id,
104
+ projectName: target.project.name,
105
+ verboseContext: target,
106
+ database,
107
+ connections
108
+ },
109
+ warnings: [],
110
+ nextSteps: []
111
+ };
112
+ }
113
+ async function runDatabaseConnectionCreate(context, databaseRef, flags) {
114
+ const { provider, target } = await requireDatabaseContext(context, flags, "database connection create");
115
+ const database = await resolveDatabase(provider, target, databaseRef, flags.branchName, context.runtime.signal);
116
+ const created = await provider.createConnection({
117
+ databaseId: database.id,
118
+ name: flags.name?.trim() || defaultConnectionName(),
119
+ signal: context.runtime.signal
120
+ });
121
+ return {
122
+ command: "database.connection.create",
123
+ result: {
124
+ projectId: target.project.id,
125
+ projectName: target.project.name,
126
+ verboseContext: target,
127
+ database,
128
+ connection: created.connection,
129
+ connectionString: created.connectionString
130
+ },
131
+ warnings: [],
132
+ nextSteps: []
133
+ };
134
+ }
135
+ async function runDatabaseConnectionRemove(context, connectionRef, flags) {
136
+ const connectionId = connectionRef.trim();
137
+ if (!connectionId) throw usageError("Connection id required", "Database connection removal needs a connection id.", "Pass the connection id to remove.", ["prisma-cli database connection remove <connection-id> --confirm <connection-id>"], "database");
138
+ requireExactConfirmation({
139
+ resourceName: "database connection",
140
+ commandName: "database connection remove",
141
+ id: connectionId,
142
+ confirm: flags.confirm
143
+ });
144
+ await (await requireDatabaseProviderOnly(context)).removeConnection(connectionId, { signal: context.runtime.signal });
145
+ return {
146
+ command: "database.connection.remove",
147
+ result: { connection: { id: connectionId } },
148
+ warnings: [],
149
+ nextSteps: []
150
+ };
151
+ }
152
+ async function requireDatabaseContext(context, flags, commandName) {
153
+ const workspace = (await requireAuthenticatedAuthState(context)).workspace;
154
+ if (!workspace) throw workspaceRequiredError();
155
+ if (isRealMode(context)) {
156
+ const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
157
+ if (!client) throw authRequiredError();
158
+ const targetResult = await resolveProjectTarget({
159
+ context,
160
+ workspace,
161
+ explicitProject: flags.projectRef,
162
+ listProjects: () => listRealWorkspaceProjects(client, workspace, context.runtime.signal),
163
+ commandName
164
+ });
165
+ if (targetResult.isErr()) throw projectResolutionErrorToCliError(targetResult.error);
166
+ return {
167
+ provider: createManagementDatabaseProvider(client),
168
+ target: targetResult.value
169
+ };
170
+ }
171
+ const targetResult = await resolveProjectTarget({
172
+ context,
173
+ workspace,
174
+ explicitProject: flags.projectRef,
175
+ listProjects: async () => listFixtureWorkspaceProjects(context, workspace),
176
+ commandName
177
+ });
178
+ if (targetResult.isErr()) throw projectResolutionErrorToCliError(targetResult.error);
179
+ return {
180
+ provider: createFixtureDatabaseProvider(context),
181
+ target: targetResult.value
182
+ };
183
+ }
184
+ async function requireDatabaseProviderOnly(context) {
185
+ await requireAuthenticatedAuthState(context);
186
+ if (isRealMode(context)) {
187
+ const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
188
+ if (!client) throw authRequiredError();
189
+ return createManagementDatabaseProvider(client);
190
+ }
191
+ return createFixtureDatabaseProvider(context);
192
+ }
193
+ function createFixtureDatabaseProvider(context) {
194
+ return {
195
+ async listDatabases(options) {
196
+ return context.api.listDatabasesForProject(options.projectId, options.branchName).map((database) => normalizeDatabase(database, database.projectId));
197
+ },
198
+ async showDatabase(databaseId) {
199
+ const database = context.api.getDatabase(databaseId);
200
+ return database ? normalizeDatabase(database, database.projectId) : null;
201
+ },
202
+ async createDatabase(options) {
203
+ const created = context.api.createDatabase(options);
204
+ return {
205
+ database: normalizeDatabase(created.database, created.database.projectId),
206
+ connection: normalizeConnection(created.connection, created.connection.databaseId),
207
+ connectionString: created.connectionString
208
+ };
209
+ },
210
+ async removeDatabase(databaseId) {
211
+ if (!context.api.removeDatabase(databaseId)) throw databaseNotFoundError(databaseId);
212
+ },
213
+ async listConnections(databaseId) {
214
+ if (!context.api.getDatabase(databaseId)) throw databaseNotFoundError(databaseId);
215
+ return context.api.listDatabaseConnections(databaseId).map((connection) => normalizeConnection(connection, connection.databaseId));
216
+ },
217
+ async createConnection(options) {
218
+ const created = context.api.createDatabaseConnection(options);
219
+ if (!created) throw databaseNotFoundError(options.databaseId);
220
+ return {
221
+ connection: normalizeConnection(created.connection, created.connection.databaseId),
222
+ connectionString: created.connectionString
223
+ };
224
+ },
225
+ async removeConnection(connectionId) {
226
+ if (!context.api.removeDatabaseConnection(connectionId)) throw connectionNotFoundError(connectionId);
227
+ }
228
+ };
229
+ }
230
+ async function resolveDatabase(provider, target, databaseRef, branchName, signal) {
231
+ const ref = databaseRef.trim();
232
+ if (!ref) throw usageError("Database id or name required", "This command needs a database id or name.", "Pass a database id or name.", ["prisma-cli database list"], "database");
233
+ const matches = (await provider.listDatabases({
234
+ projectId: target.project.id,
235
+ branchName,
236
+ signal
237
+ })).filter((database) => database.id === ref || database.name === ref);
238
+ if (matches.length === 0) throw databaseNotFoundError(ref, target.project.name, branchName);
239
+ if (matches.length > 1) throw databaseAmbiguousError(ref, matches, branchName);
240
+ const selected = matches[0];
241
+ return ensureProjectId(await provider.showDatabase(selected.id, {
242
+ projectId: target.project.id,
243
+ signal
244
+ }) ?? selected, target.project.id);
245
+ }
246
+ function ensureProjectId(database, projectId) {
247
+ return database.projectId ? database : {
248
+ ...database,
249
+ projectId
250
+ };
251
+ }
252
+ function sortDatabases(databases) {
253
+ return databases.slice().sort((left, right) => {
254
+ const branchOrder = (left.branchName ?? "").localeCompare(right.branchName ?? "");
255
+ if (branchOrder !== 0) return branchOrder;
256
+ const nameOrder = left.name.localeCompare(right.name);
257
+ return nameOrder !== 0 ? nameOrder : left.id.localeCompare(right.id);
258
+ });
259
+ }
260
+ function requireExactConfirmation(options) {
261
+ if (options.confirm === options.id) return;
262
+ throw new CliError({
263
+ code: "CONFIRMATION_REQUIRED",
264
+ domain: "database",
265
+ summary: `Confirm ${options.resourceName} removal`,
266
+ why: `Removing this ${options.resourceName} is destructive and requires the exact id.`,
267
+ fix: `Rerun with --confirm ${options.id}.`,
268
+ exitCode: 2,
269
+ nextSteps: [`prisma-cli ${options.commandName} ${options.id} --confirm ${options.id}`],
270
+ meta: {
271
+ expectedConfirm: options.id,
272
+ receivedConfirm: options.confirm ?? null
273
+ }
274
+ });
275
+ }
276
+ function defaultConnectionName() {
277
+ return `cli-${(/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 17)}-${randomBytes(2).toString("hex")}`;
278
+ }
279
+ function databaseNotFoundError(databaseRef, projectName, branchName) {
280
+ return new CliError({
281
+ code: "DATABASE_NOT_FOUND",
282
+ domain: "database",
283
+ summary: "Database not found",
284
+ why: `No database matched "${databaseRef}"${projectName ? ` in project "${projectName}"${branchName ? ` on branch "${branchName}"` : ""}` : ""}.`,
285
+ fix: "Pass a database id or name from prisma-cli database list.",
286
+ exitCode: 1,
287
+ nextSteps: ["prisma-cli database list"]
288
+ });
289
+ }
290
+ function databaseAmbiguousError(databaseRef, matches, branchName) {
291
+ return new CliError({
292
+ code: "DATABASE_AMBIGUOUS",
293
+ domain: "database",
294
+ summary: "Database resolution is ambiguous",
295
+ why: branchName ? `Multiple databases matched "${databaseRef}" on branch "${branchName}".` : `Multiple databases matched "${databaseRef}".`,
296
+ fix: "Pass the database id, or pass --branch <git-name> to narrow the match.",
297
+ exitCode: 1,
298
+ nextSteps: ["prisma-cli database list"],
299
+ meta: { matches: matches.map((database) => ({
300
+ id: database.id,
301
+ name: database.name,
302
+ branchName: database.branchName
303
+ })) }
304
+ });
305
+ }
306
+ function connectionNotFoundError(connectionId) {
307
+ return new CliError({
308
+ code: "DATABASE_CONNECTION_NOT_FOUND",
309
+ domain: "database",
310
+ summary: "Database connection not found",
311
+ why: `No database connection matched "${connectionId}".`,
312
+ fix: "Pass a connection id from prisma-cli database connection list <database>.",
313
+ exitCode: 1,
314
+ nextSteps: ["prisma-cli database connection list <database>"]
315
+ });
316
+ }
317
+ //#endregion
318
+ export { runDatabaseConnectionCreate, runDatabaseConnectionList, runDatabaseConnectionRemove, runDatabaseCreate, runDatabaseList, runDatabaseRemove, runDatabaseShow };