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