@prisma/cli 3.0.0-beta.9 → 3.0.0-dev.102.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.
- package/README.md +0 -13
- package/dist/adapters/token-storage.js +311 -33
- package/dist/cli.js +7 -7
- package/dist/cli2.js +3 -3
- package/dist/commands/app/index.js +65 -52
- package/dist/commands/auth/index.js +55 -2
- package/dist/controllers/app-env.js +10 -7
- package/dist/controllers/app.js +539 -210
- package/dist/controllers/auth.js +211 -2
- package/dist/controllers/branch.js +5 -6
- package/dist/controllers/database.js +7 -5
- package/dist/controllers/project.js +33 -18
- package/dist/lib/app/app-interaction.js +5 -0
- package/dist/lib/app/{preview-provider.js → app-provider.js} +82 -78
- package/dist/lib/app/{preview-branch-database.js → branch-database-api.js} +1 -1
- package/dist/lib/app/branch-database-deploy.js +12 -60
- package/dist/lib/app/branch-database.js +1 -102
- package/dist/lib/app/build-settings.js +93 -0
- package/dist/lib/app/build.js +82 -0
- package/dist/lib/app/bun-project.js +2 -3
- package/dist/lib/app/compute-config.js +147 -0
- package/dist/lib/app/deploy-plan.js +58 -0
- package/dist/lib/app/{preview-progress.js → deploy-progress.js} +12 -12
- package/dist/lib/app/local-dev.js +3 -60
- package/dist/lib/app/production-deploy-gate.js +3 -3
- package/dist/lib/app/read-branch.js +30 -0
- package/dist/lib/auth/auth-ops.js +10 -4
- package/dist/lib/auth/guard.js +4 -1
- package/dist/lib/auth/login.js +32 -25
- package/dist/lib/diagnostics.js +1 -1
- package/dist/lib/fs/home-path.js +24 -0
- package/dist/lib/git/local-branch.js +15 -3
- package/dist/lib/project/local-pin.js +106 -26
- package/dist/lib/project/resolution.js +162 -71
- package/dist/lib/project/setup.js +65 -19
- package/dist/output/patterns.js +1 -1
- package/dist/presenters/app.js +44 -39
- package/dist/presenters/auth.js +98 -1
- package/dist/presenters/branch.js +1 -1
- package/dist/presenters/database.js +2 -2
- package/dist/presenters/project.js +3 -9
- package/dist/shell/command-meta.js +52 -2
- package/dist/shell/command-runner.js +39 -28
- package/dist/shell/diagnostics-output.js +2 -8
- package/dist/shell/errors.js +50 -1
- package/dist/shell/help.js +30 -20
- package/dist/shell/runtime.js +8 -4
- package/dist/shell/ui.js +19 -2
- package/dist/use-cases/auth.js +68 -1
- package/package.json +18 -4
- package/dist/lib/app/preview-build-settings.js +0 -385
- package/dist/lib/app/preview-build.js +0 -475
- package/dist/lib/app/preview-interaction.js +0 -5
package/dist/controllers/app.js
CHANGED
|
@@ -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 {
|
|
9
|
-
import {
|
|
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 {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
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 {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
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 {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
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,
|
|
50
|
-
const
|
|
51
|
-
|
|
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
|
|
54
|
-
appPath:
|
|
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 ${
|
|
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,
|
|
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
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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:
|
|
84
|
-
buildType:
|
|
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
|
|
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 (
|
|
269
|
+
if (merged.httpPort) parseDeployHttpPort(merged.httpPort.value);
|
|
121
270
|
assertSupportedEntrypointForRequestedDeployShape({
|
|
122
|
-
requestedFramework:
|
|
123
|
-
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
|
-
|
|
135
|
-
|
|
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:
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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(
|
|
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(
|
|
161
|
-
explicitEntrypoint: Boolean(
|
|
162
|
-
explicitHttpPort: Boolean(
|
|
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,
|
|
174
|
-
const entrypoint = await resolveDeployEntrypoint(
|
|
175
|
-
|
|
176
|
-
|
|
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 =
|
|
352
|
+
const progressState = createDeployProgressState();
|
|
188
353
|
const deployStartedAt = Date.now();
|
|
189
354
|
const deployResult = await provider.deployApp({
|
|
190
|
-
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:
|
|
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
|
|
260
|
-
const
|
|
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
|
|
299
|
-
const
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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
|
-
|
|
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:
|
|
1373
|
-
kind: toBranchKind(
|
|
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
|
|
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(
|
|
1904
|
+
const detected = await detectDeployFramework(options.appDir, context.runtime.signal);
|
|
1567
1905
|
if (detected) return detected;
|
|
1568
|
-
throw frameworkNotDetectedError(
|
|
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
|
-
|
|
1589
|
-
|
|
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
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
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
|
|
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
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 === "
|
|
1724
|
-
context.output.stderr.write(`${title}\n${renderDeployOutputRows(context.ui, [
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
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:
|
|
1761
|
-
label:
|
|
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 ${
|
|
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
|
|
2158
|
+
return APP_BUILD_TYPES.includes(value);
|
|
1838
2159
|
}
|
|
1839
2160
|
function getBuildTypeExamples(commandName) {
|
|
1840
|
-
return
|
|
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
|
|
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
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
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;
|
|
@@ -1923,7 +2254,7 @@ function appDeployFailedError(error, progress) {
|
|
|
1923
2254
|
}
|
|
1924
2255
|
if (!progress.buildStarted) return deployFailedError("App deploy failed", error, ["prisma-cli app deploy"]);
|
|
1925
2256
|
const phaseHeadline = progress.containerLive ? "The deployment started, but the app is not ready yet." : "Deploy failed after the build completed.";
|
|
1926
|
-
const recoveryLines = progress.
|
|
2257
|
+
const recoveryLines = progress.deploymentId ? ["See what happened", `prisma-cli app logs --deployment ${progress.deploymentId}`] : ["Fix", "Retry the command, or rerun with --trace for more detailed diagnostics."];
|
|
1927
2258
|
const urlLines = progress.deploymentUrl ? [
|
|
1928
2259
|
"",
|
|
1929
2260
|
"URL",
|
|
@@ -1949,11 +2280,11 @@ function appDeployFailedError(error, progress) {
|
|
|
1949
2280
|
domain: "app",
|
|
1950
2281
|
summary: phaseHeadline,
|
|
1951
2282
|
why,
|
|
1952
|
-
fix: progress.
|
|
2283
|
+
fix: progress.deploymentId ? `Inspect logs with prisma-cli app logs --deployment ${progress.deploymentId}.` : "Retry the command, or rerun with --trace for more detailed diagnostics.",
|
|
1953
2284
|
debug,
|
|
1954
2285
|
meta: {
|
|
1955
2286
|
phase: progress.containerLive ? "runtime_ready" : "deploy",
|
|
1956
|
-
deploymentId: progress.
|
|
2287
|
+
deploymentId: progress.deploymentId,
|
|
1957
2288
|
deploymentUrl: progress.deploymentUrl
|
|
1958
2289
|
},
|
|
1959
2290
|
humanLines,
|
|
@@ -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
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
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({
|