@prisma/cli 3.0.0-beta.1 → 3.0.0-beta.11

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 (66) 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 +64 -23
  6. package/dist/cli.js +18 -3
  7. package/dist/cli2.js +9 -5
  8. package/dist/commands/app/index.js +84 -59
  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 +286 -131
  15. package/dist/controllers/app.js +699 -244
  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 +156 -85
  20. package/dist/lib/app/branch-database-deploy.js +325 -0
  21. package/dist/lib/app/branch-database.js +215 -0
  22. package/dist/lib/app/bun-project.js +12 -5
  23. package/dist/lib/app/compute-config.js +147 -0
  24. package/dist/lib/app/deploy-output.js +10 -1
  25. package/dist/lib/app/deploy-plan.js +58 -0
  26. package/dist/lib/app/env-config.js +1 -1
  27. package/dist/lib/app/env-file.js +82 -0
  28. package/dist/lib/app/env-vars.js +28 -2
  29. package/dist/lib/app/local-dev.js +8 -49
  30. package/dist/lib/app/preview-branch-database.js +102 -0
  31. package/dist/lib/app/preview-build-settings.js +376 -0
  32. package/dist/lib/app/preview-build.js +314 -97
  33. package/dist/lib/app/preview-provider.js +178 -65
  34. package/dist/lib/app/production-deploy-gate.js +161 -0
  35. package/dist/lib/auth/auth-ops.js +30 -21
  36. package/dist/lib/auth/guard.js +3 -2
  37. package/dist/lib/auth/login.js +116 -14
  38. package/dist/lib/database/provider.js +167 -0
  39. package/dist/lib/diagnostics.js +15 -0
  40. package/dist/lib/fs/home-path.js +24 -0
  41. package/dist/lib/git/local-branch.js +53 -0
  42. package/dist/lib/git/local-status.js +57 -0
  43. package/dist/lib/project/interactive-setup.js +1 -1
  44. package/dist/lib/project/local-pin.js +182 -33
  45. package/dist/lib/project/resolution.js +204 -50
  46. package/dist/lib/project/setup.js +66 -19
  47. package/dist/output/patterns.js +1 -1
  48. package/dist/presenters/app-env.js +149 -14
  49. package/dist/presenters/app.js +178 -23
  50. package/dist/presenters/branch.js +37 -102
  51. package/dist/presenters/database.js +274 -0
  52. package/dist/presenters/project.js +57 -39
  53. package/dist/presenters/verbose-context.js +64 -0
  54. package/dist/shell/command-meta.js +103 -13
  55. package/dist/shell/command-runner.js +57 -19
  56. package/dist/shell/diagnostics-output.js +57 -0
  57. package/dist/shell/errors.js +12 -1
  58. package/dist/shell/help.js +30 -20
  59. package/dist/shell/output.js +10 -1
  60. package/dist/shell/runtime.js +11 -7
  61. package/dist/shell/ui.js +42 -3
  62. package/dist/shell/update-check.js +247 -0
  63. package/dist/use-cases/branch.js +20 -68
  64. package/dist/use-cases/create-cli-gateways.js +2 -17
  65. package/dist/use-cases/project.js +2 -1
  66. package/package.json +26 -10
@@ -1,11 +1,13 @@
1
+ import { usageError } from "../../shell/errors.js";
1
2
  import { attachCommandDescriptor } from "../../shell/command-meta.js";
2
3
  import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
3
4
  import { configureRuntimeCommand } from "../../shell/runtime.js";
4
5
  import { PREVIEW_BUILD_TYPES } from "../../lib/app/preview-build.js";
5
6
  import { runAppBuild, runAppDeploy, runAppDomainAdd, runAppDomainRemove, runAppDomainRetry, runAppDomainShow, runAppDomainWait, runAppListDeploys, runAppLogs, runAppOpen, runAppPromote, runAppRemove, runAppRollback, runAppRun, runAppShow, runAppShowDeploy } from "../../controllers/app.js";
6
- import { renderAppBuild, renderAppDeploy, renderAppDomainAdd, renderAppDomainRemove, renderAppDomainRetry, renderAppDomainShow, renderAppListDeploys, renderAppOpen, renderAppPromote, renderAppRemove, renderAppRollback, renderAppRun, renderAppShow, renderAppShowDeploy, serializeAppBuild, serializeAppDeploy, serializeAppDomainAdd, serializeAppDomainRemove, serializeAppDomainRetry, serializeAppDomainShow, serializeAppListDeploys, serializeAppOpen, serializeAppPromote, serializeAppRemove, serializeAppRollback, serializeAppRun, serializeAppShow, serializeAppShowDeploy } from "../../presenters/app.js";
7
+ import { isAppDeployAllResult, renderAppBuild, renderAppDeploy, renderAppDeployAll, renderAppDomainAdd, renderAppDomainRemove, renderAppDomainRetry, renderAppDomainShow, renderAppListDeploys, renderAppOpen, renderAppPromote, renderAppRemove, renderAppRollback, renderAppRun, renderAppShow, renderAppShowDeploy, serializeAppBuild, serializeAppDeploy, serializeAppDeployAll, serializeAppDomainAdd, serializeAppDomainRemove, serializeAppDomainRetry, serializeAppDomainShow, serializeAppListDeploys, serializeAppOpen, serializeAppPromote, serializeAppRemove, serializeAppRollback, serializeAppRun, serializeAppShow, serializeAppShowDeploy } from "../../presenters/app.js";
7
8
  import { runCommand, runStreamingCommand } from "../../shell/command-runner.js";
