@prisma/cli 3.0.0-beta.9 → 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 (53) hide show
  1. package/README.md +0 -13
  2. package/dist/adapters/token-storage.js +311 -33
  3. package/dist/cli.js +7 -7
  4. package/dist/cli2.js +3 -3
  5. package/dist/commands/app/index.js +65 -52
  6. package/dist/commands/auth/index.js +55 -2
  7. package/dist/controllers/app-env.js +10 -7
  8. package/dist/controllers/app.js +536 -207
  9. package/dist/controllers/auth.js +211 -2
  10. package/dist/controllers/branch.js +5 -6
  11. package/dist/controllers/database.js +7 -5
  12. package/dist/controllers/project.js +33 -18
  13. package/dist/lib/app/app-interaction.js +5 -0
  14. package/dist/lib/app/{preview-provider.js → app-provider.js} +32 -28
  15. package/dist/lib/app/{preview-branch-database.js → branch-database-api.js} +1 -1
  16. package/dist/lib/app/branch-database-deploy.js +12 -60
  17. package/dist/lib/app/branch-database.js +1 -102
  18. package/dist/lib/app/build-settings.js +93 -0
  19. package/dist/lib/app/build.js +82 -0
  20. package/dist/lib/app/bun-project.js +2 -3
  21. package/dist/lib/app/compute-config.js +147 -0
  22. package/dist/lib/app/deploy-plan.js +58 -0
  23. package/dist/lib/app/{preview-progress.js → deploy-progress.js} +5 -5
  24. package/dist/lib/app/local-dev.js +3 -60
  25. package/dist/lib/app/production-deploy-gate.js +3 -3
  26. package/dist/lib/app/read-branch.js +30 -0
  27. package/dist/lib/auth/auth-ops.js +10 -4
  28. package/dist/lib/auth/guard.js +4 -1
  29. package/dist/lib/auth/login.js +32 -25
  30. package/dist/lib/diagnostics.js +1 -1
  31. package/dist/lib/fs/home-path.js +24 -0
  32. package/dist/lib/git/local-branch.js +15 -3
  33. package/dist/lib/project/local-pin.js +106 -26
  34. package/dist/lib/project/resolution.js +162 -71
  35. package/dist/lib/project/setup.js +65 -19
  36. package/dist/output/patterns.js +1 -1
  37. package/dist/presenters/app.js +44 -39
  38. package/dist/presenters/auth.js +98 -1
  39. package/dist/presenters/branch.js +1 -1
  40. package/dist/presenters/database.js +2 -2
  41. package/dist/presenters/project.js +3 -9
  42. package/dist/shell/command-meta.js +52 -2
  43. package/dist/shell/command-runner.js +39 -28
  44. package/dist/shell/diagnostics-output.js +2 -8
  45. package/dist/shell/errors.js +50 -1
  46. package/dist/shell/help.js +30 -20
  47. package/dist/shell/runtime.js +8 -4
  48. package/dist/shell/ui.js +19 -2
  49. package/dist/use-cases/auth.js +68 -1
  50. package/package.json +17 -3
  51. package/dist/lib/app/preview-build-settings.js +0 -385
  52. package/dist/lib/app/preview-build.js +0 -475
  53. package/dist/lib/app/preview-interaction.js +0 -5
@@ -1,59 +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";
33
- import open from "open";
34
37
  import { Result, matchError } from "better-result";
38
+ import open from "open";
35
39
  //#region src/controllers/app.ts
36
- const DEPLOY_FRAMEWORKS = [
37
- "nextjs",
38
- "hono",
39
- "tanstack-start",
40
- "bun"
41
- ];
42
- const TANSTACK_START_PACKAGES = ["@tanstack/react-start", "@tanstack/solid-start"];
43
40
  const FRAMEWORK_DEFAULT_HTTP_PORT = 3e3;
44
41
  const PRISMA_PROJECT_ID_ENV_VAR = "PRISMA_PROJECT_ID";
45
42
  const PRISMA_APP_ID_ENV_VAR = "PRISMA_APP_ID";
46
43
  function isRealMode(context) {
47
44
  return !context.runtime.fixturePath && !context.runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
48
45
  }
