@prisma/cli 3.0.0-dev.101.1 → 3.0.0-dev.104.1

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.
@@ -66,7 +66,7 @@ function createRunCommand(runtime) {
66
66
  }
67
67
  function createDeployCommand(runtime) {
68
68
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("deploy"), runtime), "app.deploy");
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"));
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("--region <region>", "Region for a newly created app; existing apps keep their region")).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"));
70
70
  addGlobalFlags(command);
71
71
  command.action(async (configTarget, options) => {
72
72
  const appName = options.app;
@@ -74,6 +74,7 @@ function createDeployCommand(runtime) {
74
74
  const branchName = options.branch;
75
75
  const framework = options.framework;
76
76
  const httpPort = options.httpPort;
77
+ const region = options.region;
77
78
  const envAssignments = options.env;
78
79
  const projectRef = options.project;
79
80
  const createProjectName = options.createProject;
@@ -89,6 +90,7 @@ function createDeployCommand(runtime) {
89
90
  entrypoint: entry,
90
91
  framework,
91
92
  httpPort,
93
+ region,
92
94
  envAssignments,
93
95
  prod: prod === true,
94
96
  db,
@@ -2,7 +2,7 @@ import { SERVICE_TOKEN_ENV_VAR, getApiBaseUrl } from "../lib/auth/client.js";
2
2
  import { FileTokenStorage } from "../adapters/token-storage.js";
3
3
  import { CliError, authRequiredError, featureUnavailableError, usageError, workspaceRequiredError } from "../shell/errors.js";
4
4
  import { confirmPrompt, selectPrompt, textPrompt } from "../shell/prompt.js";
5
- import { DEFAULT_REGION } from "../lib/app/app-interaction.js";
5
+ import "../lib/app/app-interaction.js";
6
6
  import { PRISMA_APP_CONFIG_FILENAME, detectLegacyBuildSettings, resolveConfiguredAppBuildSettings, resolveInferredAppBuildSettings } from "../lib/app/build-settings.js";
7
7
  import { APP_BUILD_TYPES, APP_BUILD_TYPE_LABELS, RESOLVED_APP_BUILD_TYPES, executeAppBuild } from "../lib/app/build.js";
8
8
  import { envVarNames, parseEnvInputs } from "../lib/app/env-vars.js";
@@ -31,7 +31,7 @@ import { writeJsonEvent } from "../shell/output.js";
31
31
  import { createSelectPromptPort } from "./select-prompt-port.js";
32
32
  import { requireAuthenticatedAuthState } from "./auth.js";
33
33
  import { listRealWorkspaceProjects } from "./project.js";
34
- import { ENTRYPOINT_BUILD_TYPES, FRAMEWORKS, LOCAL_DEV_BUILD_TYPES, frameworkByKey, frameworkFromAlias, isConfigBackedBuildType } from "@prisma/compute-sdk/config";
34
+ import { COMPUTE_REGIONS, ENTRYPOINT_BUILD_TYPES, FRAMEWORKS, LOCAL_DEV_BUILD_TYPES, frameworkByKey, frameworkFromAlias, isConfigBackedBuildType } from "@prisma/compute-sdk/config";
35
35
  import { access, readFile } from "node:fs/promises";
36
36
  import path from "node:path";
37
37
  import { Result, matchError } from "better-result";
@@ -40,6 +40,7 @@ import open from "open";
40
40
  const FRAMEWORK_DEFAULT_HTTP_PORT = 3e3;
41
41
  const PRISMA_PROJECT_ID_ENV_VAR = "PRISMA_PROJECT_ID";
42
42
  const PRISMA_APP_ID_ENV_VAR = "PRISMA_APP_ID";
43
+ const COMPUTE_REGION_IDS = new Set(COMPUTE_REGIONS);
43
44
  function isRealMode(context) {
44
45
  return !context.runtime.fixturePath && !context.runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
45
46
  }
@@ -154,7 +155,7 @@ async function runAppDeploy(context, appName, options) {
154
155
  return runSingleAppDeploy(context, appName, options, config);
155
156
  }
156
157
  async function runAppDeployAll(context, config, plannedTargets, appName, options) {
157
- assertNoPerAppInputsForDeployAll(context, config, appName, options);
158
+ assertNoPerAppInputsForDeployAll(context, plannedTargets, appName, options);
158
159
  const deployments = [];
159
160
  const warnings = [];
160
161
  for (const planned of plannedTargets) {
@@ -172,7 +173,7 @@ async function runAppDeployAll(context, config, plannedTargets, appName, options
172
173
  });
173
174
  warnings.push(...single.warnings);
174
175
  } catch (error) {
175
- throw deployAllFailedError(error, config, planned.index, deployments);
176
+ throw deployAllFailedError(error, plannedTargets, planned.index, deployments);
176
177
  }
177
178
  }
178
179
  return {
@@ -182,12 +183,13 @@ async function runAppDeployAll(context, config, plannedTargets, appName, options
182
183
  nextSteps: ["prisma-cli app list-deploys <app>"]
183
184
  };
184
185
  }
185
- function assertNoPerAppInputsForDeployAll(context, config, appName, options) {
186
+ function assertNoPerAppInputsForDeployAll(context, plannedTargets, appName, options) {
186
187
  const used = perAppInputsForDeployAll({
187
188
  appName,
188
189
  framework: options?.framework,
189
190
  entrypoint: options?.entrypoint,
190
191
  httpPort: options?.httpPort,
192
+ region: options?.region,
191
193
  envAssignments: options?.envAssignments,
192
194
  appIdEnvVar: {
193
195
  name: PRISMA_APP_ID_ENV_VAR,
@@ -195,17 +197,17 @@ function assertNoPerAppInputsForDeployAll(context, config, appName, options) {
195
197
  }
196
198
  });
197
199
  if (used.length === 0) return;
198
- const targets = config.targets.map((target) => target.key).join(", ");
199
- throw usageError(`Deploying all apps does not accept ${used.join(", ")}`, `Without a target, app deploy deploys every configured app (${targets}), so per-app inputs are ambiguous.`, "Pass the app target to apply per-app inputs to one app, or remove them to deploy all apps.", config.targets.map((target) => `prisma-cli app deploy ${target.key}`), "app");
200
+ const targetKeys = plannedTargets.map((target) => target.targetKey);
201
+ throw usageError(`Deploying all apps does not accept ${used.join(", ")}`, `Without a target, app deploy deploys every configured app (${targetKeys.join(", ")}), so per-app inputs are ambiguous.`, "Pass the app target to apply per-app inputs to one app, or remove them to deploy all apps.", targetKeys.map((target) => `prisma-cli app deploy ${target}`), "app");
200
202
  }
201
203
  function maybeRenderDeployAllTargetHeader(context, planned) {
202
204
  if (context.flags.json || context.flags.quiet) return;
203
205
  context.output.stderr.write(`${planned.index > 0 ? "\n" : ""}── ${planned.targetKey} (${planned.index + 1}/${planned.total}) ──\n\n`);
204
206
  }
205
- function deployAllFailedError(error, config, failedIndex, deployments) {
207
+ function deployAllFailedError(error, plannedTargets, failedIndex, deployments) {
206
208
  if (!(error instanceof CliError)) return error;
207
209
  const failure = describeDeployAllFailure({
208
- targetKeys: config.targets.map((target) => target.key),
210
+ targetKeys: plannedTargets.map((target) => target.targetKey),
209
211
  failedIndex,
210
212
  completed: deployments.map(({ target, result }) => ({
211
213
  target,
@@ -255,6 +257,7 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
255
257
  framework: options?.framework,
256
258
  entrypoint: options?.entrypoint,
257
259
  httpPort: options?.httpPort,
260
+ region: options?.region,
258
261
  envInputs: options?.envAssignments
259
262
  },
260
263
  target: computeConfig.target,
@@ -267,6 +270,7 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
267
270
  const localPin = localPinReadResult.value;
268
271
  const branch = await resolveDeployBranch(context, options?.branchName);
269
272
  if (merged.httpPort) parseDeployHttpPort(merged.httpPort.value);
273
+ const deployRegion = normalizeDeployRegionInput(merged.region);
270
274
  assertSupportedEntrypointForRequestedDeployShape({
271
275
  requestedFramework: merged.framework?.value,
272
276
  entrypoint: merged.entrypoint?.value
@@ -299,6 +303,7 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
299
303
  explicitAppName: appName,
300
304
  explicitAppId: envAppId,
301
305
  configAppName: merged.configAppName,
306
+ configRegion: deployRegion,
302
307
  firstDeploy: Boolean(target.localPinAction),
303
308
  inferName: () => inferTargetName(appDir, context.runtime.signal)
304
309
  });
@@ -328,15 +333,9 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
328
333
  const buildType = framework.buildType;
329
334
  assertSupportedEntrypoint(buildType, merged.entrypoint?.value, "deploy");
330
335
  const entrypoint = await resolveDeployEntrypoint(appDir, framework, merged.entrypoint?.value, context.runtime.signal);
331
- if (computeConfig.target?.build) assertConfigBackedBuildSettings(buildType);
332
- const buildSettingsResolution = computeConfig.config && computeConfig.target?.build && isConfigBackedBuildType(buildType) ? await resolveConfiguredAppBuildSettings({
333
- appPath: appDir,
334
- buildType,
335
- configured: computeConfig.target.build,
336
- configPath: computeConfig.config.configPath,
337
- signal: context.runtime.signal
338
- }) : await resolveInferredAppBuildSettings({
339
- appPath: appDir,
336
+ const buildSettingsResolution = await resolveDeployBuildSettings({
337
+ computeConfig,
338
+ appDir,
340
339
  buildType,
341
340
  signal: context.runtime.signal
342
341
  });
@@ -409,7 +408,7 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
409
408
  },
410
409
  entrypoint: entrypoint ?? buildSettingsResolution.settings.entrypoint ?? null,
411
410
  httpPort: runtime.port,
412
- region: selectedApp.region ?? null,
411
+ region: deployResult.app.region ?? selectedApp.region ?? null,
413
412
  envVars: envVarNames(envVars)
414
413
  },
415
414
  durationMs: deployDurationMs,
@@ -419,6 +418,22 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
419
418
  nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${deployResult.deployment.id}`]
420
419
  };
421
420
  }
421
+ async function resolveDeployBuildSettings(options) {
422
+ const { computeConfig, appDir, buildType, signal } = options;
423
+ if (computeConfig.target?.build) assertConfigBackedBuildSettings(buildType);
424
+ if (computeConfig.config && computeConfig.target?.build && isConfigBackedBuildType(buildType)) return resolveConfiguredAppBuildSettings({
425
+ appPath: appDir,
426
+ buildType,
427
+ configured: computeConfig.target.build,
428
+ configPath: computeConfig.config.configPath,
429
+ signal
430
+ });
431
+ return resolveInferredAppBuildSettings({
432
+ appPath: appDir,
433
+ buildType,
434
+ signal
435
+ });
436
+ }
422
437
  async function runAppListDeploys(context, appName, projectRef, configTarget) {
423
438
  ensurePreviewAppMode(context);
424
439
  const compute = await resolveComputeManagementContext(context, configTarget, "list-deploys");
@@ -1276,27 +1291,19 @@ async function sleep(milliseconds, signal) {
1276
1291
  });
1277
1292
  }
1278
1293
  async function resolveDeployAppSelection(context, projectId, apps, options) {
1279
- if (options.explicitAppName) {
1280
- const matches = findAppsByName(apps, options.explicitAppName);
1281
- if (matches.length > 1) return resolveAmbiguousDeployApp(context, matches, options.explicitAppName, options.firstDeploy);
1282
- const matched = matches[0];
1283
- if (matched) return {
1284
- appId: matched.id,
1285
- displayName: matched.name,
1286
- annotation: "set by --app",
1287
- firstDeploy: options.firstDeploy
1288
- };
1289
- return {
1290
- appName: options.explicitAppName,
1291
- region: DEFAULT_REGION,
1292
- displayName: options.explicitAppName,
1293
- annotation: "set by --app",
1294
- firstDeploy: options.firstDeploy
1295
- };
1296
- }
1294
+ const newAppRegion = deployNewAppRegion(options.configRegion);
1295
+ if (options.explicitAppName) return resolveDeployAppByName(context, apps, {
1296
+ name: options.explicitAppName,
1297
+ matchedAnnotation: "set by --app",
1298
+ newAnnotation: "set by --app",
1299
+ requestedRegion: options.configRegion,
1300
+ newAppRegion,
1301
+ firstDeploy: options.firstDeploy
1302
+ });
1297
1303
  if (options.explicitAppId) {
1298
1304
  const matched = apps.find((app) => app.id === options.explicitAppId);
1299
1305
  if (!matched) throw usageError("Selected app does not exist in the resolved project", `The app "${options.explicitAppId}" from ${PRISMA_APP_ID_ENV_VAR} could not be found in resolved project "${projectId}".`, `Unset ${PRISMA_APP_ID_ENV_VAR}, pass --app <name>, or choose an app from prisma-cli app list-deploys.`, ["prisma-cli app list-deploys"], "app");
1306
+ assertDeployRegionMatchesExistingApp(matched, options.configRegion);
1300
1307
  return {
1301
1308
  appId: matched.id,
1302
1309
  displayName: matched.name,
@@ -1306,42 +1313,52 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
1306
1313
  }
1307
1314
  if (options.configAppName) {
1308
1315
  const configName = options.configAppName;
1309
- const matches = findAppsByName(apps, configName.value);
1310
- if (matches.length > 1) return resolveAmbiguousDeployApp(context, matches, configName.value, options.firstDeploy);
1311
- const matched = matches[0];
1312
- if (matched) return {
1313
- appId: matched.id,
1314
- displayName: matched.name,
1315
- annotation: configName.annotation,
1316
+ return resolveDeployAppByName(context, apps, {
1317
+ name: configName.value,
1318
+ matchedAnnotation: configName.annotation,
1319
+ newAnnotation: configName.annotation,
1320
+ requestedRegion: options.configRegion,
1321
+ newAppRegion,
1316
1322
  firstDeploy: options.firstDeploy
1317
- };
1323
+ });
1324
+ }
1325
+ const inferredName = await options.inferName();
1326
+ const newAnnotation = inferredName.source === "package-name" ? "created from package.json" : "created from directory name";
1327
+ return resolveDeployAppByName(context, apps, {
1328
+ name: inferredName.name,
1329
+ matchedAnnotation: "existing app on this branch",
1330
+ newAnnotation,
1331
+ requestedRegion: options.configRegion,
1332
+ newAppRegion,
1333
+ firstDeploy: options.firstDeploy
1334
+ });
1335
+ }
1336
+ async function resolveDeployAppByName(context, apps, options) {
1337
+ const matches = findAppsByName(apps, options.name);
1338
+ if (matches.length > 1) return resolveAmbiguousDeployApp(context, matches, options.name, options.requestedRegion, options.newAppRegion, options.firstDeploy);
1339
+ const matched = matches[0];
1340
+ if (matched) {
1341
+ assertDeployRegionMatchesExistingApp(matched, options.requestedRegion);
1318
1342
  return {
1319
- appName: configName.value,
1320
- region: DEFAULT_REGION,
1321
- displayName: configName.value,
1322
- annotation: configName.annotation,
1343
+ appId: matched.id,
1344
+ displayName: matched.name,
1345
+ annotation: options.matchedAnnotation,
1323
1346
  firstDeploy: options.firstDeploy
1324
1347
  };
1325
1348
  }
1326
- const inferredName = await options.inferName();
1327
- const matches = findAppsByName(apps, inferredName.name);
1328
- if (matches.length > 1) return resolveAmbiguousDeployApp(context, matches, inferredName.name, options.firstDeploy);
1329
- const matched = matches[0];
1330
- if (matched) return {
1331
- appId: matched.id,
1332
- displayName: matched.name,
1333
- annotation: "existing app on this branch",
1334
- firstDeploy: options.firstDeploy
1335
- };
1336
1349
  return {
1337
- appName: inferredName.name,
1338
- region: DEFAULT_REGION,
1339
- displayName: inferredName.name,
1340
- annotation: inferredName.source === "package-name" ? "created from package.json" : "created from directory name",
1350
+ appName: options.name,
1351
+ region: options.newAppRegion,
1352
+ displayName: options.name,
1353
+ annotation: options.newAnnotation,
1341
1354
  firstDeploy: options.firstDeploy
1342
1355
  };
1343
1356
  }
1344
- async function resolveAmbiguousDeployApp(context, matches, targetName, firstDeploy) {
1357
+ function assertDeployRegionMatchesExistingApp(app, requestedRegion) {
1358
+ if (requestedRegion?.annotation !== "set by --region" || !app.region || app.region === requestedRegion.value) return;
1359
+ throw usageError("App already exists in another region", `The selected app "${app.name}" is in region "${app.region}", but --region requested "${requestedRegion.value}".`, "Remove --region to deploy the existing app, or pass --app <new-name> to create a new app in that region.", [`prisma-cli app deploy --app ${formatCommandArgument(app.name)}`, `prisma-cli app deploy --app <new-name> --region ${formatCommandArgument(requestedRegion.value)}`], "app");
1360
+ }
1361
+ async function resolveAmbiguousDeployApp(context, matches, targetName, requestedRegion, newAppRegion, firstDeploy) {
1345
1362
  if (canPrompt(context)) {
1346
1363
  const createNew = "__create_new_app__";
1347
1364
  const cancel = "__cancel__";
@@ -1367,11 +1384,12 @@ async function resolveAmbiguousDeployApp(context, matches, targetName, firstDepl
1367
1384
  if (selected === cancel) throw usageError("App selection canceled", "The command was canceled before an app was selected.", "Re-run the command and choose an app, or pass --app <name>.", ["prisma-cli app deploy --app <name>"], "app");
1368
1385
  if (selected === createNew) return {
1369
1386
  appName: targetName,
1370
- region: DEFAULT_REGION,
1387
+ region: newAppRegion,
1371
1388
  displayName: targetName,
1372
1389
  annotation: "created from package.json",
1373
1390
  firstDeploy
1374
1391
  };
1392
+ assertDeployRegionMatchesExistingApp(selected, requestedRegion);
1375
1393
  return {
1376
1394
  appId: selected.id,
1377
1395
  displayName: selected.name,
@@ -1393,6 +1411,9 @@ async function resolveAmbiguousDeployApp(context, matches, targetName, firstDepl
1393
1411
  nextSteps: ["prisma-cli app deploy --app <name>"]
1394
1412
  });
1395
1413
  }
1414
+ function deployNewAppRegion(configRegion) {
1415
+ return configRegion?.value ?? "eu-central-1";
1416
+ }
1396
1417
  async function resolveExistingAppSelection(context, projectId, apps, explicitAppName) {
1397
1418
  if (explicitAppName) {
1398
1419
  const matched = findAppByName(apps, explicitAppName);
@@ -2198,6 +2219,19 @@ function parseDeployHttpPort(requestedPort) {
2198
2219
  if (!Number.isInteger(port) || port <= 0 || port > 65535) throw usageError(`Invalid HTTP port "${requestedPort}"`, "HTTP port must be an integer between 1 and 65535.", "Pass --http-port <number> with a valid port value.", ["prisma-cli app deploy --http-port 3000"], "app");
2199
2220
  return port;
2200
2221
  }
2222
+ function parseDeployRegion(requestedRegion, source) {
2223
+ const region = requestedRegion.trim();
2224
+ if (region.length === 0) throw usageError("Invalid app region", `The app region ${source} must be a non-empty region id.`, "Pass a Prisma Compute region id.", ["prisma-cli app deploy --region eu-central-1"], "app");
2225
+ if (!COMPUTE_REGION_IDS.has(region)) throw usageError("Invalid app region", `The app region ${source} must be one of: ${COMPUTE_REGIONS.join(", ")}.`, "Pass a supported Prisma Compute region id.", ["prisma-cli app deploy --region eu-central-1"], "app");
2226
+ return region;
2227
+ }
2228
+ function normalizeDeployRegionInput(region) {
2229
+ if (!region) return;
2230
+ return {
2231
+ ...region,
2232
+ value: parseDeployRegion(region.value, region.annotation)
2233
+ };
2234
+ }
2201
2235
  function ensurePreviewAppMode(context) {
2202
2236
  if (isRealMode(context)) return;
2203
2237
  throw featureUnavailableError("App commands are not available in fixture mode", "Preview app commands require live app deployment integration.", "Rerun without fixture mode enabled to use preview app deployment workflows.", ["prisma-cli auth login", "prisma-cli project show"], "app");
@@ -2254,7 +2288,7 @@ function appDeployFailedError(error, progress) {
2254
2288
  }
2255
2289
  if (!progress.buildStarted) return deployFailedError("App deploy failed", error, ["prisma-cli app deploy"]);
2256
2290
  const phaseHeadline = progress.containerLive ? "The deployment started, but the app is not ready yet." : "Deploy failed after the build completed.";
2257
- const recoveryLines = progress.versionId ? ["See what happened", `prisma-cli app logs --deployment ${progress.versionId}`] : ["Fix", "Retry the command, or rerun with --trace for more detailed diagnostics."];
2291
+ const recoveryLines = progress.deploymentId ? ["See what happened", `prisma-cli app logs --deployment ${progress.deploymentId}`] : ["Fix", "Retry the command, or rerun with --trace for more detailed diagnostics."];
2258
2292
  const urlLines = progress.deploymentUrl ? [
2259
2293
  "",
2260
2294
  "URL",
@@ -2280,11 +2314,11 @@ function appDeployFailedError(error, progress) {
2280
2314
  domain: "app",
2281
2315
  summary: phaseHeadline,
2282
2316
  why,
2283
- fix: progress.versionId ? `Inspect logs with prisma-cli app logs --deployment ${progress.versionId}.` : "Retry the command, or rerun with --trace for more detailed diagnostics.",
2317
+ fix: progress.deploymentId ? `Inspect logs with prisma-cli app logs --deployment ${progress.deploymentId}.` : "Retry the command, or rerun with --trace for more detailed diagnostics.",
2284
2318
  debug,
2285
2319
  meta: {
2286
2320
  phase: progress.containerLive ? "runtime_ready" : "deploy",
2287
- deploymentId: progress.versionId,
2321
+ deploymentId: progress.deploymentId,
2288
2322
  deploymentUrl: progress.deploymentUrl
2289
2323
  },
2290
2324
  humanLines,
@@ -68,14 +68,14 @@ function createAppProvider(client, options) {
68
68
  return deleteEnvironmentVariable(client, options);
69
69
  },
70
70
  async removeApp(appId, options) {
71
- const appResult = await sdk.showService({
72
- serviceId: appId,
71
+ const appResult = await sdk.showApp({
72
+ appId,
73
73
  signal: options?.signal
74
74
  });
75
75
  if (appResult.isErr()) throw new Error(appResult.error.message);
76
- const destroyResult = await sdk.destroyService({
77
- serviceId: appId,
78
- keepService: false,
76
+ const destroyResult = await sdk.destroyApp({
77
+ appId,
78
+ keepApp: false,
79
79
  timeoutSeconds: 120,
80
80
  pollIntervalMs: 2e3,
81
81
  signal: options?.signal
@@ -90,8 +90,8 @@ function createAppProvider(client, options) {
90
90
  return listComputeServiceDomains(client, appId, options?.signal);
91
91
  },
92
92
  async addDomain(options) {
93
- const result = await client.POST("/v1/compute-services/{computeServiceId}/domains", {
94
- params: { path: { computeServiceId: options.appId } },
93
+ const result = await client.POST("/v1/apps/{appId}/domains", {
94
+ params: { path: { appId: options.appId } },
95
95
  body: { hostname: options.hostname },
96
96
  signal: options.signal
97
97
  });
@@ -135,8 +135,8 @@ function createAppProvider(client, options) {
135
135
  },
136
136
  async promoteDeployment(options) {
137
137
  const promoteResult = await sdk.promote({
138
- serviceId: options.appId,
139
- versionId: options.deploymentId,
138
+ appId: options.appId,
139
+ deploymentId: options.deploymentId,
140
140
  timeoutSeconds: 120,
141
141
  pollIntervalMs: 2e3,
142
142
  signal: options.signal,
@@ -169,8 +169,8 @@ function createAppProvider(client, options) {
169
169
  buildSettings: options.buildSettings
170
170
  }),
171
171
  projectId: options.projectId,
172
- serviceId: resolvedApp.appId,
173
- serviceName: resolvedApp.appName,
172
+ appId: resolvedApp.appId,
173
+ appName: resolvedApp.appName,
174
174
  region: resolvedApp.region,
175
175
  portMapping: options.portMapping,
176
176
  envVars: options.envVars,
@@ -185,22 +185,22 @@ function createAppProvider(client, options) {
185
185
  return {
186
186
  projectId: deployed.projectId,
187
187
  app: {
188
- id: deployed.serviceId,
189
- name: deployed.serviceName,
188
+ id: deployed.appId,
189
+ name: deployed.appName,
190
190
  region: deployed.region ?? null,
191
- liveDeploymentId: deployed.versionId,
192
- liveUrl: toAbsoluteUrl(deployed.serviceEndpointDomain ?? null)
191
+ liveDeploymentId: deployed.deploymentId,
192
+ liveUrl: toAbsoluteUrl(deployed.appEndpointDomain ?? null)
193
193
  },
194
194
  deployment: {
195
- id: deployed.versionId,
195
+ id: deployed.deploymentId,
196
196
  status: "running",
197
- url: toAbsoluteUrl(deployed.serviceEndpointDomain ?? deployed.versionEndpointDomain ?? null)
197
+ url: toAbsoluteUrl(deployed.appEndpointDomain ?? deployed.deploymentEndpointDomain ?? null)
198
198
  }
199
199
  };
200
200
  },
201
201
  async updateAppEnv(options) {
202
202
  const updateResult = await sdk.updateEnv({
203
- serviceId: options.appId,
203
+ appId: options.appId,
204
204
  envVars: options.envVars,
205
205
  timeoutSeconds: 120,
206
206
  pollIntervalMs: 2e3,
@@ -209,19 +209,19 @@ function createAppProvider(client, options) {
209
209
  });
210
210
  if (updateResult.isErr()) throw new Error(updateResult.error.message);
211
211
  const promoteResult = await sdk.promote({
212
- serviceId: options.appId,
213
- versionId: updateResult.value.versionId,
212
+ appId: options.appId,
213
+ deploymentId: updateResult.value.deploymentId,
214
214
  timeoutSeconds: 120,
215
215
  pollIntervalMs: 2e3,
216
216
  signal: options.signal,
217
217
  progress: options.promoteProgress
218
218
  });
219
219
  if (promoteResult.isErr()) throw new Error(promoteResult.error.message);
220
- const [serviceResult, versionResult] = await Promise.all([sdk.showService({
221
- serviceId: options.appId,
220
+ const [serviceResult, versionResult] = await Promise.all([sdk.showApp({
221
+ appId: options.appId,
222
222
  signal: options.signal
223
- }), sdk.showVersion({
224
- versionId: updateResult.value.versionId,
223
+ }), sdk.showDeployment({
224
+ deploymentId: updateResult.value.deploymentId,
225
225
  signal: options.signal
226
226
  })]);
227
227
  if (serviceResult.isErr()) throw new Error(serviceResult.error.message);
@@ -232,25 +232,25 @@ function createAppProvider(client, options) {
232
232
  id: serviceResult.value.id,
233
233
  name: serviceResult.value.name,
234
234
  region: serviceResult.value.region ?? null,
235
- liveDeploymentId: serviceResult.value.latestVersionId ?? null,
236
- liveUrl: toAbsoluteUrl(serviceResult.value.serviceEndpointDomain ?? null)
235
+ liveDeploymentId: serviceResult.value.latestDeploymentId ?? null,
236
+ liveUrl: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? null)
237
237
  },
238
238
  deployment: {
239
239
  id: versionResult.value.id,
240
240
  status: versionResult.value.status,
241
241
  createdAt: versionResult.value.createdAt,
242
- url: toAbsoluteUrl(serviceResult.value.serviceEndpointDomain ?? versionResult.value.previewDomain ?? null),
242
+ url: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? versionResult.value.previewDomain ?? null),
243
243
  live: true
244
244
  },
245
245
  variables: envVarNames(versionResult.value.envVars)
246
246
  };
247
247
  },
248
248
  async listAppEnvNames(options) {
249
- const [serviceResult, versionResult] = await Promise.all([sdk.showService({
250
- serviceId: options.appId,
249
+ const [serviceResult, versionResult] = await Promise.all([sdk.showApp({
250
+ appId: options.appId,
251
251
  signal: options.signal
252
- }), sdk.showVersion({
253
- versionId: options.deploymentId,
252
+ }), sdk.showDeployment({
253
+ deploymentId: options.deploymentId,
254
254
  signal: options.signal
255
255
  })]);
256
256
  if (serviceResult.isErr()) throw new Error(serviceResult.error.message);
@@ -261,25 +261,25 @@ function createAppProvider(client, options) {
261
261
  id: serviceResult.value.id,
262
262
  name: serviceResult.value.name,
263
263
  region: serviceResult.value.region ?? null,
264
- liveDeploymentId: serviceResult.value.latestVersionId ?? null,
265
- liveUrl: toAbsoluteUrl(serviceResult.value.serviceEndpointDomain ?? null)
264
+ liveDeploymentId: serviceResult.value.latestDeploymentId ?? null,
265
+ liveUrl: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? null)
266
266
  },
267
267
  deployment: {
268
268
  id: versionResult.value.id,
269
269
  status: versionResult.value.status,
270
270
  createdAt: versionResult.value.createdAt,
271
271
  url: toAbsoluteUrl(versionResult.value.previewDomain ?? null),
272
- live: serviceResult.value.latestVersionId === versionResult.value.id
272
+ live: serviceResult.value.latestDeploymentId === versionResult.value.id
273
273
  },
274
274
  variables: envVarNames(versionResult.value.envVars)
275
275
  };
276
276
  },
277
277
  async listDeployments(appId, options) {
278
- const [appResult, versionsResult] = await Promise.all([sdk.showService({
279
- serviceId: appId,
278
+ const [appResult, versionsResult] = await Promise.all([sdk.showApp({
279
+ appId,
280
280
  signal: options?.signal
281
- }), sdk.listVersions({
282
- serviceId: appId,
281
+ }), sdk.listDeployments({
282
+ appId,
283
283
  signal: options?.signal
284
284
  })]);
285
285
  if (appResult.isErr()) throw new Error(appResult.error.message);
@@ -289,8 +289,8 @@ function createAppProvider(client, options) {
289
289
  id: appResult.value.id,
290
290
  name: appResult.value.name,
291
291
  region: appResult.value.region ?? null,
292
- liveDeploymentId: appResult.value.latestVersionId ?? null,
293
- liveUrl: toAbsoluteUrl(appResult.value.serviceEndpointDomain ?? null)
292
+ liveDeploymentId: appResult.value.latestDeploymentId ?? null,
293
+ liveUrl: toAbsoluteUrl(appResult.value.appEndpointDomain ?? null)
294
294
  },
295
295
  deployments: versionsResult.value.slice().sort((left, right) => {
296
296
  const byDate = right.createdAt.localeCompare(left.createdAt);
@@ -305,8 +305,8 @@ function createAppProvider(client, options) {
305
305
  };
306
306
  },
307
307
  async showDeployment(deploymentId, options) {
308
- const deploymentResult = await sdk.showVersion({
309
- versionId: deploymentId,
308
+ const deploymentResult = await sdk.showDeployment({
309
+ deploymentId,
310
310
  signal: options?.signal
311
311
  });
312
312
  if (deploymentResult.isErr()) {
@@ -329,7 +329,7 @@ function createAppProvider(client, options) {
329
329
  const result = await streamLogs({
330
330
  baseUrl: options.baseUrl,
331
331
  token: await options.getToken(),
332
- versionId: streamOptions.deploymentId,
332
+ deploymentId: streamOptions.deploymentId,
333
333
  signal: streamOptions.signal
334
334
  }, streamOptions.onRecord);
335
335
  if (result.isErr()) {
@@ -382,7 +382,7 @@ async function listComputeServices(client, options) {
382
382
  const services = [];
383
383
  let cursor;
384
384
  while (true) {
385
- const result = await client.GET("/v1/compute-services", {
385
+ const result = await client.GET("/v1/apps", {
386
386
  params: { query: {
387
387
  projectId: options.projectId,
388
388
  branchGitName: options.branchGitName,
@@ -400,13 +400,13 @@ async function listComputeServices(client, options) {
400
400
  name: service.name,
401
401
  region: service.region.id ?? null,
402
402
  branchId: service.branchId,
403
- liveDeploymentId: service.latestVersionId ?? null,
404
- liveUrl: toAbsoluteUrl(service.serviceEndpointDomain ?? null)
403
+ liveDeploymentId: service.latestDeploymentId ?? null,
404
+ liveUrl: toAbsoluteUrl(service.appEndpointDomain ?? null)
405
405
  }));
406
406
  }
407
407
  async function listComputeServiceDomains(client, computeServiceId, signal) {
408
- const result = await client.GET("/v1/compute-services/{computeServiceId}/domains", {
409
- params: { path: { computeServiceId } },
408
+ const result = await client.GET("/v1/apps/{appId}/domains", {
409
+ params: { path: { appId: computeServiceId } },
410
410
  signal
411
411
  });
412
412
  if (result.error || !result.data) throw domainApiCallError("Failed to list custom domains", result.response, result.error);
@@ -453,7 +453,7 @@ async function createBranchApp(client, options) {
453
453
  gitName: options.branchName,
454
454
  signal: options.signal
455
455
  });
456
- const result = await client.POST("/v1/compute-services", {
456
+ const result = await client.POST("/v1/apps", {
457
457
  body: {
458
458
  projectId: options.projectId,
459
459
  branchId: branch.id,
@@ -503,7 +503,7 @@ async function findAppForDeployment(sdk, deploymentId, signal) {
503
503
  const projectsResult = await sdk.listProjects({ signal });
504
504
  if (projectsResult.isErr()) throw new Error(projectsResult.error.message);
505
505
  for (const project of projectsResult.value) {
506
- const servicesResult = await sdk.listServices({
506
+ const servicesResult = await sdk.listApps({
507
507
  projectId: project.id,
508
508
  signal
509
509
  });
@@ -516,8 +516,8 @@ async function findAppForDeployment(sdk, deploymentId, signal) {
516
516
  return null;
517
517
  }
518
518
  async function findServiceAppForDeployment(sdk, serviceId, deploymentId, signal) {
519
- const detailResult = await sdk.showService({
520
- serviceId,
519
+ const detailResult = await sdk.showApp({
520
+ appId: serviceId,
521
521
  signal
522
522
  });
523
523
  if (detailResult.isErr()) throw new Error(detailResult.error.message);
@@ -525,12 +525,12 @@ async function findServiceAppForDeployment(sdk, serviceId, deploymentId, signal)
525
525
  id: detailResult.value.id,
526
526
  name: detailResult.value.name,
527
527
  region: detailResult.value.region ?? null,
528
- liveDeploymentId: detailResult.value.latestVersionId ?? null,
529
- liveUrl: toAbsoluteUrl(detailResult.value.serviceEndpointDomain ?? null)
528
+ liveDeploymentId: detailResult.value.latestDeploymentId ?? null,
529
+ liveUrl: toAbsoluteUrl(detailResult.value.appEndpointDomain ?? null)
530
530
  };
531
531
  if (app.liveDeploymentId === deploymentId) return app;
532
- const versionsResult = await sdk.listVersions({
533
- serviceId,
532
+ const versionsResult = await sdk.listDeployments({
533
+ appId: serviceId,
534
534
  signal
535
535
  });
536
536
  if (versionsResult.isErr()) throw new Error(versionsResult.error.message);
@@ -18,47 +18,45 @@ function computeFrameworkToBuildType(framework) {
18
18
  function mergeComputeDeployInputs(options) {
19
19
  const { cli, target, configFilename } = options;
20
20
  const configAnnotation = `set by ${configFilename}`;
21
- const framework = cli.framework ? {
22
- value: cli.framework,
23
- annotation: "set by --framework"
24
- } : target?.framework ? {
25
- value: target.framework,
26
- annotation: configAnnotation
27
- } : void 0;
28
- const entrypoint = cli.entrypoint ? {
29
- value: cli.entrypoint,
30
- annotation: "set by --entry"
31
- } : target?.entry ? {
32
- value: target.entry,
33
- annotation: configAnnotation
34
- } : void 0;
35
- const httpPort = cli.httpPort ? {
36
- value: cli.httpPort,
37
- annotation: "set by --http-port"
38
- } : target?.httpPort ? {
39
- value: String(target.httpPort),
40
- annotation: configAnnotation
41
- } : void 0;
21
+ const framework = mergeStringInput(cli.framework, "set by --framework", target?.framework ?? void 0, configAnnotation);
22
+ const entrypoint = mergeStringInput(cli.entrypoint, "set by --entry", target?.entry ?? void 0, configAnnotation);
23
+ const httpPort = mergeStringInput(cli.httpPort, "set by --http-port", target?.httpPort ? String(target.httpPort) : void 0, configAnnotation);
24
+ const region = mergeStringInput(cli.region, "set by --region", target?.region ?? void 0, configAnnotation);
42
25
  const cliEnvInputs = cli.envInputs && cli.envInputs.length > 0 ? cli.envInputs : void 0;
43
26
  const configEnvInputs = target && target.envInputs.length > 0 ? target.envInputs : void 0;
44
27
  const envInputs = cliEnvInputs ?? configEnvInputs;
45
- const configAppName = target?.name ? {
46
- value: target.name,
47
- annotation: configAnnotation
48
- } : target?.key ? {
49
- value: target.key,
50
- annotation: configAnnotation
51
- } : void 0;
28
+ const configAppName = readConfigAppName(target, configAnnotation);
52
29
  return {
53
30
  framework,
54
31
  entrypoint,
55
32
  httpPort,
33
+ region,
56
34
  envInputs,
57
35
  envInputsFromConfig: !cliEnvInputs && configEnvInputs !== void 0,
58
36
  configAppName,
59
37
  appRoot: target?.root ?? void 0
60
38
  };
61
39
  }
40
+ function mergeStringInput(cliValue, cliAnnotation, configValue, configAnnotation) {
41
+ if (cliValue !== void 0) return {
42
+ value: cliValue,
43
+ annotation: cliAnnotation
44
+ };
45
+ if (configValue) return {
46
+ value: configValue,
47
+ annotation: configAnnotation
48
+ };
49
+ }
50
+ function readConfigAppName(target, configAnnotation) {
51
+ if (target?.name) return {
52
+ value: target.name,
53
+ annotation: configAnnotation
54
+ };
55
+ if (target?.key) return {
56
+ value: target.key,
57
+ annotation: configAnnotation
58
+ };
59
+ }
62
60
  /**
63
61
  * Merges CLI inputs for the local `app build` and `app run` commands with a
64
62
  * selected config target. Explicit flags win; `--build-type auto` is the
@@ -30,6 +30,7 @@ function perAppInputsForDeployAll(inputs) {
30
30
  ["--framework", inputs.framework],
31
31
  ["--entry", inputs.entrypoint],
32
32
  ["--http-port", inputs.httpPort],
33
+ ["--region", inputs.region],
33
34
  ["--env", inputs.envAssignments?.length ? inputs.envAssignments : void 0],
34
35
  [inputs.appIdEnvVar.name, inputs.appIdEnvVar.value]
35
36
  ].filter(([, value]) => value !== void 0).map(([flag]) => flag);
@@ -6,7 +6,7 @@ function createDeployProgressState() {
6
6
  buildCompleted: false,
7
7
  archiveReady: false,
8
8
  uploadCompleted: false,
9
- versionId: null,
9
+ deploymentId: null,
10
10
  startRequested: false,
11
11
  containerLive: false,
12
12
  deploymentUrl: null,
@@ -39,8 +39,8 @@ function createDeployProgress(output, ui, enabled, state = createDeployProgressS
39
39
  onUploadStart() {
40
40
  write("Uploading...");
41
41
  },
42
- onVersionCreated(versionId) {
43
- state.versionId = versionId;
42
+ onDeploymentCreated(deploymentId) {
43
+ state.deploymentId = deploymentId;
44
44
  },
45
45
  onUploadComplete() {
46
46
  state.uploadCompleted = true;
@@ -69,16 +69,16 @@ function createPromoteProgress(output, enabled) {
69
69
  output.write(`${line}\n`);
70
70
  };
71
71
  return {
72
- onVersionStarting(versionId) {
73
- write(`Starting deployment ${versionId}...`);
72
+ onDeploymentStarting(deploymentId) {
73
+ write(`Starting deployment ${deploymentId}...`);
74
74
  },
75
- onVersionStartRequested() {
75
+ onDeploymentStartRequested() {
76
76
  write("Requesting deployment start...");
77
77
  },
78
78
  onStatusChange(status) {
79
79
  write(`Status: ${status}`);
80
80
  },
81
- onVersionRunning() {
81
+ onDeploymentRunning() {
82
82
  write("Deployment is running.");
83
83
  },
84
84
  onPromoteStart() {
@@ -350,6 +350,7 @@ const DESCRIPTORS = [
350
350
  "prisma-cli app deploy --db",
351
351
  "prisma-cli app deploy --db --yes",
352
352
  "prisma-cli app deploy --app my-app --framework nextjs --http-port 3000",
353
+ "prisma-cli app deploy --app my-app --region us-west-1",
353
354
  "prisma-cli app deploy --branch feat-login --framework hono",
354
355
  "prisma-cli app deploy --prod --yes",
355
356
  "prisma-cli app deploy --framework bun --entry src/server.ts"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/cli",
3
- "version": "3.0.0-dev.101.1",
3
+ "version": "3.0.0-dev.104.1",
4
4
  "description": "Command-line interface for the Prisma Developer Platform.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -44,9 +44,9 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@clack/prompts": "^1.5.0",
47
- "@prisma/compute-sdk": "^0.29.0",
47
+ "@prisma/compute-sdk": "0.31.0",
48
48
  "@prisma/credentials-store": "^7.8.0",
49
- "@prisma/management-api-sdk": "^1.37.0",
49
+ "@prisma/management-api-sdk": "^1.44.0",
50
50
  "better-result": "^2.9.2",
51
51
  "colorette": "^2.0.20",
52
52
  "commander": "^14.0.3",