@prisma/cli 3.0.0-beta.8 → 3.0.0-dev.101.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.
Files changed (56) hide show
  1. package/README.md +0 -13
  2. package/dist/adapters/mock-api.js +75 -0
  3. package/dist/adapters/token-storage.js +311 -33
  4. package/dist/cli.js +7 -7
  5. package/dist/cli2.js +5 -3
  6. package/dist/commands/app/index.js +65 -52
  7. package/dist/commands/auth/index.js +55 -2
  8. package/dist/commands/database/index.js +159 -0
  9. package/dist/controllers/app-env.js +10 -7
  10. package/dist/controllers/app.js +550 -208
  11. package/dist/controllers/auth.js +211 -2
  12. package/dist/controllers/branch.js +5 -6
  13. package/dist/controllers/database.js +318 -0
  14. package/dist/controllers/project.js +49 -20
  15. package/dist/lib/app/app-interaction.js +5 -0
  16. package/dist/lib/app/{preview-provider.js → app-provider.js} +32 -28
  17. package/dist/lib/app/{preview-branch-database.js → branch-database-api.js} +1 -1
  18. package/dist/lib/app/branch-database-deploy.js +13 -60
  19. package/dist/lib/app/branch-database.js +1 -102
  20. package/dist/lib/app/build-settings.js +93 -0
  21. package/dist/lib/app/build.js +82 -0
  22. package/dist/lib/app/bun-project.js +2 -3
  23. package/dist/lib/app/compute-config.js +147 -0
  24. package/dist/lib/app/deploy-plan.js +58 -0
  25. package/dist/lib/app/{preview-progress.js → deploy-progress.js} +5 -5
  26. package/dist/lib/app/local-dev.js +3 -60
  27. package/dist/lib/app/production-deploy-gate.js +3 -3
  28. package/dist/lib/app/read-branch.js +30 -0
  29. package/dist/lib/auth/auth-ops.js +10 -4
  30. package/dist/lib/auth/guard.js +4 -1
  31. package/dist/lib/auth/login.js +32 -25
  32. package/dist/lib/database/provider.js +167 -0
  33. package/dist/lib/diagnostics.js +1 -1
  34. package/dist/lib/fs/home-path.js +24 -0
  35. package/dist/lib/git/local-branch.js +15 -3
  36. package/dist/lib/project/local-pin.js +170 -40
  37. package/dist/lib/project/resolution.js +166 -61
  38. package/dist/lib/project/setup.js +65 -19
  39. package/dist/output/patterns.js +1 -1
  40. package/dist/presenters/app.js +44 -39
  41. package/dist/presenters/auth.js +98 -1
  42. package/dist/presenters/branch.js +1 -1
  43. package/dist/presenters/database.js +274 -0
  44. package/dist/presenters/project.js +3 -9
  45. package/dist/shell/command-meta.js +153 -2
  46. package/dist/shell/command-runner.js +39 -21
  47. package/dist/shell/diagnostics-output.js +2 -8
  48. package/dist/shell/errors.js +50 -1
  49. package/dist/shell/help.js +30 -20
  50. package/dist/shell/runtime.js +8 -4
  51. package/dist/shell/ui.js +19 -2
  52. package/dist/use-cases/auth.js +68 -1
  53. package/package.json +18 -3
  54. package/dist/lib/app/preview-build-settings.js +0 -385
  55. package/dist/lib/app/preview-build.js +0 -475
  56. package/dist/lib/app/preview-interaction.js +0 -5
@@ -1,58 +1,79 @@
1
1
  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
- import { renderCommandHeader } from "../shell/ui.js";
5
- import { writeJsonEvent } from "../shell/output.js";
6
- import { canPrompt } from "../shell/runtime.js";
7
4
  import { confirmPrompt, selectPrompt, textPrompt } from "../shell/prompt.js";
8
- import { requireComputeAuth } from "../lib/auth/guard.js";
9
- import { readAuthState } from "../lib/auth/auth-ops.js";
5
+ import { DEFAULT_REGION } from "../lib/app/app-interaction.js";
6
+ import { PRISMA_APP_CONFIG_FILENAME, detectLegacyBuildSettings, resolveConfiguredAppBuildSettings, resolveInferredAppBuildSettings } from "../lib/app/build-settings.js";
7
+ import { APP_BUILD_TYPES, APP_BUILD_TYPE_LABELS, RESOLVED_APP_BUILD_TYPES, executeAppBuild } from "../lib/app/build.js";
10
8
  import { envVarNames, parseEnvInputs } from "../lib/app/env-vars.js";
11
- import { renderDeployOutputRows, renderDeploySettingsPreview } from "../lib/app/deploy-output.js";
12
- import { readBunPackageEntrypoint, readBunPackageJson } from "../lib/app/bun-project.js";
13
- import { DEFAULT_LOCAL_DEV_PORT, resolveLocalBuildType, runLocalApp } from "../lib/app/local-dev.js";
14
- import { formatCommandArgument } from "../shell/command-arguments.js";
9
+ import { DomainApiError, createAppProvider } from "../lib/app/app-provider.js";
10
+ import { renderCommandHeader } from "../shell/ui.js";
11
+ import { canPrompt } from "../shell/runtime.js";
15
12
  import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, readLocalResolutionPin } from "../lib/project/local-pin.js";