8
9
  import { Command, Option } from "commander";
10
+ import { FRAMEWORK_KEYS, LOCAL_DEV_BUILD_TYPES } from "@prisma/compute-sdk/config";
9
11
  //#region src/commands/app/index.ts
10
12
  function createAppCommand(runtime) {
11
13
  const app = attachCommandDescriptor(configureRuntimeCommand(new Command("app"), runtime), "app");
@@ -26,12 +28,16 @@ function createAppCommand(runtime) {
26
28
  }
27
29
  function createBuildCommand(runtime) {
28
30
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("build"), runtime), "app.build");
29
- command.addOption(new Option("--entry <path>", "Entrypoint path for Bun or auto builds")).addOption(new Option("--build-type <type>", "Local build type").choices([...PREVIEW_BUILD_TYPES]).default("auto"));
31
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps").addOption(new Option("--entry <path>", "Entrypoint path for Bun or auto builds")).addOption(new Option("--build-type <type>", "Local build type").choices([...PREVIEW_BUILD_TYPES]).default("auto"));
30
32
  addGlobalFlags(command);
31
- command.action(async (options) => {
33
+ command.action(async (configTarget, options) => {
32
34
  const entry = options.entry;
33
35
  const buildType = options.buildType;
34
- await runCommand(runtime, "app.build", options, (context) => runAppBuild(context, entry, buildType), {
36
+ await runCommand(runtime, "app.build", options, (context) => runAppBuild(context, {
37
+ entrypoint: entry,
38
+ buildType,
39
+ configTarget
40
+ }), {
35
41
  renderHuman: (context, descriptor, result) => renderAppBuild(context, descriptor, result),
36
42
  renderJson: (result) => serializeAppBuild(result)
37
43
  });
@@ -40,17 +46,18 @@ function createBuildCommand(runtime) {
40
46
  }
41
47
  function createRunCommand(runtime) {
42
48
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("run"), runtime), "app.run");
43
- command.addOption(new Option("--entry <path>", "Entrypoint path for Bun or auto runs")).addOption(new Option("--build-type <type>", "Local framework type").choices([
44
- "auto",
45
- "bun",
46
- "nextjs"
47
- ]).default("auto")).addOption(new Option("--port <port>", "Local port"));
49
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps").addOption(new Option("--entry <path>", "Entrypoint path for Bun or auto runs")).addOption(new Option("--build-type <type>", "Local framework type").choices(["auto", ...LOCAL_DEV_BUILD_TYPES]).default("auto")).addOption(new Option("--port <port>", "Local port"));
48
50
  addGlobalFlags(command);
49
- command.action(async (options) => {
51
+ command.action(async (configTarget, options) => {
50
52
  const entry = options.entry;
51
53
  const buildType = options.buildType;
52
54
  const port = options.port;
53
- await runCommand(runtime, "app.run", options, (context) => runAppRun(context, entry, buildType, port), {
55
+ await runCommand(runtime, "app.run", options, (context) => runAppRun(context, {
56
+ entrypoint: entry,
57
+ buildType,
58
+ port,
59
+ configTarget
60
+ }), {
54
61
  renderHuman: (context, descriptor, result) => renderAppRun(context, descriptor, result),
55
62
  renderJson: (result) => serializeAppRun(result)
56
63
  });
@@ -59,14 +66,9 @@ function createRunCommand(runtime) {
59
66
  }
60
67
  function createDeployCommand(runtime) {
61
68
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("deploy"), runtime), "app.deploy");
62
- command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--create-project <name>", "Create and link a new Project before deploying")).addOption(new Option("--branch <name>", "Branch name")).addOption(new Option("--framework <name>", "Framework to deploy").choices([
63
- "nextjs",
64
- "hono",
65
- "tanstack-start",
66
- "bun"
67
- ])).addOption(new Option("--entry <path>", "Entrypoint path for Bun deploys")).addOption(new Option("--http-port <port>", "HTTP port override for the deployed app")).addOption(new Option("--env <name=value>", "Environment variable").argParser(collectRepeatableValues));
69
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps").addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--create-project <name>", "Create and link a new Project before deploying")).addOption(new Option("--branch <name>", "Branch name")).addOption(new Option("--framework <name>", "Framework to deploy").choices([...FRAMEWORK_KEYS])).addOption(new Option("--entry <path>", "Entrypoint path for Bun deploys")).addOption(new Option("--http-port <port>", "HTTP port override for the deployed app")).addOption(new Option("--env <name=value|file>", "Environment variable assignment or dotenv file").argParser(collectRepeatableValues)).addOption(new Option("--db", "Create and wire a Prisma Postgres database for this deploy target")).addOption(new Option("--no-db", "Skip database setup")).addOption(new Option("--prod", "Confirm intent to deploy to production"));
68
70
  addGlobalFlags(command);
69
- command.action(async (options) => {
71
+ command.action(async (configTarget, options) => {
70
72
  const appName = options.app;
71
73
  const entry = options.entry;
72
74
  const branchName = options.branch;
@@ -75,29 +77,41 @@ function createDeployCommand(runtime) {
75
77
  const envAssignments = options.env;
76
78
  const projectRef = options.project;
77
79
  const createProjectName = options.createProject;
78
- await runCommand(runtime, "app.deploy", options, (context) => runAppDeploy(context, appName, {
79
- projectRef,
80
- createProjectName,
81
- branchName,
82
- entrypoint: entry,
83
- framework,
84
- httpPort,
85
- envAssignments
86
- }), {
87
- renderHuman: (context, descriptor, result) => renderAppDeploy(context, descriptor, result),
88
- renderJson: (result) => serializeAppDeploy(result)
80
+ const prod = options.prod;
81
+ const db = options.db;
82
+ const hasDbConflict = hasFlag(runtime.argv, "--db") && hasFlag(runtime.argv, "--no-db");
83
+ await runCommand(runtime, "app.deploy", options, (context) => {
84
+ if (hasDbConflict) throw usageError("app deploy accepts either --db or --no-db", "--db requests database setup, while --no-db disables it.", "Pass exactly one database setup flag.", ["prisma-cli app deploy --db", "prisma-cli app deploy --no-db"], "app");
85
+ return runAppDeploy(context, appName, {
86
+ projectRef,
87
+ createProjectName,
88
+ branchName,
89
+ entrypoint: entry,
90
+ framework,
91
+ httpPort,
92
+ envAssignments,
93
+ prod: prod === true,
94
+ db,
95
+ configTarget
96
+ });
97
+ }, {
98
+ renderHuman: (context, descriptor, result) => isAppDeployAllResult(result) ? renderAppDeployAll(context, descriptor, result) : renderAppDeploy(context, descriptor, result),
99
+ renderJson: (result) => isAppDeployAllResult(result) ? serializeAppDeployAll(result) : serializeAppDeploy(result)
89
100
  });
90
101
  });
91
102
  return command;
92
103
  }
104
+ function hasFlag(argv, flag) {
105
+ return argv.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
106
+ }
93
107
  function createShowCommand(runtime) {
94
108
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "app.show");
95
- command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
109
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps").addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
96
110
  addGlobalFlags(command);
97
- command.action(async (options) => {
111
+ command.action(async (configTarget, options) => {
98
112
  const appName = options.app;
99
113
  const projectRef = options.project;
100
- await runCommand(runtime, "app.show", options, (context) => runAppShow(context, appName, projectRef), {
114
+ await runCommand(runtime, "app.show", options, (context) => runAppShow(context, appName, projectRef, configTarget), {
101
115
  renderHuman: (context, descriptor, result) => renderAppShow(context, descriptor, result),
102
116
  renderJson: (result) => serializeAppShow(result)
103
117
  });
@@ -106,12 +120,12 @@ function createShowCommand(runtime) {
106
120
  }
107
121
  function createOpenCommand(runtime) {
108
122
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("open"), runtime), "app.open");
109
- command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
123
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps").addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
110
124
  addGlobalFlags(command);
111
- command.action(async (options) => {
125
+ command.action(async (configTarget, options) => {
112
126
  const appName = options.app;
113
127
  const projectRef = options.project;
114
- await runCommand(runtime, "app.open", options, (context) => runAppOpen(context, appName, projectRef), {
128
+ await runCommand(runtime, "app.open", options, (context) => runAppOpen(context, appName, projectRef, configTarget), {
115
129
  renderHuman: (context, descriptor, result) => renderAppOpen(context, descriptor, result),
116
130
  renderJson: (result) => serializeAppOpen(result)
117
131
  });
@@ -134,16 +148,18 @@ function addDomainTargetOptions(command) {
134
148
  function createDomainAddCommand(runtime) {
135
149
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("add"), runtime), "app.domain.add");
136
150
  command.argument("<hostname>", "Custom domain hostname");
151
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps");
137
152
  addDomainTargetOptions(command);
138
153
  addGlobalFlags(command);
139
- command.action(async (hostname, options) => {
154
+ command.action(async (hostname, configTarget, options) => {
140
155
  const appName = options.app;
141
156
  const projectRef = options.project;
142
157
  const branchName = options.branch;
143
158
  await runCommand(runtime, "app.domain.add", options, (context) => runAppDomainAdd(context, hostname, {
144
159
  appName,
145
160
  projectRef,
146
- branchName
161
+ branchName,
162
+ configTarget
147
163
  }), {
148
164
  renderHuman: (context, descriptor, result) => renderAppDomainAdd(context, descriptor, result),
149
165
  renderJson: (result) => serializeAppDomainAdd(result)
@@ -154,16 +170,18 @@ function createDomainAddCommand(runtime) {
154
170
  function createDomainShowCommand(runtime) {
155
171
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "app.domain.show");
156
172
  command.argument("<hostname>", "Custom domain hostname");
173
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps");
157
174
  addDomainTargetOptions(command);
158
175
  addGlobalFlags(command);
159
- command.action(async (hostname, options) => {
176
+ command.action(async (hostname, configTarget, options) => {
160
177
  const appName = options.app;
161
178
  const projectRef = options.project;
162
179
  const branchName = options.branch;
163
180
  await runCommand(runtime, "app.domain.show", options, (context) => runAppDomainShow(context, hostname, {
164
181
  appName,
165
182
  projectRef,
166
- branchName
183
+ branchName,
184
+ configTarget
167
185
  }), {
168
186
  renderHuman: (context, descriptor, result) => renderAppDomainShow(context, descriptor, result),
169
187
  renderJson: (result) => serializeAppDomainShow(result)
@@ -174,16 +192,18 @@ function createDomainShowCommand(runtime) {
174
192
  function createDomainRemoveCommand(runtime) {
175
193
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("remove"), runtime), "app.domain.remove");
176
194
  command.argument("<hostname>", "Custom domain hostname");
195
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps");
177
196
  addDomainTargetOptions(command);
178
197
  addGlobalFlags(command);
179
- command.action(async (hostname, options) => {
198
+ command.action(async (hostname, configTarget, options) => {
180
199
  const appName = options.app;
181
200
  const projectRef = options.project;
182
201
  const branchName = options.branch;
183
202
  await runCommand(runtime, "app.domain.remove", options, (context) => runAppDomainRemove(context, hostname, {
184
203
  appName,
185
204
  projectRef,
186
- branchName
205
+ branchName,
206
+ configTarget
187
207
  }), {
188
208
  renderHuman: (context, descriptor, result) => renderAppDomainRemove(context, descriptor, result),
189
209
  renderJson: (result) => serializeAppDomainRemove(result)
@@ -194,16 +214,18 @@ function createDomainRemoveCommand(runtime) {
194
214
  function createDomainRetryCommand(runtime) {
195
215
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("retry"), runtime), "app.domain.retry");
196
216
  command.argument("<hostname>", "Custom domain hostname");
217
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps");
197
218
  addDomainTargetOptions(command);
198
219
  addGlobalFlags(command);
199
- command.action(async (hostname, options) => {
220
+ command.action(async (hostname, configTarget, options) => {
200
221
  const appName = options.app;
201
222
  const projectRef = options.project;
202
223
  const branchName = options.branch;
203
224
  await runCommand(runtime, "app.domain.retry", options, (context) => runAppDomainRetry(context, hostname, {
204
225
  appName,
205
226
  projectRef,
206
- branchName
227
+ branchName,
228
+ configTarget
207
229
  }), {
208
230
  renderHuman: (context, descriptor, result) => renderAppDomainRetry(context, descriptor, result),
209
231
  renderJson: (result) => serializeAppDomainRetry(result)
@@ -214,10 +236,11 @@ function createDomainRetryCommand(runtime) {
214
236
  function createDomainWaitCommand(runtime) {
215
237
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("wait"), runtime), "app.domain.wait");
216
238
  command.argument("<hostname>", "Custom domain hostname");
239
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps");
217
240
  addDomainTargetOptions(command);
218
241
  command.addOption(new Option("--timeout <duration>", "Maximum time to wait").default("15m"));
219
242
  addGlobalFlags(command);
220
- command.action(async (hostname, options) => {
243
+ command.action(async (hostname, configTarget, options) => {
221
244
  const appName = options.app;
222
245
  const projectRef = options.project;
223
246
  const branchName = options.branch;
@@ -226,20 +249,21 @@ function createDomainWaitCommand(runtime) {
226
249
  appName,
227
250
  projectRef,
228
251
  branchName,
229
- timeout
252
+ timeout,
253
+ configTarget
230
254
  }));
231
255
  });
232
256
  return command;
233
257
  }
234
258
  function createLogsCommand(runtime) {
235
259
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("logs"), runtime), "app.logs");
236
- command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--deployment <id>", "Deployment id"));
260
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps").addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--deployment <id>", "Deployment id"));
237
261
  addGlobalFlags(command);
238
- command.action(async (options) => {
262
+ command.action(async (configTarget, options) => {
239
263
  const appName = options.app;
240
264
  const deploymentId = options.deployment;
241
265
  const projectRef = options.project;
242
- await runStreamingCommand(runtime, "app.logs", options, (context) => runAppLogs(context, appName, deploymentId, projectRef));
266
+ await runStreamingCommand(runtime, "app.logs", options, (context) => runAppLogs(context, appName, deploymentId, projectRef, configTarget));
243
267
  });
244
268
  return command;
245
269
  }
@@ -248,12 +272,12 @@ function collectRepeatableValues(value, previous) {
248
272
  }
249
273
  function createListDeploysCommand(runtime) {
250
274
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list-deploys"), runtime), "app.list-deploys");
251
- command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
275
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps").addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
252
276
  addGlobalFlags(command);
253
- command.action(async (options) => {
277
+ command.action(async (configTarget, options) => {
254
278
  const appName = options.app;
255
279
  const projectRef = options.project;
256
- await runCommand(runtime, "app.list-deploys", options, (context) => runAppListDeploys(context, appName, projectRef), {
280
+ await runCommand(runtime, "app.list-deploys", options, (context) => runAppListDeploys(context, appName, projectRef, configTarget), {
257
281
  renderHuman: (context, descriptor, result) => renderAppListDeploys(context, descriptor, result),
258
282
  renderJson: (result) => serializeAppListDeploys(result)
259
283
  });
@@ -275,12 +299,13 @@ function createShowDeployCommand(runtime) {
275
299
  function createPromoteCommand(runtime) {
276
300
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("promote"), runtime), "app.promote");
277
301
  command.argument("<deployment>", "Deployment id");
302
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps");
278
303
  command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
279
304
  addGlobalFlags(command);
280
- command.action(async (deploymentId, options) => {
305
+ command.action(async (deploymentId, configTarget, options) => {
281
306
  const appName = options.app;
282
307
  const projectRef = options.project;
283
- await runCommand(runtime, "app.promote", options, (context) => runAppPromote(context, deploymentId, appName, projectRef), {
308
+ await runCommand(runtime, "app.promote", options, (context) => runAppPromote(context, deploymentId, appName, projectRef, configTarget), {
284
309
  renderHuman: (context, descriptor, result) => renderAppPromote(context, descriptor, result),
285
310
  renderJson: (result) => serializeAppPromote(result)
286
311
  });
@@ -289,13 +314,13 @@ function createPromoteCommand(runtime) {
289
314
  }
290
315
  function createRollbackCommand(runtime) {
291
316
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("rollback"), runtime), "app.rollback");
292
- command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--to <deployment>", "Deployment id"));
317
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps").addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--to <deployment>", "Deployment id"));
293
318
  addGlobalFlags(command);
294
- command.action(async (options) => {
319
+ command.action(async (configTarget, options) => {
295
320
  const appName = options.app;
296
321
  const deploymentId = options.to;
297
322
  const projectRef = options.project;
298
- await runCommand(runtime, "app.rollback", options, (context) => runAppRollback(context, appName, deploymentId, projectRef), {
323
+ await runCommand(runtime, "app.rollback", options, (context) => runAppRollback(context, appName, deploymentId, projectRef, configTarget), {
299
324
  renderHuman: (context, descriptor, result) => renderAppRollback(context, descriptor, result),
300
325
  renderJson: (result) => serializeAppRollback(result)
301
326
  });
@@ -304,12 +329,12 @@ function createRollbackCommand(runtime) {
304
329
  }
305
330
  function createRemoveCommand(runtime) {
306
331
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("remove"), runtime), "app.remove");
307
- command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
332
+ command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps").addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
308
333
  addGlobalFlags(command);
309
- command.action(async (options) => {
334
+ command.action(async (configTarget, options) => {
310
335
  const appName = options.app;
311
336
  const projectRef = options.project;
312
- await runCommand(runtime, "app.remove", options, (context) => runAppRemove(context, appName, projectRef), {
337
+ await runCommand(runtime, "app.remove", options, (context) => runAppRemove(context, appName, projectRef, configTarget), {
313
338
  renderHuman: (context, descriptor, result) => renderAppRemove(context, descriptor, result),
314
339
  renderJson: (result) => serializeAppRemove(result)
315
340
  });
@@ -2,16 +2,14 @@ import { attachCommandDescriptor } from "../../shell/command-meta.js";
2
2
  import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
3
3
  import { configureRuntimeCommand } from "../../shell/runtime.js";
4
4
  import { runCommand } from "../../shell/command-runner.js";
5
- import { runBranchList, runBranchShow, runBranchUse } from "../../controllers/branch.js";
6
- import { renderBranchList, renderBranchShow, renderBranchUse, serializeBranchList, serializeBranchShow } from "../../presenters/branch.js";
5
+ import { runBranchList } from "../../controllers/branch.js";
6
+ import { renderBranchList, serializeBranchList } from "../../presenters/branch.js";
7
7
  import { Command } from "commander";
8
8
  //#region src/commands/branch/index.ts
9
9
  function createBranchCommand(runtime) {
10
10
  const branch = attachCommandDescriptor(configureRuntimeCommand(new Command("branch"), runtime), "branch");
11
11
  addCompactGlobalFlags(branch);
12
12
  branch.addCommand(createBranchListCommand(runtime));
13
- branch.addCommand(createBranchShowCommand(runtime));
14
- branch.addCommand(createBranchUseCommand(runtime));
15
13
  return branch;
16
14
  }
17
15
  function createBranchListCommand(runtime) {
@@ -25,28 +23,5 @@ function createBranchListCommand(runtime) {
25
23
  });
26
24
  return command;
27
25
  }
28
- function createBranchShowCommand(runtime) {
29
- const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "branch.show");
30
- addGlobalFlags(command);
31
- command.action(async (options) => {
32
- await runCommand(runtime, "branch.show", options, (context) => runBranchShow(context), {
33
- renderHuman: (context, descriptor, result) => renderBranchShow(context, descriptor, result),
34
- renderJson: (result) => serializeBranchShow(result)
35
- });
36
- });
37
- return command;
38
- }
39
- function createBranchUseCommand(runtime) {
40
- const command = attachCommandDescriptor(configureRuntimeCommand(new Command("use"), runtime), "branch.use");
41
- command.argument("[name]", "Branch name");
42
- addGlobalFlags(command);
43
- command.action(async (branchName, options) => {
44
- await runCommand(runtime, "branch.use", options, (context) => runBranchUse(context, branchName), {
45
- renderHuman: (context, descriptor, result) => renderBranchUse(context, descriptor, result),
46
- renderJson: (result) => serializeBranchShow(result)
47
- });
48
- });
49
- return command;
50
- }
51
26
  //#endregion
52
27
  export { createBranchCommand };
@@ -0,0 +1,159 @@
1
+ import { attachCommandDescriptor } from "../../shell/command-meta.js";
2
+ import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
3
+ import { configureRuntimeCommand } from "../../shell/runtime.js";
4
+ import { runCommand } from "../../shell/command-runner.js";
5
+ import { runDatabaseConnectionCreate, runDatabaseConnectionList, runDatabaseConnectionRemove, runDatabaseCreate, runDatabaseList, runDatabaseRemove, runDatabaseShow } from "../../controllers/database.js";
6
+ import { renderDatabaseConnectionCreate, renderDatabaseConnectionCreateStdout, renderDatabaseConnectionList, renderDatabaseConnectionRemove, renderDatabaseCreate, renderDatabaseCreateStdout, renderDatabaseList, renderDatabaseRemove, renderDatabaseShow, serializeDatabaseConnectionCreate, serializeDatabaseConnectionList, serializeDatabaseConnectionRemove, serializeDatabaseCreate, serializeDatabaseList, serializeDatabaseRemove, serializeDatabaseShow } from "../../presenters/database.js";
7
+ import { Command, Option } from "commander";
8
+ //#region src/commands/database/index.ts
9
+ function createDatabaseCommand(runtime) {
10
+ const database = attachCommandDescriptor(configureRuntimeCommand(new Command("database"), runtime), "database");
11
+ addCompactGlobalFlags(database);
12
+ database.addCommand(createDatabaseListCommand(runtime));
13
+ database.addCommand(createDatabaseShowCommand(runtime));
14
+ database.addCommand(createDatabaseCreateCommand(runtime));
15
+ database.addCommand(createDatabaseRemoveCommand(runtime));
16
+ database.addCommand(createDatabaseConnectionCommand(runtime));
17
+ return database;
18
+ }
19
+ function addProjectAndBranchOptions(command) {
20
+ return command.addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--branch <git-name>", "Branch git name"));
21
+ }
22
+ function createDatabaseListCommand(runtime) {
23
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list"), runtime), "database.list");
24
+ addProjectAndBranchOptions(command);
25
+ addGlobalFlags(command);
26
+ command.action(async (options) => {
27
+ const projectRef = options.project;
28
+ const branchName = options.branch;
29
+ await runCommand(runtime, "database.list", options, (context) => runDatabaseList(context, {
30
+ projectRef,
31
+ branchName
32
+ }), {
33
+ renderHuman: (context, descriptor, result) => renderDatabaseList(context, descriptor, result),
34
+ renderJson: (result) => serializeDatabaseList(result)
35
+ });
36
+ });
37
+ return command;
38
+ }
39
+ function createDatabaseShowCommand(runtime) {
40
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "database.show");
41
+ command.argument("<database>", "Database id or name");
42
+ addProjectAndBranchOptions(command);
43
+ addGlobalFlags(command);
44
+ command.action(async (databaseRef, options) => {
45
+ const projectRef = options.project;
46
+ const branchName = options.branch;
47
+ await runCommand(runtime, "database.show", options, (context) => runDatabaseShow(context, databaseRef, {
48
+ projectRef,
49
+ branchName
50
+ }), {
51
+ renderHuman: (context, descriptor, result) => renderDatabaseShow(context, descriptor, result),
52
+ renderJson: (result) => serializeDatabaseShow(result)
53
+ });
54
+ });
55
+ return command;
56
+ }
57
+ function createDatabaseCreateCommand(runtime) {
58
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("create"), runtime), "database.create");
59
+ command.argument("<name>", "Database name").addOption(new Option("--region <region>", "Prisma Postgres region id"));
60
+ addProjectAndBranchOptions(command);
61
+ addGlobalFlags(command);
62
+ command.action(async (name, options) => {
63
+ const projectRef = options.project;
64
+ const branchName = options.branch;
65
+ const region = options.region;
66
+ await runCommand(runtime, "database.create", options, (context) => runDatabaseCreate(context, name, {
67
+ projectRef,
68
+ branchName,
69
+ region
70
+ }), {
71
+ renderStdout: (context, descriptor, result) => renderDatabaseCreateStdout(context, descriptor, result),
72
+ renderHuman: (context, descriptor, result) => renderDatabaseCreate(context, descriptor, result),
73
+ renderJson: (result) => serializeDatabaseCreate(result)
74
+ });
75
+ });
76
+ return command;
77
+ }
78
+ function createDatabaseRemoveCommand(runtime) {
79
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("remove"), runtime), "database.remove");
80
+ command.argument("<database>", "Database id or name").addOption(new Option("--confirm <database-id>", "Exact database id required to remove"));
81
+ addProjectAndBranchOptions(command);
82
+ addGlobalFlags(command);
83
+ command.action(async (databaseRef, options) => {
84
+ const projectRef = options.project;
85
+ const branchName = options.branch;
86
+ const confirm = options.confirm;
87
+ await runCommand(runtime, "database.remove", options, (context) => runDatabaseRemove(context, databaseRef, {
88
+ projectRef,
89
+ branchName,
90
+ confirm
91
+ }), {
92
+ renderHuman: (context, descriptor, result) => renderDatabaseRemove(context, descriptor, result),
93
+ renderJson: (result) => serializeDatabaseRemove(result)
94
+ });
95
+ });
96
+ return command;
97
+ }
98
+ function createDatabaseConnectionCommand(runtime) {
99
+ const connection = attachCommandDescriptor(configureRuntimeCommand(new Command("connection"), runtime), "database.connection");
100
+ addCompactGlobalFlags(connection);
101
+ connection.addCommand(createDatabaseConnectionListCommand(runtime));
102
+ connection.addCommand(createDatabaseConnectionCreateCommand(runtime));
103
+ connection.addCommand(createDatabaseConnectionRemoveCommand(runtime));
104
+ return connection;
105
+ }
106
+ function createDatabaseConnectionListCommand(runtime) {
107
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list"), runtime), "database.connection.list");
108
+ command.argument("<database>", "Database id or name");
109
+ addProjectAndBranchOptions(command);
110
+ addGlobalFlags(command);
111
+ command.action(async (databaseRef, options) => {
112
+ const projectRef = options.project;
113
+ const branchName = options.branch;
114
+ await runCommand(runtime, "database.connection.list", options, (context) => runDatabaseConnectionList(context, databaseRef, {
115
+ projectRef,
116
+ branchName
117
+ }), {
118
+ renderHuman: (context, descriptor, result) => renderDatabaseConnectionList(context, descriptor, result),
119
+ renderJson: (result) => serializeDatabaseConnectionList(result)
120
+ });
121
+ });
122
+ return command;
123
+ }
124
+ function createDatabaseConnectionCreateCommand(runtime) {
125
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("create"), runtime), "database.connection.create");
126
+ command.argument("<database>", "Database id or name").addOption(new Option("--name <name>", "Connection name"));
127
+ addProjectAndBranchOptions(command);
128
+ addGlobalFlags(command);
129
+ command.action(async (databaseRef, options) => {
130
+ const projectRef = options.project;
131
+ const branchName = options.branch;
132
+ const name = options.name;
133
+ await runCommand(runtime, "database.connection.create", options, (context) => runDatabaseConnectionCreate(context, databaseRef, {
134
+ projectRef,
135
+ branchName,
136
+ name
137
+ }), {
138
+ renderStdout: (context, descriptor, result) => renderDatabaseConnectionCreateStdout(context, descriptor, result),
139
+ renderHuman: (context, descriptor, result) => renderDatabaseConnectionCreate(context, descriptor, result),
140
+ renderJson: (result) => serializeDatabaseConnectionCreate(result)
141
+ });
142
+ });
143
+ return command;
144
+ }
145
+ function createDatabaseConnectionRemoveCommand(runtime) {
146
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("remove"), runtime), "database.connection.remove");
147
+ command.argument("<connection>", "Connection id").addOption(new Option("--confirm <connection-id>", "Exact connection id required to remove"));
148
+ addGlobalFlags(command);
149
+ command.action(async (connectionRef, options) => {
150
+ const confirm = options.confirm;
151
+ await runCommand(runtime, "database.connection.remove", options, (context) => runDatabaseConnectionRemove(context, connectionRef, { confirm }), {
152
+ renderHuman: (context, descriptor, result) => renderDatabaseConnectionRemove(context, descriptor, result),
153
+ renderJson: (result) => serializeDatabaseConnectionRemove(result)
154
+ });
155
+ });
156
+ return command;
157
+ }
158
+ //#endregion
159
+ export { createDatabaseCommand };
@@ -17,16 +17,18 @@ function createEnvCommand(runtime) {
17
17
  }
18
18
  function createEnvAddCommand(runtime) {
19
19
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("add"), runtime), "project.env.add");
20
- command.argument("<assignment>", "Variable assignment as KEY=VALUE or KEY from the current environment").addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--branch <git-name>", "Preview branch override scope")).addOption(new Option("--project <id-or-name>", "Project id or name"));
20
+ command.argument("[assignment]", "Variable assignment as KEY=VALUE or KEY from the current environment").addOption(new Option("--file <path>", "Read KEY=VALUE assignments from a dotenv file")).addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--branch <git-name>", "Preview branch override scope")).addOption(new Option("--project <id-or-name>", "Project id or name"));
21
21
  addGlobalFlags(command);
22
22
  command.action(async (assignment, options) => {
23
23
  const roleName = options.role;
24
24
  const branchName = options.branch;
25
25
  const projectRef = options.project;
26
+ const filePath = options.file;
26
27
  await runCommand(runtime, "project.env.add", options, (context) => runEnvAdd(context, assignment, {
27
28
  roleName,
28
29
  branchName,
29
- projectRef
30
+ projectRef,
31
+ filePath
30
32
  }), {
31
33
  renderHuman: (context, descriptor, result) => renderEnvAdd(context, descriptor, result),
32
34
  renderJson: (result) => serializeEnvAdd(result)
@@ -36,16 +38,18 @@ function createEnvAddCommand(runtime) {
36
38
  }
37
39
  function createEnvUpdateCommand(runtime) {
38
40
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("update"), runtime), "project.env.update");
39
- command.argument("<assignment>", "Variable assignment as KEY=VALUE or KEY from the current environment").addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--branch <git-name>", "Preview branch override scope")).addOption(new Option("--project <id-or-name>", "Project id or name"));
41
+ command.argument("[assignment]", "Variable assignment as KEY=VALUE or KEY from the current environment").addOption(new Option("--file <path>", "Read KEY=VALUE assignments from a dotenv file")).addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--branch <git-name>", "Preview branch override scope")).addOption(new Option("--project <id-or-name>", "Project id or name"));
40
42
  addGlobalFlags(command);
41
43
  command.action(async (assignment, options) => {
42
44
  const roleName = options.role;
43
45
  const branchName = options.branch;
44
46
  const projectRef = options.project;
47
+ const filePath = options.file;
45
48
  await runCommand(runtime, "project.env.update", options, (context) => runEnvUpdate(context, assignment, {
46
49
  roleName,
47
50
  branchName,
48
- projectRef
51
+ projectRef,
52
+ filePath
49
53
  }), {
50
54
  renderHuman: (context, descriptor, result) => renderEnvUpdate(context, descriptor, result),
51
55
  renderJson: (result) => serializeEnvUpdate(result)
@@ -0,0 +1,54 @@
1
+ import { CliError, authRequiredError } from "../shell/errors.js";
2
+ //#region src/controllers/app-env-api.ts
3
+ async function findVariableByNaturalKey(client, projectId, key, resolved, signal) {
4
+ const { data, error, response } = await client.GET("/v1/environment-variables", {
5
+ params: { query: {
6
+ projectId,
7
+ class: resolved.apiTarget.class,
8
+ key
9
+ } },
10
+ signal
11
+ });
12
+ if (error || !data) throw apiCallError(`Failed to look up ${key}`, response, error);
13
+ return data.data.filter((row) => rowMatchesExactScope(row, resolved))[0] ?? null;
14
+ }
15
+ function toMetadata(row, requestedScope) {
16
+ const rowScope = row.branchId === null ? {
17
+ kind: "role",
18
+ role: row.class
19
+ } : requestedScope;
20
+ return {
21
+ id: row.id,
22
+ key: row.key,
23
+ scope: rowScope,
24
+ source: formatDescriptorLabel(rowScope),
25
+ isManagedBySystem: row.isManagedBySystem,
26
+ updatedAt: row.updatedAt
27
+ };
28
+ }
29
+ function rowMatchesExactScope(row, resolved) {
30
+ return row.class === resolved.apiTarget.class && row.branchId === resolved.apiTarget.branchId;
31
+ }
32
+ function apiCallError(summary, response, error) {
33
+ const status = response?.status ?? 0;
34
+ const apiCode = error?.error?.code;
35
+ const apiMessage = error?.error?.message;
36
+ const apiHint = error?.error?.hint;
37
+ if (status === 401 || status === 403) return authRequiredError(["prisma auth login"]);
38
+ return new CliError({
39
+ code: apiCode ?? "ENV_API_ERROR",
40
+ domain: "app",
41
+ summary,
42
+ why: apiMessage ?? `The Management API returned status ${status || "unknown"}.`,
43
+ fix: apiHint ?? "Re-run with --trace for the underlying API response details.",
44
+ exitCode: 1,
45
+ nextSteps: []
46
+ });
47
+ }
48
+ function formatDescriptorLabel(scope) {
49
+ if (scope.kind === "role") return scope.role ?? "unknown";
50
+ if (scope.kind === "overview") return "overview";
51
+ return `branch:${scope.branchName ?? scope.branchId ?? "unknown"}`;
52
+ }
53
+ //#endregion
54
+ export { apiCallError, findVariableByNaturalKey, toMetadata };