49
- async function runAppBuild(context, entrypoint, requestedBuildType) {
50
- const buildType = normalizeBuildType(requestedBuildType);
51
- 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;
52
71
  try {
53
- const { artifact, buildType: actualBuildType } = await executePreviewBuild({
54
- appPath: context.runtime.cwd,
55
- entrypoint,
72
+ const { artifact, buildType: actualBuildType } = await executeAppBuild({
73
+ appPath: appDir,
74
+ entrypoint: merged.entrypoint,
56
75
  buildType,
76
+ buildSettings,
57
77
  signal: context.runtime.signal
58
78
  });
59
79
  return {
@@ -67,21 +87,37 @@ async function runAppBuild(context, entrypoint, requestedBuildType) {
67
87
  nextSteps: ["prisma-cli app deploy"]
68
88
  };
69
89
  } catch (error) {
70
- 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");
71
91
  throw buildFailedError("Local app build failed", error);
72
92
  }
73
93
  }
74
- async function runAppRun(context, entrypoint, requestedBuildType, requestedPort) {
94
+ async function runAppRun(context, options) {
75
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");
76
- const buildType = normalizeBuildType(requestedBuildType);
77
- assertSupportedEntrypoint(buildType, entrypoint, "run");
78
- const port = parseLocalPort(requestedPort);
79
- 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;
80
116
  let runResult;
81
117
  try {
82
118
  runResult = await runLocalApp({
83
- appPath: context.runtime.cwd,
84
- buildType: resolvedBuildType,
119
+ appPath: appDir,
120
+ buildType: framework.buildType,
85
121
  entrypoint,
86
122
  port,
87
123
  env: context.runtime.env,
@@ -106,6 +142,106 @@ async function runAppRun(context, entrypoint, requestedBuildType, requestedPort)
106
142
  }
107
143
  async function runAppDeploy(context, appName, options) {
108
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) {
109
245
  const envProjectId = readDeployEnvOverride(context, PRISMA_PROJECT_ID_ENV_VAR);
110
246
  const envAppId = readDeployEnvOverride(context, PRISMA_APP_ID_ENV_VAR);
111
247
  assertExclusiveDeployProjectInputs({
@@ -113,14 +249,27 @@ async function runAppDeploy(context, appName, options) {
113
249
  createProjectName: options?.createProjectName,
114
250
  envProjectId
115
251
  });
116
- const localPinReadResult = Boolean(envProjectId || options?.projectRef || options?.createProjectName) ? Result.ok({ kind: "missing" }) : await readLocalResolutionPin(context.runtime.cwd, context.runtime.signal);
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);
117
266
  if (localPinReadResult.isErr()) throw localPinReadErrorToDeployError(localPinReadResult.error);
118
267
  const localPin = localPinReadResult.value;
119
268
  const branch = await resolveDeployBranch(context, options?.branchName);
120
- if (options?.httpPort) parseDeployHttpPort(options.httpPort);
269
+ if (merged.httpPort) parseDeployHttpPort(merged.httpPort.value);
121
270
  assertSupportedEntrypointForRequestedDeployShape({
122
- requestedFramework: options?.framework,
123
- entrypoint: options?.entrypoint
271
+ requestedFramework: merged.framework?.value,
272
+ entrypoint: merged.entrypoint?.value
124
273
  });
125
274
  const { provider, target, projectId } = await requireProviderAndDeployProjectContext(context, options?.projectRef, {
126
275
  branch,
@@ -130,25 +279,32 @@ async function runAppDeploy(context, appName, options) {
130
279
  });
131
280
  let localPinResult;
132
281
  if (target.localPinAction) {
133
- const setupResult = await bindProjectToDirectory(context, target.workspace, target.project, target.localPinAction);
134
- localPinResult = setupResult.localPin;
135
- 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);
136
287
  }
137
288
  let framework = await resolveDeployFramework(context, {
138
- requestedFramework: options?.framework,
139
- entrypoint: options?.entrypoint
140
- });
141
- let runtime = resolveDeployRuntime(options?.httpPort, framework);
142
- assertSupportedEntrypoint(framework.buildType, options?.entrypoint, "deploy");
143
- 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" }));
144
298
  const selectedApp = await resolveDeployAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), {
145
299
  explicitAppName: appName,
146
300
  explicitAppId: envAppId,
301
+ configAppName: merged.configAppName,
147
302
  firstDeploy: Boolean(target.localPinAction),
148
- inferName: () => inferTargetName(context.runtime.cwd, context.runtime.signal)
303
+ inferName: () => inferTargetName(appDir, context.runtime.signal)
149
304
  });
150
305
  await maybeRenderDeploySetupBlock(context, {
151
306
  includeDirectory: !target.localPinAction,
307
+ appDir,
152
308
  projectName: target.project.name,
153
309
  branchName: target.branch.name,
154
310
  appName: selectedApp.displayName
@@ -157,9 +313,9 @@ async function runAppDeploy(context, appName, options) {
157
313
  framework,
158
314
  runtime,
159
315
  firstDeploy: selectedApp.firstDeploy,
160
- explicitFramework: Boolean(options?.framework),
161
- explicitEntrypoint: Boolean(options?.entrypoint),
162
- explicitHttpPort: Boolean(options?.httpPort)
316
+ explicitFramework: Boolean(merged.framework),
317
+ explicitEntrypoint: Boolean(merged.entrypoint),
318
+ explicitHttpPort: Boolean(merged.httpPort)
163
319
  });
164
320
  framework = customized.framework;
165
321
  runtime = customized.runtime;
@@ -170,24 +326,33 @@ async function runAppDeploy(context, appName, options) {
170
326
  prod: options?.prod === true
171
327
  });
172
328
  const buildType = framework.buildType;
173
- assertSupportedEntrypoint(buildType, options?.entrypoint, "deploy");
174
- const entrypoint = await resolveDeployEntrypoint(context.runtime.cwd, framework, options?.entrypoint, context.runtime.signal);
175
- const buildSettingsResolution = await resolveOrCreatePreviewBuildSettings({
176
- 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,
177
340
  buildType,
178
341
  signal: context.runtime.signal
179
342
  });
343
+ const legacyWarnings = await handleLegacyBuildSettings(context, appDir, buildSettingsResolution.settings);
180
344
  maybeRenderDeployBuildSettings(context, buildSettingsResolution);
181
345
  const portMapping = parseDeployPortMapping(String(runtime.port));
182
346
  const branchDatabaseSetup = await maybeSetupBranchDatabase(context, provider, projectId, toBranchDatabaseDeployBranch(target.branch), {
183
347
  db: options?.db,
184
348
  providedEnvVars: envVars,
185
- firstProductionDeploy: productionDeployGate.firstProductionDeploy
349
+ firstProductionDeploy: productionDeployGate.firstProductionDeploy,
350
+ projectDir
186
351
  });
187
- const progressState = createPreviewDeployProgressState();
352
+ const progressState = createDeployProgressState();
188
353
  const deployStartedAt = Date.now();
189
354
  const deployResult = await provider.deployApp({
190
- cwd: context.runtime.cwd,
355
+ cwd: appDir,
191
356
  projectId,
192
357
  branchName: target.branch.name,
193
358
  appId: selectedApp.appId,
@@ -200,7 +365,7 @@ async function runAppDeploy(context, appName, options) {
200
365
  envVars,
201
366
  interaction: void 0,
202
367
  signal: context.runtime.signal,
203
- 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)
204
369
  }).catch((error) => {
205
370
  throw appDeployFailedError(error, progressState);
206
371
  });
@@ -242,7 +407,7 @@ async function runAppDeploy(context, appName, options) {
242
407
  name: framework.displayName,
243
408
  source: framework.annotation
244
409
  },
245
- entrypoint: entrypoint ?? null,
410
+ entrypoint: entrypoint ?? buildSettingsResolution.settings.entrypoint ?? null,
246
411
  httpPort: runtime.port,
247
412
  region: selectedApp.region ?? null,
248
413
  envVars: envVarNames(envVars)
@@ -250,14 +415,18 @@ async function runAppDeploy(context, appName, options) {
250
415
  durationMs: deployDurationMs,
251
416
  localPin: localPinResult
252
417
  },
253
- warnings: branchDatabaseSetup.warnings,
418
+ warnings: [...legacyWarnings, ...branchDatabaseSetup.warnings],
254
419
  nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${deployResult.deployment.id}`]
255
420
  };
256
421
  }
257
- async function runAppListDeploys(context, appName, projectRef) {
422
+ async function runAppListDeploys(context, appName, projectRef, configTarget) {
258
423
  ensurePreviewAppMode(context);
259
- const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app list-deploys" });
260
- 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);
261
430
  if (!selectedApp) return {
262
431
  command: "app.list-deploys",
263
432
  result: {
@@ -293,10 +462,14 @@ async function runAppListDeploys(context, appName, projectRef) {
293
462
  nextSteps: deployments.length > 0 ? [`prisma-cli app show-deploy ${deployments[0]?.id}`] : ["prisma-cli app deploy"]
294
463
  };
295
464
  }
296
- async function runAppShow(context, appName, projectRef) {
465
+ async function runAppShow(context, appName, projectRef, configTarget) {
297
466
  ensurePreviewAppMode(context);
298
- const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app show" });
299
- 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);
300
473
  if (!selectedApp) return {
301
474
  command: "app.show",
302
475
  result: {
@@ -371,9 +544,14 @@ async function runAppShowDeploy(context, deploymentId) {
371
544
  nextSteps: []
372
545
  };
373
546
  }
374
- async function runAppOpen(context, appName, projectRef) {
547
+ async function runAppOpen(context, appName, projectRef, configTarget) {
375
548
  ensurePreviewAppMode(context);
376
- 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
+ });
377
555
  const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName);
378
556
  if (!selectedApp) throw noDeploymentsError("No deployments available to open", "The resolved project does not have any deployed app yet.");
379
557
  const deploymentsResult = await provider.listDeployments(selectedApp.id, { signal: context.runtime.signal }).catch((error) => {
@@ -537,15 +715,19 @@ async function runAppDomainWait(context, hostname, options) {
537
715
  });
538
716
  }
539
717
  }
540
- async function runAppLogs(context, appName, deploymentId, projectRef) {
718
+ async function runAppLogs(context, appName, deploymentId, projectRef, configTarget) {
541
719
  ensurePreviewAppMode(context);
542
- 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
+ });
543
726
  const target = deploymentId ? await resolveExplicitLogDeployment(context, provider, projectId, resolvedTarget.branch.name, appName, deploymentId) : await resolveLiveLogDeployment(context, provider, projectId, resolvedTarget.branch.name, appName);
544
727
  if (!context.flags.json && !context.flags.quiet) {
545
728
  const lines = renderCommandHeader(context.ui, {
546
729
  commandLabel: "app logs",
547
730
  description: "Streaming logs for the selected deployment.",
548
- docsPath: "docs/product/command-spec.md#prisma-cli-app-logs---app-name---deployment-id",
549
731
  rows: [
550
732
  {
551
733
  key: "project",
@@ -662,9 +844,14 @@ function writeLogRecord(context, record) {
662
844
  if (!record.text.endsWith("\n")) context.output.stdout.write("\n");
663
845
  }
664
846
  }
665
- async function runAppPromote(context, deploymentId, appName, projectRef) {
847
+ async function runAppPromote(context, deploymentId, appName, projectRef, configTarget) {
666
848
  ensurePreviewAppMode(context);
667
- 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
+ });
668
855
  const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName, "promote");
669
856
  const deploymentsResult = await provider.listDeployments(selectedApp.id, { signal: context.runtime.signal }).catch((error) => {
670
857
  throw deployFailedError("Failed to list app deployments", error, ["prisma-cli app list-deploys"]);
@@ -680,7 +867,7 @@ async function runAppPromote(context, deploymentId, appName, projectRef) {
680
867
  appId: selectedApp.id,
681
868
  deploymentId: targetDeployment.id,
682
869
  signal: context.runtime.signal,
683
- progress: createPreviewPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
870
+ progress: createPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
684
871
  }).catch((error) => {
685
872
  throw deployFailedError("Failed to promote deployment", error, ["prisma-cli app list-deploys"]);
686
873
  });
@@ -704,9 +891,14 @@ async function runAppPromote(context, deploymentId, appName, projectRef) {
704
891
  nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${targetDeployment.id}`]
705
892
  };
706
893
  }
707
- async function runAppRollback(context, appName, deploymentId, projectRef) {
894
+ async function runAppRollback(context, appName, deploymentId, projectRef, configTarget) {
708
895
  ensurePreviewAppMode(context);
709
- 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
+ });
710
902
  const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName, "rollback");
711
903
  const deploymentsResult = await provider.listDeployments(selectedApp.id, { signal: context.runtime.signal }).catch((error) => {
712
904
  throw deployFailedError("Failed to list app deployments", error, ["prisma-cli app list-deploys"]);
@@ -723,7 +915,7 @@ async function runAppRollback(context, appName, deploymentId, projectRef) {
723
915
  appId: selectedApp.id,
724
916
  deploymentId: targetDeployment.id,
725
917
  signal: context.runtime.signal,
726
- progress: createPreviewPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
918
+ progress: createPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
727
919
  }).catch((error) => {
728
920
  throw deployFailedError("Failed to roll back deployment", error, ["prisma-cli app list-deploys"]);
729
921
  });
@@ -748,9 +940,14 @@ async function runAppRollback(context, appName, deploymentId, projectRef) {
748
940
  nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${targetDeployment.id}`]
749
941
  };
750
942
  }
751
- async function runAppRemove(context, appName, projectRef) {
943
+ async function runAppRemove(context, appName, projectRef, configTarget) {
752
944
  ensurePreviewAppMode(context);
753
- 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
+ });
754
951
  const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName, "remove");
755
952
  await confirmAppRemoval(context, selectedApp);
756
953
  const removedApp = await provider.removeApp(selectedApp.id, { signal: context.runtime.signal }).catch((error) => {
@@ -774,6 +971,7 @@ async function runAppRemove(context, appName, projectRef) {
774
971
  }
775
972
  async function resolveAppDomainTarget(context, options, commandName = "app domain") {
776
973
  ensurePreviewAppMode(context);
974
+ const compute = await resolveComputeManagementContext(context, options?.configTarget, commandName.replace(/^app /, ""));
777
975
  const branch = resolveDomainBranch(options?.branchName);
778
976
  if (toBranchKind(branch.name) !== "production") throw new CliError({
779
977
  code: "BRANCH_NOT_DEPLOYABLE",
@@ -789,10 +987,11 @@ async function resolveAppDomainTarget(context, options, commandName = "app domai
789
987
  const { provider, target, projectId } = await requireProviderAndProjectContext(context, options?.projectRef, {
790
988
  branch,
791
989
  commandName,
792
- envProjectId
990
+ envProjectId,
991
+ projectDir: compute.projectDir
793
992
  });
794
993
  const selectedApp = await resolveDomainAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), {
795
- explicitAppName: options?.appName,
994
+ explicitAppName: options?.appName ?? compute.configAppName,
796
995
  explicitAppId: envAppId
797
996
  });
798
997
  await context.stateStore.setSelectedApp(projectId, {
@@ -908,7 +1107,7 @@ async function confirmDomainRemoval(context, target, hostname) {
908
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");
909
1108
  }
910
1109
  function domainCommandError(command, error, hostname) {
911
- if (error instanceof PreviewDomainApiError) {
1110
+ if (error instanceof DomainApiError) {
912
1111
  if (command === "add" && (error.status === 400 || error.status === 422) && isDomainDnsError(error)) return domainDnsNotConfiguredError(hostname, error);
913
1112
  if (command === "add" && error.status === 400) return new CliError({
914
1113
  code: "DOMAIN_HOSTNAME_INVALID",
@@ -1089,7 +1288,7 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
1089
1288
  };
1090
1289
  return {
1091
1290
  appName: options.explicitAppName,
1092
- region: PREVIEW_DEFAULT_REGION,
1291
+ region: DEFAULT_REGION,
1093
1292
  displayName: options.explicitAppName,
1094
1293
  annotation: "set by --app",
1095
1294
  firstDeploy: options.firstDeploy
@@ -1105,6 +1304,25 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
1105
1304
  firstDeploy: options.firstDeploy
1106
1305
  };
1107
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
+ }
1108
1326
  const inferredName = await options.inferName();
1109
1327
  const matches = findAppsByName(apps, inferredName.name);
1110
1328
  if (matches.length > 1) return resolveAmbiguousDeployApp(context, matches, inferredName.name, options.firstDeploy);
@@ -1117,7 +1335,7 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
1117
1335
  };
1118
1336
  return {
1119
1337
  appName: inferredName.name,
1120
- region: PREVIEW_DEFAULT_REGION,
1338
+ region: DEFAULT_REGION,
1121
1339
  displayName: inferredName.name,
1122
1340
  annotation: inferredName.source === "package-name" ? "created from package.json" : "created from directory name",
1123
1341
  firstDeploy: options.firstDeploy
@@ -1149,7 +1367,7 @@ async function resolveAmbiguousDeployApp(context, matches, targetName, firstDepl
1149
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");
1150
1368
  if (selected === createNew) return {
1151
1369
  appName: targetName,
1152
- region: PREVIEW_DEFAULT_REGION,
1370
+ region: DEFAULT_REGION,
1153
1371
  displayName: targetName,
1154
1372
  annotation: "created from package.json",
1155
1373
  firstDeploy
@@ -1314,7 +1532,7 @@ async function requirePreviewAppProviderWithClient(context) {
1314
1532
  if (!client) throw authRequiredError(["prisma-cli auth login"]);
1315
1533
  return {
1316
1534
  client,
1317
- provider: createPreviewAppProvider(client, createPreviewLogAuthOptions(context.runtime.env, context.runtime.signal))
1535
+ provider: createAppProvider(client, createPreviewLogAuthOptions(context.runtime.env, context.runtime.signal))
1318
1536
  };
1319
1537
  }
1320
1538
  function createPreviewLogAuthOptions(env, signal) {
@@ -1356,21 +1574,29 @@ async function requireProviderAndDeployProjectContext(context, explicitProject,
1356
1574
  async function resolveProjectContext(context, client, explicitProject, options) {
1357
1575
  const authState = await requireAuthenticatedAuthState(context);
1358
1576
  if (!authState.workspace) throw workspaceRequiredError();
1359
- const resolved = await resolveProjectTarget({
1577
+ const resolvedResult = await resolveProjectTarget({
1360
1578
  context,
1361
1579
  workspace: authState.workspace,
1362
1580
  explicitProject,
1363
1581
  envProjectId: options?.envProjectId,
1582
+ projectDir: options?.projectDir,
1364
1583
  listProjects: () => listRealWorkspaceProjects(client, authState.workspace, context.runtime.signal),
1365
1584
  commandName: options?.commandName
1366
1585
  });
1367
- 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
+ });
1368
1594
  return {
1369
1595
  ...resolved,
1370
- branch: {
1596
+ branch: remoteBranch ?? {
1371
1597
  id: null,
1372
- name: branch.name,
1373
- kind: toBranchKind(branch.name)
1598
+ name: requested.name,
1599
+ kind: toBranchKind(requested.name)
1374
1600
  }
1375
1601
  };
1376
1602
  }
@@ -1418,7 +1644,11 @@ async function resolveDeployProjectContext(context, client, provider, explicitPr
1418
1644
  }
1419
1645
  const localPin = options.localPin;
1420
1646
  if (localPin.kind === "present") {
1421
- 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
+ });
1422
1652
  const project = projects.find((candidate) => candidate.id === localPin.pin.projectId);
1423
1653
  if (!project) throw localResolutionPinStaleError();
1424
1654
  return withRemoteDeployBranch(provider, {
@@ -1555,22 +1785,130 @@ async function resolveDeployBranch(context, explicitBranchName) {
1555
1785
  annotation: "default"
1556
1786
  };
1557
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
+ }
1558
1896
  async function resolveDeployFramework(context, options) {
1559
- if (options.requestedFramework) return frameworkFromUserFacingValue(options.requestedFramework, "set by --framework");
1897
+ if (options.requestedFramework) return frameworkFromUserFacingValue(options.requestedFramework, options.requestedFrameworkAnnotation ?? "set by --framework");
1560
1898
  if (options.entrypoint) return {
1561
1899
  key: "bun",
1562
1900
  buildType: "bun",
1563
1901
  displayName: "Bun",
1564
- annotation: "set by --entry"
1902
+ annotation: options.entrypointAnnotation ?? "set by --entry"
1565
1903
  };
1566
- const detected = await detectDeployFramework(context.runtime.cwd, context.runtime.signal);
1904
+ const detected = await detectDeployFramework(options.appDir, context.runtime.signal);
1567
1905
  if (detected) return detected;
1568
- throw frameworkNotDetectedError(context.runtime.cwd);
1906
+ throw frameworkNotDetectedError(options.appDir);
1569
1907
  }
1570
- function resolveDeployRuntime(requestedHttpPort, framework) {
1908
+ function resolveDeployRuntime(requestedHttpPort, requestedHttpPortAnnotation, framework) {
1571
1909
  if (requestedHttpPort) return {
1572
1910
  port: parseDeployHttpPort(requestedHttpPort),
1573
- annotation: "set by --http-port"
1911
+ annotation: requestedHttpPortAnnotation ?? "set by --http-port"
1574
1912
  };
1575
1913
  return {
1576
1914
  port: FRAMEWORK_DEFAULT_HTTP_PORT,
@@ -1585,8 +1923,8 @@ async function resolveDeployEntrypoint(cwd, framework, explicitEntrypoint, signa
1585
1923
  if (explicitEntrypoint || framework.buildType !== "bun") return explicitEntrypoint;
1586
1924
  const packageEntrypoint = readBunPackageEntrypoint(await readBunPackageJson(cwd, signal));
1587
1925
  if (packageEntrypoint) return packageEntrypoint;
1588
- if (framework.key !== "hono") return;
1589
- const defaultEntrypoint = "src/index.ts";
1926
+ const defaultEntrypoint = frameworkFromAlias(framework.key)?.defaultEntrypoint;
1927
+ if (!defaultEntrypoint) return;
1590
1928
  signal.throwIfAborted();
1591
1929
  try {
1592
1930
  await access(path.join(cwd, defaultEntrypoint));
@@ -1600,34 +1938,22 @@ async function resolveDeployEntrypoint(cwd, framework, explicitEntrypoint, signa
1600
1938
  }
1601
1939
  async function detectDeployFramework(cwd, signal) {
1602
1940
  const packageJson = await readBunPackageJson(cwd, signal);
1603
- const nextConfig = await detectNextConfig(cwd, signal);
1604
- if (nextConfig.exists || hasPackageDependency(packageJson, "next")) return {
1605
- key: "nextjs",
1606
- buildType: "nextjs",
1607
- displayName: "Next.js",
1608
- annotation: nextConfig.standalone ? "standalone output detected" : nextConfig.exists ? "detected from next.config" : "detected from package.json"
1609
- };
1610
- if (hasPackageDependency(packageJson, "hono")) return {
1611
- key: "hono",
1612
- buildType: "bun",
1613
- displayName: "Hono",
1614
- annotation: "detected from package.json"
1615
- };
1616
- if (hasAnyPackageDependency(packageJson, TANSTACK_START_PACKAGES)) return {
1617
- key: "tanstack-start",
1618
- buildType: "tanstack-start",
1619
- displayName: "TanStack Start",
1620
- annotation: "detected from package.json"
1621
- };
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
+ }
1622
1953
  return null;
1623
1954
  }
1624
- async function detectNextConfig(cwd, signal) {
1625
- for (const candidate of [
1626
- "next.config.js",
1627
- "next.config.mjs",
1628
- "next.config.ts",
1629
- "next.config.mts"
1630
- ]) {
1955
+ async function detectFrameworkConfigFile(cwd, framework, signal) {
1956
+ for (const candidate of framework.detectConfigFiles) {
1631
1957
  const filePath = path.join(cwd, candidate);
1632
1958
  signal.throwIfAborted();
1633
1959
  try {
@@ -1637,7 +1963,8 @@ async function detectNextConfig(cwd, signal) {
1637
1963
  });
1638
1964
  return {
1639
1965
  exists: true,
1640
- standalone: /\boutput\s*:\s*["'`]standalone["'`]/.test(content)
1966
+ standalone: /\boutput\s*:\s*["'`]standalone["'`]/.test(content),
1967
+ path: filePath
1641
1968
  };
1642
1969
  } catch (error) {
1643
1970
  if (signal.aborted) throw error;
@@ -1646,7 +1973,8 @@ async function detectNextConfig(cwd, signal) {
1646
1973
  }
1647
1974
  return {
1648
1975
  exists: false,
1649
- standalone: false
1976
+ standalone: false,
1977
+ path: null
1650
1978
  };
1651
1979
  }
1652
1980
  function hasPackageDependency(packageJson, dependencyName) {
@@ -1659,48 +1987,36 @@ function hasDependency(dependencies, dependencyName) {
1659
1987
  return Boolean(dependencies && typeof dependencies === "object" && dependencyName in dependencies);
1660
1988
  }
1661
1989
  function frameworkFromUserFacingValue(value, annotation) {
1662
- switch (value.trim().toLowerCase()) {
1663
- case "next":
1664
- case "next.js":
1665
- case "nextjs": return {
1666
- key: "nextjs",
1667
- buildType: "nextjs",
1668
- displayName: "Next.js",
1669
- annotation
1670
- };
1671
- case "hono": return {
1672
- key: "hono",
1673
- buildType: "bun",
1674
- displayName: "Hono",
1675
- annotation
1676
- };
1677
- case "bun": return {
1678
- key: "bun",
1679
- buildType: "bun",
1680
- displayName: "Bun",
1681
- annotation
1682
- };
1683
- case "tanstack":
1684
- case "tanstack-start":
1685
- case "@tanstack/react-start":
1686
- case "@tanstack/solid-start": return {
1687
- key: "tanstack-start",
1688
- buildType: "tanstack-start",
1689
- displayName: "TanStack Start",
1690
- annotation
1691
- };
1692
- default: throw frameworkNotDetectedError(void 0, value);
1693
- }
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
+ });
1694
2010
  }
1695
2011
  function frameworkNotDetectedError(cwd, requestedFramework) {
1696
- const supported = "Next.js, Hono, TanStack Start, Bun";
2012
+ const supported = FRAMEWORKS.map((framework) => framework.displayName).join(", ");
1697
2013
  const directory = cwd ? ` in ${formatDeployDirectory(cwd)}` : "";
1698
2014
  return new CliError({
1699
2015
  code: "FRAMEWORK_NOT_DETECTED",
1700
2016
  domain: "app",
1701
2017
  summary: requestedFramework ? `Unsupported framework "${requestedFramework}"` : `Cannot detect a supported framework${directory}`,
1702
2018
  why: `Supported Beta frameworks: ${supported}.`,
1703
- 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.`,
1704
2020
  exitCode: 2,
1705
2021
  nextSteps: [
1706
2022
  "prisma-cli app deploy --framework nextjs",
@@ -1713,23 +2029,31 @@ function frameworkNotDetectedError(cwd, requestedFramework) {
1713
2029
  }
1714
2030
  async function maybeRenderDeploySetupBlock(context, details) {
1715
2031
  if (context.flags.json || context.flags.quiet) return;
1716
- const directory = formatDeployDirectory(context.runtime.cwd);
2032
+ const directory = formatAppDirectoryLabel(context.runtime.cwd, details.appDir);
1717
2033
  const prefix = details.includeDirectory ? `Deploying ${directory} to` : "Deploying to";
1718
2034
  context.output.stderr.write(`${prefix} ${details.projectName} / ${details.branchName} / ${details.appName}\n\n`);
1719
2035
  }
1720
2036
  function maybeRenderDeployBuildSettings(context, resolution) {
1721
2037
  if (context.flags.json || context.flags.quiet) return;
1722
2038
  const settings = resolution.settings;
1723
- const title = resolution.status === "created" ? `Created ${resolution.relativeConfigPath}` : `Using ${resolution.relativeConfigPath}`;
1724
- context.output.stderr.write(`${title}\n${renderDeployOutputRows(context.ui, [{
1725
- label: "Build Command",
1726
- value: settings.buildCommand ?? "none",
1727
- origin: settings.buildCommandSource ?? void 0
1728
- }, {
1729
- label: "Output Directory",
1730
- value: settings.outputDirectory,
1731
- origin: settings.outputDirectorySource ?? void 0
1732
- }]).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`);
1733
2057
  }
1734
2058
  function maybeRenderProjectLinked(context, directory, projectName, localPinPath) {
1735
2059
  if (context.flags.json || context.flags.quiet) return;
@@ -1757,9 +2081,9 @@ async function maybeCustomizeDeploySettings(context, options) {
1757
2081
  input: context.runtime.stdin,
1758
2082
  output: context.runtime.stderr,
1759
2083
  message: `Framework (${options.framework.displayName})`,
1760
- choices: DEPLOY_FRAMEWORKS.map((framework) => ({
1761
- label: frameworkDisplayName(framework),
1762
- value: framework
2084
+ choices: FRAMEWORKS.map((framework) => ({
2085
+ label: framework.displayName,
2086
+ value: framework.key
1763
2087
  }))
1764
2088
  }), "set by you");
1765
2089
  const requestedPort = await textPrompt({
@@ -1802,14 +2126,6 @@ function maybeRenderDeploySettingsPreview(context, options) {
1802
2126
  value: `HTTP ${options.runtime.port}`
1803
2127
  }]).join("\n")}\n\n`);
1804
2128
  }
1805
- function frameworkDisplayName(framework) {
1806
- switch (framework) {
1807
- case "nextjs": return "Next.js";
1808
- case "hono": return "Hono";
1809
- case "tanstack-start": return "TanStack Start";
1810
- case "bun": return "Bun";
1811
- }
1812
- }
1813
2129
  function validateDeployHttpPortText(value) {
1814
2130
  if (!value?.trim()) return;
1815
2131
  try {
@@ -1823,6 +2139,11 @@ function formatDeployDirectory(cwd) {
1823
2139
  const basename = path.basename(cwd);
1824
2140
  return basename ? `./${basename}` : ".";
1825
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
+ }
1826
2147
  async function readCurrentWorkspaceId(context) {
1827
2148
  const state = await context.stateStore.read();
1828
2149
  if (state.auth?.workspaceId) return state.auth.workspaceId;
@@ -1831,26 +2152,36 @@ async function readCurrentWorkspaceId(context) {
1831
2152
  function normalizeBuildType(requestedBuildType) {
1832
2153
  if (!requestedBuildType) return "auto";
1833
2154
  if (isPreviewBuildType(requestedBuildType)) return requestedBuildType;
1834
- 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");
1835
2156
  }
1836
2157
  function isPreviewBuildType(value) {
1837
- return PREVIEW_BUILD_TYPES.includes(value);
2158
+ return APP_BUILD_TYPES.includes(value);
1838
2159
  }
1839
2160
  function getBuildTypeExamples(commandName) {
1840
- return RESOLVED_PREVIEW_BUILD_TYPES.map((buildType) => {
2161
+ return RESOLVED_APP_BUILD_TYPES.map((buildType) => {
1841
2162
  return `prisma-cli app ${commandName} --build-type ${buildType}${buildType === "bun" ? " --entry server.ts" : ""}`;
1842
2163
  });
1843
2164
  }
1844
2165
  function assertSupportedEntrypoint(buildType, entrypoint, commandName) {
1845
- if (buildType !== "auto" && buildType !== "bun" && entrypoint) {
2166
+ if (buildType !== "auto" && !ENTRYPOINT_BUILD_TYPES.includes(buildType) && entrypoint) {
1846
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");
1847
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");
1848
2169
  }
1849
2170
  }
1850
- async function requireLocalBuildType(context, buildType, commandName) {
1851
- const resolvedBuildType = await resolveLocalBuildType(context.runtime.cwd, buildType, context.runtime.signal);
1852
- if (resolvedBuildType) return resolvedBuildType;
1853
- 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");
1854
2185
  }
1855
2186
  function parseLocalPort(requestedPort) {
1856
2187
  if (!requestedPort) return DEFAULT_LOCAL_DEV_PORT;
@@ -2067,14 +2398,12 @@ function isAutoBuildDetectionError(error) {
2067
2398
  return error instanceof Error && error.message.startsWith("Entrypoint is required.");
2068
2399
  }
2069
2400
  function formatBuildTypeName(buildType) {
2070
- switch (buildType) {
2071
- case "nextjs": return "Next.js";
2072
- case "nuxt": return "Nuxt";
2073
- case "astro": return "Astro";
2074
- case "tanstack-start": return "TanStack Start";
2075
- case "bun": return "Bun";
2076
- 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;
2077
2405
  }
2406
+ return buildType;
2078
2407
  }
2079
2408
  function removeFailedError(summary, error, nextSteps) {
2080
2409
  return new CliError({