16
- import { buildProjectSetupNextActions, inferTargetName, projectNotFoundError, resolveDurablePlatformMapping, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
17
- import { bindProjectToDirectory, projectCreateFailedError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
18
- import { promptForProjectSetupChoice } from "../lib/project/interactive-setup.js";
19
- import { readLocalGitBranch } from "../lib/git/local-branch.js";
20
- import { resolveOrCreatePreviewBuildSettings } from "../lib/app/preview-build-settings.js";
21
- import { PREVIEW_BUILD_TYPES, RESOLVED_PREVIEW_BUILD_TYPES, executePreviewBuild } from "../lib/app/preview-build.js";
22
- import { PREVIEW_DEFAULT_REGION } from "../lib/app/preview-interaction.js";
13
+ import { formatCommandArgument } from "../shell/command-arguments.js";
14
+ import { buildProjectSetupNextActions, inferTargetName, localProjectWorkspaceMismatchError, projectNotFoundError, projectResolutionErrorToCliError, resolveDurablePlatformMapping, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
15
+ import { bindProjectToDirectory, projectCreateFailedError, projectDirectoryBindingErrorToCliError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
23
16
  import { maybeSetupBranchDatabase } from "../lib/app/branch-database-deploy.js";
24
- import { createPreviewDeployProgress, createPreviewDeployProgressState, createPreviewPromoteProgress } from "../lib/app/preview-progress.js";
25
- import { PreviewDomainApiError, createPreviewAppProvider } from "../lib/app/preview-provider.js";
26
- import { enforceProductionDeployGate } from "../lib/app/production-deploy-gate.js";
17
+ import { readBunPackageEntrypoint, readBunPackageJson } from "../lib/app/bun-project.js";
18
+ import { COMPUTE_CONFIG_FILENAME as COMPUTE_CONFIG_FILENAME$1, ComputeConfigTargetRequiredError, computeConfigErrorToCliError, computeFrameworkToBuildType, computeTargetAppDir, inferComputeTargetFromCwd, loadComputeConfig as loadComputeConfig$1, mergeComputeDeployInputs, mergeComputeLocalInputs, selectComputeDeployTarget } from "../lib/app/compute-config.js";
19
+ import { renderDeployOutputRows, renderDeploySettingsPreview } from "../lib/app/deploy-output.js";
20
+ import { describeDeployAllFailure, perAppInputsForDeployAll, planAppDeploy } from "../lib/app/deploy-plan.js";
21
+ import { createDeployProgress, createDeployProgressState, createPromoteProgress } from "../lib/app/deploy-progress.js";
27
22
  import { formatDomainFailureFix } from "../lib/app/domain-guidance.js";
23
+ import { DEFAULT_LOCAL_DEV_PORT, runLocalApp } from "../lib/app/local-dev.js";
24
+ import { enforceProductionDeployGate } from "../lib/app/production-deploy-gate.js";
25
+ import { resolveReadBranch } from "../lib/app/read-branch.js";
26
+ import { requireComputeAuth } from "../lib/auth/guard.js";
27
+ import { readAuthState } from "../lib/auth/auth-ops.js";
28
+ import { readLocalGitBranch } from "../lib/git/local-branch.js";
29
+ import { promptForProjectSetupChoice } from "../lib/project/interactive-setup.js";
30
+ import { writeJsonEvent } from "../shell/output.js";
28
31
  import { createSelectPromptPort } from "./select-prompt-port.js";
29
32
  import { requireAuthenticatedAuthState } from "./auth.js";
30
33
  import { listRealWorkspaceProjects } from "./project.js";
34
+ import { ENTRYPOINT_BUILD_TYPES, FRAMEWORKS, LOCAL_DEV_BUILD_TYPES, frameworkByKey, frameworkFromAlias, isConfigBackedBuildType } from "@prisma/compute-sdk/config";
31
35
  import { access, readFile } from "node:fs/promises";
32
36
  import path from "node:path";
37
+ import { Result, matchError } from "better-result";
33
38
  import open from "open";
34
39
  //#region src/controllers/app.ts
35
- const DEPLOY_FRAMEWORKS = [
36
- "nextjs",
37
- "hono",
38
- "tanstack-start",
39
- "bun"
40
- ];
41
- const TANSTACK_START_PACKAGES = ["@tanstack/react-start", "@tanstack/solid-start"];
42
40
  const FRAMEWORK_DEFAULT_HTTP_PORT = 3e3;
43
41
  const PRISMA_PROJECT_ID_ENV_VAR = "PRISMA_PROJECT_ID";
44
42
  const PRISMA_APP_ID_ENV_VAR = "PRISMA_APP_ID";
45
43
  function isRealMode(context) {
46
44
  return !context.runtime.fixturePath && !context.runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
47
45
  }
48
- async function runAppBuild(context, entrypoint, requestedBuildType) {
49
- const buildType = normalizeBuildType(requestedBuildType);
50
- assertSupportedEntrypoint(buildType, entrypoint, "build");
46
+ async function runAppBuild(context, options) {
47
+ const compute = await resolveComputeTargetOrThrow(context, options?.configTarget, "build");
48
+ const merged = mergeComputeLocalInputs({
49
+ cli: {
50
+ entrypoint: options?.entrypoint,
51
+ buildType: options?.buildType
52
+ },
53
+ target: compute.target
54
+ });
55
+ const appDir = await resolveComputeAppDir(context, compute);
56
+ let buildType = normalizeBuildType(merged.buildType);
57
+ if (compute.target?.build && buildType === "auto") {
58
+ const detected = await detectDeployFramework(appDir, context.runtime.signal);
59
+ if (!detected) throw frameworkNotDetectedError(appDir);
60
+ buildType = detected.buildType;
61
+ }
62
+ assertSupportedEntrypoint(buildType, merged.entrypoint, "build");
63
+ if (compute.target?.build && buildType !== "auto") assertConfigBackedBuildSettings(buildType);
64
+ const buildSettings = compute.config && compute.target?.build && isConfigBackedBuildType(buildType) ? (await resolveConfiguredAppBuildSettings({
65
+ appPath: appDir,
66
+ buildType,
67
+ configured: compute.target.build,
68
+ configPath: compute.config.configPath,
69
+ signal: context.runtime.signal
70
+ })).settings : void 0;
51
71
  try {
52
- const { artifact, buildType: actualBuildType } = await executePreviewBuild({
53
- appPath: context.runtime.cwd,
54
- entrypoint,
72
+ const { artifact, buildType: actualBuildType } = await executeAppBuild({
73
+ appPath: appDir,
74
+ entrypoint: merged.entrypoint,
55
75
  buildType,
76
+ buildSettings,
56
77
  signal: context.runtime.signal
57
78
  });
58
79
  return {
@@ -66,21 +87,37 @@ async function runAppBuild(context, entrypoint, requestedBuildType) {
66
87
  nextSteps: ["prisma-cli app deploy"]
67
88
  };
68
89
  } catch (error) {
69
- if (buildType === "auto" && isAutoBuildDetectionError(error)) throw usageError("App build requires an explicit framework when detection is ambiguous", `This preview auto-detects clear project shapes for ${RESOLVED_PREVIEW_BUILD_TYPES.map(formatBuildTypeName).join(", ")}.`, "Pass a supported --build-type value, or pass --entry <path> for a Bun app.", getBuildTypeExamples("build"), "app");
90
+ if (buildType === "auto" && isAutoBuildDetectionError(error)) throw usageError("App build requires an explicit framework when detection is ambiguous", `This preview auto-detects clear project shapes for ${RESOLVED_APP_BUILD_TYPES.map(formatBuildTypeName).join(", ")}.`, "Pass a supported --build-type value, or pass --entry <path> for a Bun app.", getBuildTypeExamples("build"), "app");
70
91
  throw buildFailedError("Local app build failed", error);
71
92
  }
72
93
  }
73
- async function runAppRun(context, entrypoint, requestedBuildType, requestedPort) {
94
+ async function runAppRun(context, options) {
74
95
  if (context.flags.json) throw usageError("App run does not support --json", "This command streams the framework dev server directly and cannot return structured JSON.", "Rerun without --json to pass framework logs through directly.", ["prisma-cli app run"], "app");
75
- const buildType = normalizeBuildType(requestedBuildType);
76
- assertSupportedEntrypoint(buildType, entrypoint, "run");
77
- const port = parseLocalPort(requestedPort);
78
- const resolvedBuildType = await requireLocalBuildType(context, buildType, "run");
96
+ const compute = await resolveComputeTargetOrThrow(context, options?.configTarget, "run");
97
+ const merged = mergeComputeLocalInputs({
98
+ cli: {
99
+ entrypoint: options?.entrypoint,
100
+ buildType: options?.buildType,
101
+ port: options?.port
102
+ },
103
+ target: compute.target
104
+ });
105
+ if (merged.buildTypeFromConfig && compute.target?.framework && !frameworkByKey(compute.target.framework).hasLocalDevServer) throw usageError(`App run does not support the ${compute.target?.framework} framework yet`, `${compute.config?.relativeConfigPath ?? COMPUTE_CONFIG_FILENAME$1} sets a framework that has no local dev server in the current preview.`, "Run the framework dev server directly, or pass --build-type nextjs or --build-type bun to override.", ["prisma-cli app run --build-type nextjs", "prisma-cli app run --build-type bun --entry server.ts"], "app");
106
+ const appDir = await resolveComputeAppDir(context, compute);
107
+ const buildType = normalizeBuildType(merged.buildType);
108
+ assertSupportedEntrypoint(buildType, merged.entrypoint, "run");
109
+ const port = parseLocalPort(merged.port);
110
+ const framework = await resolveLocalRunFramework(context, {
111
+ requestedBuildType: buildType,
112
+ configFramework: compute.target?.framework ?? null,
113
+ appDir
114
+ });
115
+ const entrypoint = framework.buildType === "bun" ? await resolveDeployEntrypoint(appDir, framework, merged.entrypoint, context.runtime.signal) : merged.entrypoint;
79
116
  let runResult;
80
117
  try {
81
118
  runResult = await runLocalApp({
82
- appPath: context.runtime.cwd,
83
- buildType: resolvedBuildType,
119
+ appPath: appDir,
120
+ buildType: framework.buildType,
84
121
  entrypoint,
85
122
  port,
86
123
  env: context.runtime.env,
@@ -105,6 +142,106 @@ async function runAppRun(context, entrypoint, requestedBuildType, requestedPort)
105
142
  }
106
143
  async function runAppDeploy(context, appName, options) {
107
144
  ensurePreviewAppMode(context);
145
+ const loaded = await loadComputeConfig$1(context.runtime.cwd, context.runtime.signal);
146
+ if (loaded.isErr()) throw computeConfigErrorToCliError(loaded.error, "deploy");
147
+ const config = loaded.value;
148
+ const plan = planAppDeploy({
149
+ config,
150
+ requestedTarget: options?.configTarget ?? (config ? inferComputeTargetFromCwd(config, context.runtime.cwd) : void 0),
151
+ hasCreateProject: options?.createProjectName !== void 0
152
+ });
153
+ if (plan.mode === "all") return runAppDeployAll(context, config, plan.targets, appName, options);
154
+ return runSingleAppDeploy(context, appName, options, config);
155
+ }
156
+ async function runAppDeployAll(context, config, plannedTargets, appName, options) {
157
+ assertNoPerAppInputsForDeployAll(context, config, appName, options);
158
+ const deployments = [];
159
+ const warnings = [];
160
+ for (const planned of plannedTargets) {
161
+ maybeRenderDeployAllTargetHeader(context, planned);
162
+ const targetOptions = {
163
+ ...options,
164
+ configTarget: planned.targetKey,
165
+ createProjectName: planned.bindsCreateProject ? options?.createProjectName : void 0
166
+ };
167
+ try {
168
+ const single = await runSingleAppDeploy(context, void 0, targetOptions, config);
169
+ deployments.push({
170
+ target: planned.targetKey,
171
+ result: single.result
172
+ });
173
+ warnings.push(...single.warnings);
174
+ } catch (error) {
175
+ throw deployAllFailedError(error, config, planned.index, deployments);
176
+ }
177
+ }
178
+ return {
179
+ command: "app.deploy",
180
+ result: { deployments },
181
+ warnings,
182
+ nextSteps: ["prisma-cli app list-deploys <app>"]
183
+ };
184
+ }
185
+ function assertNoPerAppInputsForDeployAll(context, config, appName, options) {
186
+ const used = perAppInputsForDeployAll({
187
+ appName,
188
+ framework: options?.framework,
189
+ entrypoint: options?.entrypoint,
190
+ httpPort: options?.httpPort,
191
+ envAssignments: options?.envAssignments,
192
+ appIdEnvVar: {
193
+ name: PRISMA_APP_ID_ENV_VAR,
194
+ value: readDeployEnvOverride(context, PRISMA_APP_ID_ENV_VAR)
195
+ }
196
+ });
197
+ 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
+ }
201
+ function maybeRenderDeployAllTargetHeader(context, planned) {
202
+ if (context.flags.json || context.flags.quiet) return;
203
+ context.output.stderr.write(`${planned.index > 0 ? "\n" : ""}── ${planned.targetKey} (${planned.index + 1}/${planned.total}) ──\n\n`);
204
+ }
205
+ function deployAllFailedError(error, config, failedIndex, deployments) {
206
+ if (!(error instanceof CliError)) return error;
207
+ const failure = describeDeployAllFailure({
208
+ targetKeys: config.targets.map((target) => target.key),
209
+ failedIndex,
210
+ completed: deployments.map(({ target, result }) => ({
211
+ target,
212
+ deploymentId: result.deployment.id,
213
+ url: result.deployment.url
214
+ }))
215
+ });
216
+ const contextSentence = failure.contextLines.join(" ");
217
+ return new CliError({
218
+ code: error.code,
219
+ domain: error.domain,
220
+ summary: error.summary,
221
+ why: error.humanLines ? error.why : [error.why, contextSentence].filter(Boolean).join(" "),
222
+ fix: error.fix,
223
+ debug: error.debug,
224
+ where: error.where,
225
+ meta: {
226
+ ...error.meta,
227
+ deployAll: {
228
+ failedTarget: failure.failedTarget,
229
+ completed: failure.completed,
230
+ notAttempted: failure.notAttempted
231
+ }
232
+ },
233
+ docsUrl: error.docsUrl,
234
+ exitCode: error.exitCode,
235
+ nextSteps: error.nextSteps,
236
+ nextActions: error.nextActions,
237
+ humanLines: error.humanLines ? [
238
+ ...error.humanLines,
239
+ "",
240
+ ...failure.contextLines
241
+ ] : void 0
242
+ });
243
+ }
244
+ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
108
245
  const envProjectId = readDeployEnvOverride(context, PRISMA_PROJECT_ID_ENV_VAR);
109
246
  const envAppId = readDeployEnvOverride(context, PRISMA_APP_ID_ENV_VAR);
110
247
  assertExclusiveDeployProjectInputs({
@@ -112,14 +249,27 @@ async function runAppDeploy(context, appName, options) {
112
249
  createProjectName: options?.createProjectName,
113
250
  envProjectId
114
251
  });
115
- const skipLocalPin = Boolean(envProjectId || options?.projectRef || options?.createProjectName);
116
- const localPin = skipLocalPin ? { kind: "missing" } : await readLocalResolutionPin(context.runtime.cwd, context.runtime.signal);
117
- if (!skipLocalPin && localPin.kind === "invalid") throw localResolutionPinStaleError();
252
+ const computeConfig = await resolveComputeTargetOrThrow(context, options?.configTarget, "deploy", { preloaded: preloadedConfig });
253
+ const merged = mergeComputeDeployInputs({
254
+ cli: {
255
+ framework: options?.framework,
256
+ entrypoint: options?.entrypoint,
257
+ httpPort: options?.httpPort,
258
+ envInputs: options?.envAssignments
259
+ },
260
+ target: computeConfig.target,
261
+ configFilename: computeConfig.config?.relativeConfigPath ?? COMPUTE_CONFIG_FILENAME$1
262
+ });
263
+ const appDir = await resolveComputeAppDir(context, computeConfig);
264
+ const projectDir = computeConfig.config?.configDir ?? context.runtime.cwd;
265
+ const localPinReadResult = Boolean(envProjectId || options?.projectRef || options?.createProjectName) ? Result.ok({ kind: "missing" }) : await readLocalResolutionPin(projectDir, context.runtime.signal);
266
+ if (localPinReadResult.isErr()) throw localPinReadErrorToDeployError(localPinReadResult.error);
267
+ const localPin = localPinReadResult.value;
118
268
  const branch = await resolveDeployBranch(context, options?.branchName);
119
- if (options?.httpPort) parseDeployHttpPort(options.httpPort);
269
+ if (merged.httpPort) parseDeployHttpPort(merged.httpPort.value);
120
270
  assertSupportedEntrypointForRequestedDeployShape({
121
- requestedFramework: options?.framework,
122
- entrypoint: options?.entrypoint
271
+ requestedFramework: merged.framework?.value,
272
+ entrypoint: merged.entrypoint?.value
123
273
  });
124
274
  const { provider, target, projectId } = await requireProviderAndDeployProjectContext(context, options?.projectRef, {
125
275
  branch,
@@ -129,25 +279,32 @@ async function runAppDeploy(context, appName, options) {
129
279
  });
130
280
  let localPinResult;
131
281
  if (target.localPinAction) {
132
- const setupResult = await bindProjectToDirectory(context, target.workspace, target.project, target.localPinAction);
133
- localPinResult = setupResult.localPin;
134
- maybeRenderProjectLinked(context, setupResult.directory, setupResult.project.name, setupResult.localPin.path);
282
+ const setupResult = await bindProjectToDirectory(context, target.workspace, target.project, target.localPinAction, projectDir);
283
+ if (setupResult.isErr()) throw projectDirectoryBindingErrorToCliError(setupResult.error);
284
+ const projectSetup = setupResult.value;
285
+ localPinResult = projectSetup.localPin;
286
+ maybeRenderProjectLinked(context, projectSetup.directory, projectSetup.project.name, projectSetup.localPin.path);
135
287
  }
136
288
  let framework = await resolveDeployFramework(context, {
137
- requestedFramework: options?.framework,
138
- entrypoint: options?.entrypoint
139
- });
140
- let runtime = resolveDeployRuntime(options?.httpPort, framework);
141
- assertSupportedEntrypoint(framework.buildType, options?.entrypoint, "deploy");
142
- const envVars = toOptionalEnvVars(await parseEnvInputs(context.runtime.cwd, options?.envAssignments, { commandName: "deploy" }));
289
+ requestedFramework: merged.framework?.value,
290
+ requestedFrameworkAnnotation: merged.framework?.annotation,
291
+ entrypoint: merged.entrypoint?.value,
292
+ entrypointAnnotation: merged.entrypoint?.annotation,
293
+ appDir
294
+ });
295
+ let runtime = resolveDeployRuntime(merged.httpPort?.value, merged.httpPort?.annotation, framework);
296
+ assertSupportedEntrypoint(framework.buildType, merged.entrypoint?.value, "deploy");
297
+ const envVars = toOptionalEnvVars(await parseEnvInputs(merged.envInputsFromConfig ? projectDir : context.runtime.cwd, merged.envInputs, { commandName: "deploy" }));
143
298
  const selectedApp = await resolveDeployAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), {
144
299
  explicitAppName: appName,
145
300
  explicitAppId: envAppId,
301
+ configAppName: merged.configAppName,
146
302
  firstDeploy: Boolean(target.localPinAction),
147
- inferName: () => inferTargetName(context.runtime.cwd, context.runtime.signal)
303
+ inferName: () => inferTargetName(appDir, context.runtime.signal)
148
304
  });
149
305
  await maybeRenderDeploySetupBlock(context, {
150
306
  includeDirectory: !target.localPinAction,
307
+ appDir,
151
308
  projectName: target.project.name,
152
309
  branchName: target.branch.name,
153
310
  appName: selectedApp.displayName
@@ -156,9 +313,9 @@ async function runAppDeploy(context, appName, options) {
156
313
  framework,
157
314
  runtime,
158
315
  firstDeploy: selectedApp.firstDeploy,
159
- explicitFramework: Boolean(options?.framework),
160
- explicitEntrypoint: Boolean(options?.entrypoint),
161
- explicitHttpPort: Boolean(options?.httpPort)
316
+ explicitFramework: Boolean(merged.framework),
317
+ explicitEntrypoint: Boolean(merged.entrypoint),
318
+ explicitHttpPort: Boolean(merged.httpPort)
162
319
  });
163
320
  framework = customized.framework;
164
321
  runtime = customized.runtime;
@@ -169,24 +326,33 @@ async function runAppDeploy(context, appName, options) {
169
326
  prod: options?.prod === true
170
327
  });
171
328
  const buildType = framework.buildType;
172
- assertSupportedEntrypoint(buildType, options?.entrypoint, "deploy");
173
- const entrypoint = await resolveDeployEntrypoint(context.runtime.cwd, framework, options?.entrypoint, context.runtime.signal);
174
- const buildSettingsResolution = await resolveOrCreatePreviewBuildSettings({
175
- appPath: context.runtime.cwd,
329
+ assertSupportedEntrypoint(buildType, merged.entrypoint?.value, "deploy");
330
+ 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,
176
340
  buildType,
177
341
  signal: context.runtime.signal
178
342
  });
343
+ const legacyWarnings = await handleLegacyBuildSettings(context, appDir, buildSettingsResolution.settings);
179
344
  maybeRenderDeployBuildSettings(context, buildSettingsResolution);
180
345
  const portMapping = parseDeployPortMapping(String(runtime.port));
181
346
  const branchDatabaseSetup = await maybeSetupBranchDatabase(context, provider, projectId, toBranchDatabaseDeployBranch(target.branch), {
182
347
  db: options?.db,
183
348
  providedEnvVars: envVars,
184
- firstProductionDeploy: productionDeployGate.firstProductionDeploy
349
+ firstProductionDeploy: productionDeployGate.firstProductionDeploy,
350
+ projectDir
185
351
  });
186
- const progressState = createPreviewDeployProgressState();
352
+ const progressState = createDeployProgressState();
187
353
  const deployStartedAt = Date.now();
188
354
  const deployResult = await provider.deployApp({
189
- cwd: context.runtime.cwd,
355
+ cwd: appDir,
190
356
  projectId,
191
357
  branchName: target.branch.name,
192
358
  appId: selectedApp.appId,
@@ -199,7 +365,7 @@ async function runAppDeploy(context, appName, options) {
199
365
  envVars,
200
366
  interaction: void 0,
201
367
  signal: context.runtime.signal,
202
- progress: createPreviewDeployProgress(context.output.stderr, context.ui, !context.flags.json && !context.flags.quiet, progressState)
368
+ progress: createDeployProgress(context.output.stderr, context.ui, !context.flags.json && !context.flags.quiet, progressState)
203
369
  }).catch((error) => {
204
370
  throw appDeployFailedError(error, progressState);
205
371
  });
@@ -241,7 +407,7 @@ async function runAppDeploy(context, appName, options) {
241
407
  name: framework.displayName,
242
408
  source: framework.annotation
243
409
  },
244
- entrypoint: entrypoint ?? null,
410
+ entrypoint: entrypoint ?? buildSettingsResolution.settings.entrypoint ?? null,
245
411
  httpPort: runtime.port,
246
412
  region: selectedApp.region ?? null,
247
413
  envVars: envVarNames(envVars)
@@ -249,14 +415,18 @@ async function runAppDeploy(context, appName, options) {
249
415
  durationMs: deployDurationMs,
250
416
  localPin: localPinResult
251
417
  },
252
- warnings: branchDatabaseSetup.warnings,
418
+ warnings: [...legacyWarnings, ...branchDatabaseSetup.warnings],
253
419
  nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${deployResult.deployment.id}`]
254
420
  };
255
421
  }
256
- async function runAppListDeploys(context, appName, projectRef) {
422
+ async function runAppListDeploys(context, appName, projectRef, configTarget) {
257
423
  ensurePreviewAppMode(context);
258
- const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app list-deploys" });
259
- const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName);
424
+ const compute = await resolveComputeManagementContext(context, configTarget, "list-deploys");
425
+ const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, {
426
+ commandName: "app list-deploys",
427
+ projectDir: compute.projectDir
428
+ });
429
+ const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName ?? compute.configAppName);
260
430
  if (!selectedApp) return {
261
431
  command: "app.list-deploys",
262
432
  result: {
@@ -292,10 +462,14 @@ async function runAppListDeploys(context, appName, projectRef) {
292
462
  nextSteps: deployments.length > 0 ? [`prisma-cli app show-deploy ${deployments[0]?.id}`] : ["prisma-cli app deploy"]
293
463
  };
294
464
  }
295
- async function runAppShow(context, appName, projectRef) {
465
+ async function runAppShow(context, appName, projectRef, configTarget) {
296
466
  ensurePreviewAppMode(context);
297
- const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app show" });
298
- const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName);
467
+ const compute = await resolveComputeManagementContext(context, configTarget, "show");
468
+ const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, {
469
+ commandName: "app show",
470
+ projectDir: compute.projectDir
471
+ });
472
+ const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName ?? compute.configAppName);
299
473
  if (!selectedApp) return {
300
474
  command: "app.show",
301
475
  result: {
@@ -370,9 +544,14 @@ async function runAppShowDeploy(context, deploymentId) {
370
544
  nextSteps: []
371
545
  };
372
546
  }
373
- async function runAppOpen(context, appName, projectRef) {
547
+ async function runAppOpen(context, appName, projectRef, configTarget) {
374
548
  ensurePreviewAppMode(context);
375
- const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app open" });
549
+ const compute = await resolveComputeManagementContext(context, configTarget, "open");
550
+ appName = appName ?? compute.configAppName;
551
+ const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, {
552
+ commandName: "app open",
553
+ projectDir: compute.projectDir
554
+ });
376
555
  const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName);
377
556
  if (!selectedApp) throw noDeploymentsError("No deployments available to open", "The resolved project does not have any deployed app yet.");
378
557
  const deploymentsResult = await provider.listDeployments(selectedApp.id, { signal: context.runtime.signal }).catch((error) => {
@@ -536,15 +715,19 @@ async function runAppDomainWait(context, hostname, options) {
536
715
  });
537
716
  }
538
717
  }
539
- async function runAppLogs(context, appName, deploymentId, projectRef) {
718
+ async function runAppLogs(context, appName, deploymentId, projectRef, configTarget) {
540
719
  ensurePreviewAppMode(context);
541
- const { provider, target: resolvedTarget, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app logs" });
720
+ const compute = await resolveComputeManagementContext(context, configTarget, "logs");
721
+ appName = appName ?? compute.configAppName;
722
+ const { provider, target: resolvedTarget, projectId } = await requireProviderAndProjectContext(context, projectRef, {
723
+ commandName: "app logs",
724
+ projectDir: compute.projectDir
725
+ });
542
726
  const target = deploymentId ? await resolveExplicitLogDeployment(context, provider, projectId, resolvedTarget.branch.name, appName, deploymentId) : await resolveLiveLogDeployment(context, provider, projectId, resolvedTarget.branch.name, appName);
543
727
  if (!context.flags.json && !context.flags.quiet) {
544
728
  const lines = renderCommandHeader(context.ui, {
545
729
  commandLabel: "app logs",
546
730
  description: "Streaming logs for the selected deployment.",
547
- docsPath: "docs/product/command-spec.md#prisma-cli-app-logs---app-name---deployment-id",
548
731
  rows: [
549
732
  {
550
733
  key: "project",
@@ -661,9 +844,14 @@ function writeLogRecord(context, record) {
661
844
  if (!record.text.endsWith("\n")) context.output.stdout.write("\n");
662
845
  }
663
846
  }
664
- async function runAppPromote(context, deploymentId, appName, projectRef) {
847
+ async function runAppPromote(context, deploymentId, appName, projectRef, configTarget) {
665
848
  ensurePreviewAppMode(context);
666
- const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app promote" });
849
+ const compute = await resolveComputeManagementContext(context, configTarget, "promote");
850
+ appName = appName ?? compute.configAppName;
851
+ const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, {
852
+ commandName: "app promote",
853
+ projectDir: compute.projectDir
854
+ });
667
855
  const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName, "promote");
668
856
  const deploymentsResult = await provider.listDeployments(selectedApp.id, { signal: context.runtime.signal }).catch((error) => {
669
857
  throw deployFailedError("Failed to list app deployments", error, ["prisma-cli app list-deploys"]);
@@ -679,7 +867,7 @@ async function runAppPromote(context, deploymentId, appName, projectRef) {
679
867
  appId: selectedApp.id,
680
868
  deploymentId: targetDeployment.id,
681
869
  signal: context.runtime.signal,
682
- progress: createPreviewPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
870
+ progress: createPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
683
871
  }).catch((error) => {
684
872
  throw deployFailedError("Failed to promote deployment", error, ["prisma-cli app list-deploys"]);
685
873
  });
@@ -703,9 +891,14 @@ async function runAppPromote(context, deploymentId, appName, projectRef) {
703
891
  nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${targetDeployment.id}`]
704
892
  };
705
893
  }
706
- async function runAppRollback(context, appName, deploymentId, projectRef) {
894
+ async function runAppRollback(context, appName, deploymentId, projectRef, configTarget) {
707
895
  ensurePreviewAppMode(context);
708
- const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app rollback" });
896
+ const compute = await resolveComputeManagementContext(context, configTarget, "rollback");
897
+ appName = appName ?? compute.configAppName;
898
+ const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, {
899
+ commandName: "app rollback",
900
+ projectDir: compute.projectDir
901
+ });
709
902
  const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName, "rollback");
710
903
  const deploymentsResult = await provider.listDeployments(selectedApp.id, { signal: context.runtime.signal }).catch((error) => {
711
904
  throw deployFailedError("Failed to list app deployments", error, ["prisma-cli app list-deploys"]);
@@ -722,7 +915,7 @@ async function runAppRollback(context, appName, deploymentId, projectRef) {
722
915
  appId: selectedApp.id,
723
916
  deploymentId: targetDeployment.id,
724
917
  signal: context.runtime.signal,
725
- progress: createPreviewPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
918
+ progress: createPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
726
919
  }).catch((error) => {
727
920
  throw deployFailedError("Failed to roll back deployment", error, ["prisma-cli app list-deploys"]);
728
921
  });
@@ -747,9 +940,14 @@ async function runAppRollback(context, appName, deploymentId, projectRef) {
747
940
  nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${targetDeployment.id}`]
748
941
  };
749
942
  }
750
- async function runAppRemove(context, appName, projectRef) {
943
+ async function runAppRemove(context, appName, projectRef, configTarget) {
751
944
  ensurePreviewAppMode(context);
752
- const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app remove" });
945
+ const compute = await resolveComputeManagementContext(context, configTarget, "remove");
946
+ appName = appName ?? compute.configAppName;
947
+ const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, {
948
+ commandName: "app remove",
949
+ projectDir: compute.projectDir
950
+ });
753
951
  const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName, "remove");
754
952
  await confirmAppRemoval(context, selectedApp);
755
953
  const removedApp = await provider.removeApp(selectedApp.id, { signal: context.runtime.signal }).catch((error) => {
@@ -773,6 +971,7 @@ async function runAppRemove(context, appName, projectRef) {
773
971
  }
774
972
  async function resolveAppDomainTarget(context, options, commandName = "app domain") {
775
973
  ensurePreviewAppMode(context);
974
+ const compute = await resolveComputeManagementContext(context, options?.configTarget, commandName.replace(/^app /, ""));
776
975
  const branch = resolveDomainBranch(options?.branchName);
777
976
  if (toBranchKind(branch.name) !== "production") throw new CliError({
778
977
  code: "BRANCH_NOT_DEPLOYABLE",
@@ -788,10 +987,11 @@ async function resolveAppDomainTarget(context, options, commandName = "app domai
788
987
  const { provider, target, projectId } = await requireProviderAndProjectContext(context, options?.projectRef, {
789
988
  branch,
790
989
  commandName,
791
- envProjectId
990
+ envProjectId,
991
+ projectDir: compute.projectDir
792
992
  });
793
993
  const selectedApp = await resolveDomainAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), {
794
- explicitAppName: options?.appName,
994
+ explicitAppName: options?.appName ?? compute.configAppName,
795
995
  explicitAppId: envAppId
796
996
  });
797
997
  await context.stateStore.setSelectedApp(projectId, {
@@ -907,7 +1107,7 @@ async function confirmDomainRemoval(context, target, hostname) {
907
1107
  })) throw usageError("Custom domain removal canceled", "The command was canceled before the domain was detached.", "Rerun the command and confirm removal, or pass --yes.", [`prisma-cli app domain remove ${hostname} --app ${target.app.name} --yes`], "app");
908
1108
  }
909
1109
  function domainCommandError(command, error, hostname) {
910
- if (error instanceof PreviewDomainApiError) {
1110
+ if (error instanceof DomainApiError) {
911
1111
  if (command === "add" && (error.status === 400 || error.status === 422) && isDomainDnsError(error)) return domainDnsNotConfiguredError(hostname, error);
912
1112
  if (command === "add" && error.status === 400) return new CliError({
913
1113
  code: "DOMAIN_HOSTNAME_INVALID",
@@ -1088,7 +1288,7 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
1088
1288
  };
1089
1289
  return {
1090
1290
  appName: options.explicitAppName,
1091
- region: PREVIEW_DEFAULT_REGION,
1291
+ region: DEFAULT_REGION,
1092
1292
  displayName: options.explicitAppName,
1093
1293
  annotation: "set by --app",
1094
1294
  firstDeploy: options.firstDeploy
@@ -1104,6 +1304,25 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
1104
1304
  firstDeploy: options.firstDeploy
1105
1305
  };
1106
1306
  }
1307
+ if (options.configAppName) {
1308
+ 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
+ firstDeploy: options.firstDeploy
1317
+ };
1318
+ return {
1319
+ appName: configName.value,
1320
+ region: DEFAULT_REGION,
1321
+ displayName: configName.value,
1322
+ annotation: configName.annotation,
1323
+ firstDeploy: options.firstDeploy
1324
+ };
1325
+ }
1107
1326
  const inferredName = await options.inferName();
1108
1327
  const matches = findAppsByName(apps, inferredName.name);
1109
1328
  if (matches.length > 1) return resolveAmbiguousDeployApp(context, matches, inferredName.name, options.firstDeploy);
@@ -1116,7 +1335,7 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
1116
1335
  };
1117
1336
  return {
1118
1337
  appName: inferredName.name,
1119
- region: PREVIEW_DEFAULT_REGION,
1338
+ region: DEFAULT_REGION,
1120
1339
  displayName: inferredName.name,
1121
1340
  annotation: inferredName.source === "package-name" ? "created from package.json" : "created from directory name",
1122
1341
  firstDeploy: options.firstDeploy
@@ -1148,7 +1367,7 @@ async function resolveAmbiguousDeployApp(context, matches, targetName, firstDepl
1148
1367
  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");
1149
1368
  if (selected === createNew) return {
1150
1369
  appName: targetName,
1151
- region: PREVIEW_DEFAULT_REGION,
1370
+ region: DEFAULT_REGION,
1152
1371
  displayName: targetName,
1153
1372
  annotation: "created from package.json",
1154
1373
  firstDeploy
@@ -1313,7 +1532,7 @@ async function requirePreviewAppProviderWithClient(context) {
1313
1532
  if (!client) throw authRequiredError(["prisma-cli auth login"]);
1314
1533
  return {
1315
1534
  client,
1316
- provider: createPreviewAppProvider(client, createPreviewLogAuthOptions(context.runtime.env, context.runtime.signal))
1535
+ provider: createAppProvider(client, createPreviewLogAuthOptions(context.runtime.env, context.runtime.signal))
1317
1536
  };
1318
1537
  }
1319
1538
  function createPreviewLogAuthOptions(env, signal) {
@@ -1355,21 +1574,29 @@ async function requireProviderAndDeployProjectContext(context, explicitProject,
1355
1574
  async function resolveProjectContext(context, client, explicitProject, options) {
1356
1575
  const authState = await requireAuthenticatedAuthState(context);
1357
1576
  if (!authState.workspace) throw workspaceRequiredError();
1358
- const resolved = await resolveProjectTarget({
1577
+ const resolvedResult = await resolveProjectTarget({
1359
1578
  context,
1360
1579
  workspace: authState.workspace,
1361
1580
  explicitProject,
1362
1581
  envProjectId: options?.envProjectId,
1582
+ projectDir: options?.projectDir,
1363
1583
  listProjects: () => listRealWorkspaceProjects(client, authState.workspace, context.runtime.signal),
1364
1584
  commandName: options?.commandName
1365
1585
  });
1366
- const branch = options?.branch ?? await resolveDeployBranch(context, void 0);
1586
+ if (resolvedResult.isErr()) throw projectResolutionErrorToCliError(resolvedResult.error);
1587
+ const resolved = resolvedResult.value;
1588
+ const requested = options?.branch ?? await resolveDeployBranch(context, void 0);
1589
+ const remoteBranch = options?.branch ? null : await resolveReadBranch(client, {
1590
+ projectId: resolved.project.id,
1591
+ branchName: requested.name,
1592
+ signal: context.runtime.signal
1593
+ });
1367
1594
  return {
1368
1595
  ...resolved,
1369
- branch: {
1596
+ branch: remoteBranch ?? {
1370
1597
  id: null,
1371
- name: branch.name,
1372
- kind: toBranchKind(branch.name)
1598
+ name: requested.name,
1599
+ kind: toBranchKind(requested.name)
1373
1600
  }
1374
1601
  };
1375
1602
  }
@@ -1417,7 +1644,11 @@ async function resolveDeployProjectContext(context, client, provider, explicitPr
1417
1644
  }
1418
1645
  const localPin = options.localPin;
1419
1646
  if (localPin.kind === "present") {
1420
- if (localPin.pin.workspaceId !== workspace.id) throw localResolutionPinStaleError();
1647
+ if (localPin.pin.workspaceId !== workspace.id) throw localProjectWorkspaceMismatchError({
1648
+ pinnedWorkspaceId: localPin.pin.workspaceId,
1649
+ pinnedProjectId: localPin.pin.projectId,
1650
+ activeWorkspace: workspace
1651
+ });
1421
1652
  const project = projects.find((candidate) => candidate.id === localPin.pin.projectId);
1422
1653
  if (!project) throw localResolutionPinStaleError();
1423
1654
  return withRemoteDeployBranch(provider, {
@@ -1554,22 +1785,130 @@ async function resolveDeployBranch(context, explicitBranchName) {
1554
1785
  annotation: "default"
1555
1786
  };
1556
1787
  }
1788
+ async function resolveComputeTargetOrThrow(context, configTarget, commandName, options) {
1789
+ let config;
1790
+ if (options?.preloaded !== void 0) config = options.preloaded;
1791
+ else {
1792
+ const loaded = await loadComputeConfig$1(context.runtime.cwd, context.runtime.signal);
1793
+ if (loaded.isErr()) throw computeConfigErrorToCliError(loaded.error, commandName);
1794
+ config = loaded.value;
1795
+ }
1796
+ if (!config) {
1797
+ if (configTarget) throw usageError(`App target "${configTarget}" requires a compute config file`, `No ${COMPUTE_CONFIG_FILENAME$1} exists in the current directory, so there are no named app targets.`, `Create ${COMPUTE_CONFIG_FILENAME$1} with an apps entry named "${configTarget}", or rerun without the target argument.`, [`prisma-cli app ${commandName}`], "app");
1798
+ return {
1799
+ config: null,
1800
+ target: null
1801
+ };
1802
+ }
1803
+ const requestedTarget = configTarget ?? inferComputeTargetFromCwd(config, context.runtime.cwd);
1804
+ const selected = selectComputeDeployTarget(config, requestedTarget);
1805
+ if (selected.isErr()) {
1806
+ if (options?.targetOptional && selected.error instanceof ComputeConfigTargetRequiredError) return {
1807
+ config,
1808
+ target: null
1809
+ };
1810
+ throw computeConfigErrorToCliError(selected.error, commandName);
1811
+ }
1812
+ return {
1813
+ config,
1814
+ target: selected.value
1815
+ };
1816
+ }
1817
+ /**
1818
+ * Compute-config context for app management commands: the project directory
1819
+ * (where `.prisma/local.json` lives) and the config-selected app name, which
1820
+ * ranks below `--app` but above the remembered app selection.
1821
+ */
1822
+ async function resolveComputeManagementContext(context, configTarget, commandName) {
1823
+ const compute = await resolveComputeTargetOrThrow(context, configTarget, commandName, { targetOptional: true });
1824
+ return {
1825
+ projectDir: compute.config?.configDir ?? context.runtime.cwd,
1826
+ configAppName: compute.target?.name ?? compute.target?.key ?? void 0
1827
+ };
1828
+ }
1829
+ async function resolveComputeAppDir(context, compute) {
1830
+ if (!compute.config || !compute.target) return context.runtime.cwd;
1831
+ const appDir = computeTargetAppDir(compute.config, compute.target);
1832
+ if (!compute.target.root) return appDir;
1833
+ context.runtime.signal.throwIfAborted();
1834
+ try {
1835
+ await access(appDir);
1836
+ context.runtime.signal.throwIfAborted();
1837
+ } catch (error) {
1838
+ if (context.runtime.signal.aborted) throw error;
1839
+ throw new CliError({
1840
+ code: "COMPUTE_CONFIG_INVALID",
1841
+ domain: "app",
1842
+ summary: `App root "${compute.target.root}" does not exist`,
1843
+ why: `${compute.config.relativeConfigPath} points the selected app at "${compute.target.root}", but that directory does not exist.`,
1844
+ fix: `Fix the root path in ${compute.config.relativeConfigPath} or create the directory.`,
1845
+ where: appDir,
1846
+ meta: {
1847
+ appRoot: compute.target.root,
1848
+ appDir
1849
+ },
1850
+ exitCode: 2,
1851
+ nextSteps: ["prisma-cli app deploy"]
1852
+ });
1853
+ }
1854
+ return appDir;
1855
+ }
1856
+ /**
1857
+ * `prisma.app.json` is no longer read or written. A leftover file that
1858
+ * matches the effective settings only warns; one with custom values fails
1859
+ * with migration guidance so builds never silently change.
1860
+ */
1861
+ async function handleLegacyBuildSettings(context, appDir, effective) {
1862
+ const legacy = await detectLegacyBuildSettings({
1863
+ appPath: appDir,
1864
+ effective,
1865
+ signal: context.runtime.signal
1866
+ });
1867
+ switch (legacy.kind) {
1868
+ case "absent": return [];
1869
+ case "matching": return [`${PRISMA_APP_CONFIG_FILENAME} is no longer used and matches the resolved build settings. Delete it.`];
1870
+ case "invalid": return [`${PRISMA_APP_CONFIG_FILENAME} is no longer used and could not be parsed. Delete it.`];
1871
+ case "custom": {
1872
+ const buildBlock = [
1873
+ "build: {",
1874
+ ` command: ${legacy.buildCommand === null ? "null" : JSON.stringify(legacy.buildCommand)},`,
1875
+ ` outputDirectory: ${JSON.stringify(legacy.outputDirectory)},`,
1876
+ "}"
1877
+ ].join(" ");
1878
+ throw new CliError({
1879
+ code: "BUILD_SETTINGS_MIGRATION_REQUIRED",
1880
+ domain: "app",
1881
+ summary: `${PRISMA_APP_CONFIG_FILENAME} is no longer supported`,
1882
+ why: `${PRISMA_APP_CONFIG_FILENAME} contains custom build settings that differ from the resolved defaults, and the file is no longer read.`,
1883
+ fix: `Move the settings into prisma.compute.ts as \`${buildBlock}\` on this app, then delete ${PRISMA_APP_CONFIG_FILENAME}.`,
1884
+ where: legacy.configPath,
1885
+ meta: {
1886
+ configPath: legacy.configPath,
1887
+ buildCommand: legacy.buildCommand,
1888
+ outputDirectory: legacy.outputDirectory
1889
+ },
1890
+ exitCode: 2,
1891
+ nextSteps: ["prisma-cli app deploy"]
1892
+ });
1893
+ }
1894
+ }
1895
+ }
1557
1896
  async function resolveDeployFramework(context, options) {
1558
- if (options.requestedFramework) return frameworkFromUserFacingValue(options.requestedFramework, "set by --framework");
1897
+ if (options.requestedFramework) return frameworkFromUserFacingValue(options.requestedFramework, options.requestedFrameworkAnnotation ?? "set by --framework");
1559
1898
  if (options.entrypoint) return {
1560
1899
  key: "bun",
1561
1900
  buildType: "bun",
1562
1901
  displayName: "Bun",
1563
- annotation: "set by --entry"
1902
+ annotation: options.entrypointAnnotation ?? "set by --entry"
1564
1903
  };
1565
- const detected = await detectDeployFramework(context.runtime.cwd, context.runtime.signal);
1904
+ const detected = await detectDeployFramework(options.appDir, context.runtime.signal);
1566
1905
  if (detected) return detected;
1567
- throw frameworkNotDetectedError(context.runtime.cwd);
1906
+ throw frameworkNotDetectedError(options.appDir);
1568
1907
  }
1569
- function resolveDeployRuntime(requestedHttpPort, framework) {
1908
+ function resolveDeployRuntime(requestedHttpPort, requestedHttpPortAnnotation, framework) {
1570
1909
  if (requestedHttpPort) return {
1571
1910
  port: parseDeployHttpPort(requestedHttpPort),
1572
- annotation: "set by --http-port"
1911
+ annotation: requestedHttpPortAnnotation ?? "set by --http-port"
1573
1912
  };
1574
1913
  return {
1575
1914
  port: FRAMEWORK_DEFAULT_HTTP_PORT,
@@ -1584,8 +1923,8 @@ async function resolveDeployEntrypoint(cwd, framework, explicitEntrypoint, signa
1584
1923
  if (explicitEntrypoint || framework.buildType !== "bun") return explicitEntrypoint;
1585
1924
  const packageEntrypoint = readBunPackageEntrypoint(await readBunPackageJson(cwd, signal));
1586
1925
  if (packageEntrypoint) return packageEntrypoint;
1587
- if (framework.key !== "hono") return;
1588
- const defaultEntrypoint = "src/index.ts";
1926
+ const defaultEntrypoint = frameworkFromAlias(framework.key)?.defaultEntrypoint;
1927
+ if (!defaultEntrypoint) return;
1589
1928
  signal.throwIfAborted();
1590
1929
  try {
1591
1930
  await access(path.join(cwd, defaultEntrypoint));
@@ -1599,34 +1938,22 @@ async function resolveDeployEntrypoint(cwd, framework, explicitEntrypoint, signa
1599
1938
  }
1600
1939
  async function detectDeployFramework(cwd, signal) {
1601
1940
  const packageJson = await readBunPackageJson(cwd, signal);
1602
- const nextConfig = await detectNextConfig(cwd, signal);
1603
- if (nextConfig.exists || hasPackageDependency(packageJson, "next")) return {
1604
- key: "nextjs",
1605
- buildType: "nextjs",
1606
- displayName: "Next.js",
1607
- annotation: nextConfig.standalone ? "standalone output detected" : nextConfig.exists ? "detected from next.config" : "detected from package.json"
1608
- };
1609
- if (hasPackageDependency(packageJson, "hono")) return {
1610
- key: "hono",
1611
- buildType: "bun",
1612
- displayName: "Hono",
1613
- annotation: "detected from package.json"
1614
- };
1615
- if (hasAnyPackageDependency(packageJson, TANSTACK_START_PACKAGES)) return {
1616
- key: "tanstack-start",
1617
- buildType: "tanstack-start",
1618
- displayName: "TanStack Start",
1619
- annotation: "detected from package.json"
1620
- };
1941
+ for (const framework of FRAMEWORKS) {
1942
+ if (framework.detectConfigFiles.length === 0 && framework.detectPackages.length === 0) continue;
1943
+ const configFile = await detectFrameworkConfigFile(cwd, framework, signal);
1944
+ if (!configFile.exists && !hasAnyPackageDependency(packageJson, framework.detectPackages)) continue;
1945
+ const annotation = framework.key === "nextjs" && configFile.standalone ? "standalone output detected" : configFile.exists ? `detected from ${path.basename(configFile.path)}` : "detected from package.json";
1946
+ return {
1947
+ key: framework.key,
1948
+ buildType: framework.buildType,
1949
+ displayName: framework.displayName,
1950
+ annotation
1951
+ };
1952
+ }
1621
1953
  return null;
1622
1954
  }
1623
- async function detectNextConfig(cwd, signal) {
1624
- for (const candidate of [
1625
- "next.config.js",
1626
- "next.config.mjs",
1627
- "next.config.ts",
1628
- "next.config.mts"
1629
- ]) {
1955
+ async function detectFrameworkConfigFile(cwd, framework, signal) {
1956
+ for (const candidate of framework.detectConfigFiles) {
1630
1957
  const filePath = path.join(cwd, candidate);
1631
1958
  signal.throwIfAborted();
1632
1959
  try {
@@ -1636,7 +1963,8 @@ async function detectNextConfig(cwd, signal) {
1636
1963
  });
1637
1964
  return {
1638
1965
  exists: true,
1639
- standalone: /\boutput\s*:\s*["'`]standalone["'`]/.test(content)
1966
+ standalone: /\boutput\s*:\s*["'`]standalone["'`]/.test(content),
1967
+ path: filePath
1640
1968
  };
1641
1969
  } catch (error) {
1642
1970
  if (signal.aborted) throw error;
@@ -1645,7 +1973,8 @@ async function detectNextConfig(cwd, signal) {
1645
1973
  }
1646
1974
  return {
1647
1975
  exists: false,
1648
- standalone: false
1976
+ standalone: false,
1977
+ path: null
1649
1978
  };
1650
1979
  }
1651
1980
  function hasPackageDependency(packageJson, dependencyName) {
@@ -1658,48 +1987,36 @@ function hasDependency(dependencies, dependencyName) {
1658
1987
  return Boolean(dependencies && typeof dependencies === "object" && dependencyName in dependencies);
1659
1988
  }
1660
1989
  function frameworkFromUserFacingValue(value, annotation) {
1661
- switch (value.trim().toLowerCase()) {
1662
- case "next":
1663
- case "next.js":
1664
- case "nextjs": return {
1665
- key: "nextjs",
1666
- buildType: "nextjs",
1667
- displayName: "Next.js",
1668
- annotation
1669
- };
1670
- case "hono": return {
1671
- key: "hono",
1672
- buildType: "bun",
1673
- displayName: "Hono",
1674
- annotation
1675
- };
1676
- case "bun": return {
1677
- key: "bun",
1678
- buildType: "bun",
1679
- displayName: "Bun",
1680
- annotation
1681
- };
1682
- case "tanstack":
1683
- case "tanstack-start":
1684
- case "@tanstack/react-start":
1685
- case "@tanstack/solid-start": return {
1686
- key: "tanstack-start",
1687
- buildType: "tanstack-start",
1688
- displayName: "TanStack Start",
1689
- annotation
1690
- };
1691
- default: throw frameworkNotDetectedError(void 0, value);
1692
- }
1990
+ const framework = frameworkFromAlias(value);
1991
+ if (!framework) throw frameworkNotDetectedError(void 0, value);
1992
+ return {
1993
+ key: framework.key,
1994
+ buildType: framework.buildType,
1995
+ displayName: framework.displayName,
1996
+ annotation
1997
+ };
1998
+ }
1999
+ function assertConfigBackedBuildSettings(buildType) {
2000
+ if (isConfigBackedBuildType(buildType)) return;
2001
+ const displayName = FRAMEWORKS.find((framework) => framework.buildType === buildType)?.displayName ?? buildType;
2002
+ throw new CliError({
2003
+ code: "BUILD_SETTINGS_UNSUPPORTED",
2004
+ domain: "app",
2005
+ summary: `build settings are not supported for ${displayName} apps`,
2006
+ why: `${displayName} deploys run \`${buildType} build\` and package its output automatically.`,
2007
+ fix: "Remove the `build` block from prisma.compute.ts for this app.",
2008
+ exitCode: 2
2009
+ });
1693
2010
  }
1694
2011
  function frameworkNotDetectedError(cwd, requestedFramework) {
1695
- const supported = "Next.js, Hono, TanStack Start, Bun";
2012
+ const supported = FRAMEWORKS.map((framework) => framework.displayName).join(", ");
1696
2013
  const directory = cwd ? ` in ${formatDeployDirectory(cwd)}` : "";
1697
2014
  return new CliError({
1698
2015
  code: "FRAMEWORK_NOT_DETECTED",
1699
2016
  domain: "app",
1700
2017
  summary: requestedFramework ? `Unsupported framework "${requestedFramework}"` : `Cannot detect a supported framework${directory}`,
1701
2018
  why: `Supported Beta frameworks: ${supported}.`,
1702
- fix: "Add one of these frameworks as a dependency, pass --framework <nextjs|hono|tanstack-start|bun>, or pass --entry <path> for a Bun app.",
2019
+ fix: `Add one of these frameworks as a dependency, pass --framework <${FRAMEWORKS.map((framework) => framework.key).join("|")}>, or pass --entry <path> for a Bun app.`,
1703
2020
  exitCode: 2,
1704
2021
  nextSteps: [
1705
2022
  "prisma-cli app deploy --framework nextjs",
@@ -1712,23 +2029,31 @@ function frameworkNotDetectedError(cwd, requestedFramework) {
1712
2029
  }
1713
2030
  async function maybeRenderDeploySetupBlock(context, details) {
1714
2031
  if (context.flags.json || context.flags.quiet) return;
1715
- const directory = formatDeployDirectory(context.runtime.cwd);
2032
+ const directory = formatAppDirectoryLabel(context.runtime.cwd, details.appDir);
1716
2033
  const prefix = details.includeDirectory ? `Deploying ${directory} to` : "Deploying to";
1717
2034
  context.output.stderr.write(`${prefix} ${details.projectName} / ${details.branchName} / ${details.appName}\n\n`);
1718
2035
  }
1719
2036
  function maybeRenderDeployBuildSettings(context, resolution) {
1720
2037
  if (context.flags.json || context.flags.quiet) return;
1721
2038
  const settings = resolution.settings;
1722
- const title = resolution.status === "created" ? `Created ${resolution.relativeConfigPath}` : `Using ${resolution.relativeConfigPath}`;
1723
- context.output.stderr.write(`${title}\n${renderDeployOutputRows(context.ui, [{
1724
- label: "Build Command",
1725
- value: settings.buildCommand ?? "none",
1726
- origin: settings.buildCommandSource ?? void 0
1727
- }, {
1728
- label: "Output Directory",
1729
- value: settings.outputDirectory,
1730
- origin: settings.outputDirectorySource ?? void 0
1731
- }]).join("\n")}\n\n`);
2039
+ const title = resolution.status === "config" ? `Using ${resolution.relativeConfigPath}` : "Build settings";
2040
+ context.output.stderr.write(`${title}\n${renderDeployOutputRows(context.ui, [
2041
+ {
2042
+ label: "Build Command",
2043
+ value: settings.buildCommand ?? "none",
2044
+ origin: settings.buildCommandSource ?? void 0
2045
+ },
2046
+ {
2047
+ label: "Output Directory",
2048
+ value: settings.outputDirectory,
2049
+ origin: settings.outputDirectorySource ?? void 0
2050
+ },
2051
+ ...settings.entrypoint ? [{
2052
+ label: "Entrypoint",
2053
+ value: settings.entrypoint,
2054
+ origin: settings.entrypointSource ?? void 0
2055
+ }] : []
2056
+ ]).join("\n")}\n\n`);
1732
2057
  }
1733
2058
  function maybeRenderProjectLinked(context, directory, projectName, localPinPath) {
1734
2059
  if (context.flags.json || context.flags.quiet) return;
@@ -1756,9 +2081,9 @@ async function maybeCustomizeDeploySettings(context, options) {
1756
2081
  input: context.runtime.stdin,
1757
2082
  output: context.runtime.stderr,
1758
2083
  message: `Framework (${options.framework.displayName})`,
1759
- choices: DEPLOY_FRAMEWORKS.map((framework) => ({
1760
- label: frameworkDisplayName(framework),
1761
- value: framework
2084
+ choices: FRAMEWORKS.map((framework) => ({
2085
+ label: framework.displayName,
2086
+ value: framework.key
1762
2087
  }))
1763
2088
  }), "set by you");
1764
2089
  const requestedPort = await textPrompt({
@@ -1801,14 +2126,6 @@ function maybeRenderDeploySettingsPreview(context, options) {
1801
2126
  value: `HTTP ${options.runtime.port}`
1802
2127
  }]).join("\n")}\n\n`);
1803
2128
  }
1804
- function frameworkDisplayName(framework) {
1805
- switch (framework) {
1806
- case "nextjs": return "Next.js";
1807
- case "hono": return "Hono";
1808
- case "tanstack-start": return "TanStack Start";
1809
- case "bun": return "Bun";
1810
- }
1811
- }
1812
2129
  function validateDeployHttpPortText(value) {
1813
2130
  if (!value?.trim()) return;
1814
2131
  try {
@@ -1822,6 +2139,11 @@ function formatDeployDirectory(cwd) {
1822
2139
  const basename = path.basename(cwd);
1823
2140
  return basename ? `./${basename}` : ".";
1824
2141
  }
2142
+ function formatAppDirectoryLabel(cwd, appDir) {
2143
+ if (appDir === cwd) return formatDeployDirectory(cwd);
2144
+ const relative = path.relative(cwd, appDir).split(path.sep).join("/");
2145
+ return relative.startsWith("..") ? relative : `./${relative}`;
2146
+ }
1825
2147
  async function readCurrentWorkspaceId(context) {
1826
2148
  const state = await context.stateStore.read();
1827
2149
  if (state.auth?.workspaceId) return state.auth.workspaceId;
@@ -1830,26 +2152,36 @@ async function readCurrentWorkspaceId(context) {
1830
2152
  function normalizeBuildType(requestedBuildType) {
1831
2153
  if (!requestedBuildType) return "auto";
1832
2154
  if (isPreviewBuildType(requestedBuildType)) return requestedBuildType;
1833
- throw usageError(`Unsupported build type "${requestedBuildType}"`, `Only ${PREVIEW_BUILD_TYPES.join(", ")} are supported in the current preview.`, "Pass a supported --build-type value.", getBuildTypeExamples("build"), "app");
2155
+ throw usageError(`Unsupported build type "${requestedBuildType}"`, `Only ${APP_BUILD_TYPE_LABELS} are supported in the current preview.`, "Pass a supported --build-type value.", getBuildTypeExamples("build"), "app");
1834
2156
  }
1835
2157
  function isPreviewBuildType(value) {
1836
- return PREVIEW_BUILD_TYPES.includes(value);
2158
+ return APP_BUILD_TYPES.includes(value);
1837
2159
  }
1838
2160
  function getBuildTypeExamples(commandName) {
1839
- return RESOLVED_PREVIEW_BUILD_TYPES.map((buildType) => {
2161
+ return RESOLVED_APP_BUILD_TYPES.map((buildType) => {
1840
2162
  return `prisma-cli app ${commandName} --build-type ${buildType}${buildType === "bun" ? " --entry server.ts" : ""}`;
1841
2163
  });
1842
2164
  }
1843
2165
  function assertSupportedEntrypoint(buildType, entrypoint, commandName) {
1844
- if (buildType !== "auto" && buildType !== "bun" && entrypoint) {
2166
+ if (buildType !== "auto" && !ENTRYPOINT_BUILD_TYPES.includes(buildType) && entrypoint) {
1845
2167
  if (commandName === "deploy") throw usageError(`App deploy does not accept --entry with ${formatBuildTypeName(buildType)}`, `${formatBuildTypeName(buildType)} apps derive their runtime entrypoint from build output.`, "Remove --entry, or use --framework bun when you want to target a Bun entrypoint directly.", [`prisma-cli app deploy --framework ${buildType}`, "prisma-cli app deploy --framework bun --entry server.ts"], "app");
1846
2168
  throw usageError(`App ${commandName} does not accept --entry with --build-type ${buildType}`, `${formatBuildTypeName(buildType)} apps do not use an entrypoint flag in the current preview.`, `Remove --entry, or rerun prisma-cli app ${commandName} with --build-type bun when you want to target a Bun entrypoint directly.`, [`prisma-cli app ${commandName} --build-type ${buildType}`, `prisma-cli app ${commandName} --build-type bun --entry server.ts`], "app");
1847
2169
  }
1848
2170
  }
1849
- async function requireLocalBuildType(context, buildType, commandName) {
1850
- const resolvedBuildType = await resolveLocalBuildType(context.runtime.cwd, buildType, context.runtime.signal);
1851
- if (resolvedBuildType) return resolvedBuildType;
1852
- throw usageError(`App ${commandName} requires an explicit framework when detection is ambiguous`, "This preview only starts local dev servers for clear Next.js or Bun project shapes.", "Pass --build-type nextjs for a Next.js app, or pass --build-type bun with --entry <path> for a Bun app.", [`prisma-cli app ${commandName} --build-type nextjs`, `prisma-cli app ${commandName} --build-type bun --entry server.ts`], "app");
2171
+ /**
2172
+ * Resolves the framework for `app run` with the same detection as deploy, so
2173
+ * a repo that deploys without flags also runs without flags. Local dev server
2174
+ * support is intentionally narrower than deploy build support: only Next.js
2175
+ * and Bun/Hono have dev servers in the current preview.
2176
+ */
2177
+ async function resolveLocalRunFramework(context, options) {
2178
+ if (LOCAL_DEV_BUILD_TYPES.includes(options.requestedBuildType)) {
2179
+ if (options.configFramework && computeFrameworkToBuildType(options.configFramework) === options.requestedBuildType) return frameworkFromUserFacingValue(options.configFramework, `set by ${COMPUTE_CONFIG_FILENAME$1}`);
2180
+ return frameworkFromUserFacingValue(options.requestedBuildType, "set by --build-type");
2181
+ }
2182
+ const detected = await detectDeployFramework(options.appDir, context.runtime.signal);
2183
+ if (detected && LOCAL_DEV_BUILD_TYPES.includes(detected.buildType)) return detected;
2184
+ throw usageError("App run requires an explicit framework when detection is ambiguous", "This preview only starts local dev servers for clear Next.js or Bun project shapes.", "Pass --build-type nextjs for a Next.js app, or pass --build-type bun with --entry <path> for a Bun app.", ["prisma-cli app run --build-type nextjs", "prisma-cli app run --build-type bun --entry server.ts"], "app");
1853
2185
  }
1854
2186
  function parseLocalPort(requestedPort) {
1855
2187
  if (!requestedPort) return DEFAULT_LOCAL_DEV_PORT;
@@ -1976,6 +2308,18 @@ function localResolutionPinStaleError() {
1976
2308
  ]
1977
2309
  });
1978
2310
  }
2311
+ function localPinReadErrorToDeployError(error) {
2312
+ return matchError(error, {
2313
+ LocalResolutionPinInvalidJsonError: () => localResolutionPinStaleError(),
2314
+ LocalResolutionPinInvalidShapeError: () => localResolutionPinStaleError(),
2315
+ LocalResolutionPinReadAbortedError: (error) => {
2316
+ throw error;
2317
+ },
2318
+ UnhandledException: (error) => {
2319
+ throw error;
2320
+ }
2321
+ });
2322
+ }
1979
2323
  function readDeployEnvOverride(context, name) {
1980
2324
  const value = context.runtime.env[name]?.trim();
1981
2325
  return value ? value : void 0;
@@ -2054,14 +2398,12 @@ function isAutoBuildDetectionError(error) {
2054
2398
  return error instanceof Error && error.message.startsWith("Entrypoint is required.");
2055
2399
  }
2056
2400
  function formatBuildTypeName(buildType) {
2057
- switch (buildType) {
2058
- case "nextjs": return "Next.js";
2059
- case "nuxt": return "Nuxt";
2060
- case "astro": return "Astro";
2061
- case "tanstack-start": return "TanStack Start";
2062
- case "bun": return "Bun";
2063
- case "auto": return "Auto";
2401
+ if (buildType === "auto") return "Auto";
2402
+ for (let index = FRAMEWORKS.length - 1; index >= 0; index -= 1) {
2403
+ const framework = FRAMEWORKS[index];
2404
+ if (framework?.buildType === buildType) return framework.displayName;
2064
2405
  }
2406
+ return buildType;
2065
2407
  }
2066
2408
  function removeFailedError(summary, error, nextSteps) {
2067
2409
  return new CliError({