@prisma/cli 3.0.0-beta.10 → 3.0.0-beta.12
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/dist/adapters/token-storage.js +2 -2
- package/dist/cli.js +7 -7
- package/dist/cli2.js +3 -3
- package/dist/commands/app/index.js +65 -52
- package/dist/controllers/app-env.js +6 -5
- package/dist/controllers/app.js +505 -184
- package/dist/controllers/branch.js +1 -1
- package/dist/controllers/database.js +1 -1
- package/dist/controllers/project.js +6 -6
- 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 +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 +80 -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/login.js +31 -24
- 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/resolution.js +2 -2
- package/dist/lib/project/setup.js +10 -7
- package/dist/output/patterns.js +1 -1
- package/dist/presenters/app.js +44 -39
- 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-runner.js +37 -27
- package/dist/shell/diagnostics-output.js +2 -8
- package/dist/shell/help.js +30 -20
- package/dist/shell/runtime.js +8 -4
- package/dist/shell/ui.js +19 -2
- package/package.json +17 -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,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, 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";
|
|
13
|
+
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
16
14
|
import { buildProjectSetupNextActions, inferTargetName, projectNotFoundError, projectResolutionErrorToCliError, resolveDurablePlatformMapping, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
|
|
17
15
|
import { bindProjectToDirectory, projectCreateFailedError, projectDirectoryBindingErrorToCliError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
|
|
18
|
-
import { promptForProjectSetupChoice } from "../lib/project/interactive-setup.js";
|
|
19
|
-
import { readLocalGitBranch } from "../lib/git/local-branch.js";
|
|
20
|
-
import { resolveOrCreatePreviewBuildSettings } from "../lib/app/preview-build-settings.js";
|
|
21
|
-
import { PREVIEW_BUILD_TYPES, RESOLVED_PREVIEW_BUILD_TYPES, executePreviewBuild } from "../lib/app/preview-build.js";
|
|
22
|
-
import { PREVIEW_DEFAULT_REGION } from "../lib/app/preview-interaction.js";
|
|
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,27 +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);
|
|
282
|
+
const setupResult = await bindProjectToDirectory(context, target.workspace, target.project, target.localPinAction, projectDir);
|
|
134
283
|
if (setupResult.isErr()) throw projectDirectoryBindingErrorToCliError(setupResult.error);
|
|
135
284
|
const projectSetup = setupResult.value;
|
|
136
285
|
localPinResult = projectSetup.localPin;
|
|
137
286
|
maybeRenderProjectLinked(context, projectSetup.directory, projectSetup.project.name, projectSetup.localPin.path);
|
|
138
287
|
}
|
|
139
288
|
let framework = await resolveDeployFramework(context, {
|
|
140
|
-
requestedFramework:
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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" }));
|
|
146
298
|
const selectedApp = await resolveDeployAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), {
|
|
147
299
|
explicitAppName: appName,
|
|
148
300
|
explicitAppId: envAppId,
|
|
301
|
+
configAppName: merged.configAppName,
|
|
149
302
|
firstDeploy: Boolean(target.localPinAction),
|
|
150
|
-
inferName: () => inferTargetName(
|
|
303
|
+
inferName: () => inferTargetName(appDir, context.runtime.signal)
|
|
151
304
|
});
|
|
152
305
|
await maybeRenderDeploySetupBlock(context, {
|
|
153
306
|
includeDirectory: !target.localPinAction,
|
|
307
|
+
appDir,
|
|
154
308
|
projectName: target.project.name,
|
|
155
309
|
branchName: target.branch.name,
|
|
156
310
|
appName: selectedApp.displayName
|
|
@@ -159,9 +313,9 @@ async function runAppDeploy(context, appName, options) {
|
|
|
159
313
|
framework,
|
|
160
314
|
runtime,
|
|
161
315
|
firstDeploy: selectedApp.firstDeploy,
|
|
162
|
-
explicitFramework: Boolean(
|
|
163
|
-
explicitEntrypoint: Boolean(
|
|
164
|
-
explicitHttpPort: Boolean(
|
|
316
|
+
explicitFramework: Boolean(merged.framework),
|
|
317
|
+
explicitEntrypoint: Boolean(merged.entrypoint),
|
|
318
|
+
explicitHttpPort: Boolean(merged.httpPort)
|
|
165
319
|
});
|
|
166
320
|
framework = customized.framework;
|
|
167
321
|
runtime = customized.runtime;
|
|
@@ -172,24 +326,33 @@ async function runAppDeploy(context, appName, options) {
|
|
|
172
326
|
prod: options?.prod === true
|
|
173
327
|
});
|
|
174
328
|
const buildType = framework.buildType;
|
|
175
|
-
assertSupportedEntrypoint(buildType,
|
|
176
|
-
const entrypoint = await resolveDeployEntrypoint(
|
|
177
|
-
|
|
178
|
-
|
|
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,
|
|
179
340
|
buildType,
|
|
180
341
|
signal: context.runtime.signal
|
|
181
342
|
});
|
|
343
|
+
const legacyWarnings = await handleLegacyBuildSettings(context, appDir, buildSettingsResolution.settings);
|
|
182
344
|
maybeRenderDeployBuildSettings(context, buildSettingsResolution);
|
|
183
345
|
const portMapping = parseDeployPortMapping(String(runtime.port));
|
|
184
346
|
const branchDatabaseSetup = await maybeSetupBranchDatabase(context, provider, projectId, toBranchDatabaseDeployBranch(target.branch), {
|
|
185
347
|
db: options?.db,
|
|
186
348
|
providedEnvVars: envVars,
|
|
187
|
-
firstProductionDeploy: productionDeployGate.firstProductionDeploy
|
|
349
|
+
firstProductionDeploy: productionDeployGate.firstProductionDeploy,
|
|
350
|
+
projectDir
|
|
188
351
|
});
|
|
189
|
-
const progressState =
|
|
352
|
+
const progressState = createDeployProgressState();
|
|
190
353
|
const deployStartedAt = Date.now();
|
|
191
354
|
const deployResult = await provider.deployApp({
|
|
192
|
-
cwd:
|
|
355
|
+
cwd: appDir,
|
|
193
356
|
projectId,
|
|
194
357
|
branchName: target.branch.name,
|
|
195
358
|
appId: selectedApp.appId,
|
|
@@ -202,7 +365,7 @@ async function runAppDeploy(context, appName, options) {
|
|
|
202
365
|
envVars,
|
|
203
366
|
interaction: void 0,
|
|
204
367
|
signal: context.runtime.signal,
|
|
205
|
-
progress:
|
|
368
|
+
progress: createDeployProgress(context.output.stderr, context.ui, !context.flags.json && !context.flags.quiet, progressState)
|
|
206
369
|
}).catch((error) => {
|
|
207
370
|
throw appDeployFailedError(error, progressState);
|
|
208
371
|
});
|
|
@@ -252,14 +415,18 @@ async function runAppDeploy(context, appName, options) {
|
|
|
252
415
|
durationMs: deployDurationMs,
|
|
253
416
|
localPin: localPinResult
|
|
254
417
|
},
|
|
255
|
-
warnings: branchDatabaseSetup.warnings,
|
|
418
|
+
warnings: [...legacyWarnings, ...branchDatabaseSetup.warnings],
|
|
256
419
|
nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${deployResult.deployment.id}`]
|
|
257
420
|
};
|
|
258
421
|
}
|
|
259
|
-
async function runAppListDeploys(context, appName, projectRef) {
|
|
422
|
+
async function runAppListDeploys(context, appName, projectRef, configTarget) {
|
|
260
423
|
ensurePreviewAppMode(context);
|
|
261
|
-
const
|
|
262
|
-
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);
|
|
263
430
|
if (!selectedApp) return {
|
|
264
431
|
command: "app.list-deploys",
|
|
265
432
|
result: {
|
|
@@ -295,10 +462,14 @@ async function runAppListDeploys(context, appName, projectRef) {
|
|
|
295
462
|
nextSteps: deployments.length > 0 ? [`prisma-cli app show-deploy ${deployments[0]?.id}`] : ["prisma-cli app deploy"]
|
|
296
463
|
};
|
|
297
464
|
}
|
|
298
|
-
async function runAppShow(context, appName, projectRef) {
|
|
465
|
+
async function runAppShow(context, appName, projectRef, configTarget) {
|
|
299
466
|
ensurePreviewAppMode(context);
|
|
300
|
-
const
|
|
301
|
-
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);
|
|
302
473
|
if (!selectedApp) return {
|
|
303
474
|
command: "app.show",
|
|
304
475
|
result: {
|
|
@@ -373,9 +544,14 @@ async function runAppShowDeploy(context, deploymentId) {
|
|
|
373
544
|
nextSteps: []
|
|
374
545
|
};
|
|
375
546
|
}
|
|
376
|
-
async function runAppOpen(context, appName, projectRef) {
|
|
547
|
+
async function runAppOpen(context, appName, projectRef, configTarget) {
|
|
377
548
|
ensurePreviewAppMode(context);
|
|
378
|
-
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
|
+
});
|
|
379
555
|
const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName);
|
|
380
556
|
if (!selectedApp) throw noDeploymentsError("No deployments available to open", "The resolved project does not have any deployed app yet.");
|
|
381
557
|
const deploymentsResult = await provider.listDeployments(selectedApp.id, { signal: context.runtime.signal }).catch((error) => {
|
|
@@ -539,15 +715,19 @@ async function runAppDomainWait(context, hostname, options) {
|
|
|
539
715
|
});
|
|
540
716
|
}
|
|
541
717
|
}
|
|
542
|
-
async function runAppLogs(context, appName, deploymentId, projectRef) {
|
|
718
|
+
async function runAppLogs(context, appName, deploymentId, projectRef, configTarget) {
|
|
543
719
|
ensurePreviewAppMode(context);
|
|
544
|
-
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
|
+
});
|
|
545
726
|
const target = deploymentId ? await resolveExplicitLogDeployment(context, provider, projectId, resolvedTarget.branch.name, appName, deploymentId) : await resolveLiveLogDeployment(context, provider, projectId, resolvedTarget.branch.name, appName);
|
|
546
727
|
if (!context.flags.json && !context.flags.quiet) {
|
|
547
728
|
const lines = renderCommandHeader(context.ui, {
|
|
548
729
|
commandLabel: "app logs",
|
|
549
730
|
description: "Streaming logs for the selected deployment.",
|
|
550
|
-
docsPath: "docs/product/command-spec.md#prisma-cli-app-logs---app-name---deployment-id",
|
|
551
731
|
rows: [
|
|
552
732
|
{
|
|
553
733
|
key: "project",
|
|
@@ -664,9 +844,14 @@ function writeLogRecord(context, record) {
|
|
|
664
844
|
if (!record.text.endsWith("\n")) context.output.stdout.write("\n");
|
|
665
845
|
}
|
|
666
846
|
}
|
|
667
|
-
async function runAppPromote(context, deploymentId, appName, projectRef) {
|
|
847
|
+
async function runAppPromote(context, deploymentId, appName, projectRef, configTarget) {
|
|
668
848
|
ensurePreviewAppMode(context);
|
|
669
|
-
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
|
+
});
|
|
670
855
|
const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName, "promote");
|
|
671
856
|
const deploymentsResult = await provider.listDeployments(selectedApp.id, { signal: context.runtime.signal }).catch((error) => {
|
|
672
857
|
throw deployFailedError("Failed to list app deployments", error, ["prisma-cli app list-deploys"]);
|
|
@@ -682,7 +867,7 @@ async function runAppPromote(context, deploymentId, appName, projectRef) {
|
|
|
682
867
|
appId: selectedApp.id,
|
|
683
868
|
deploymentId: targetDeployment.id,
|
|
684
869
|
signal: context.runtime.signal,
|
|
685
|
-
progress:
|
|
870
|
+
progress: createPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
|
|
686
871
|
}).catch((error) => {
|
|
687
872
|
throw deployFailedError("Failed to promote deployment", error, ["prisma-cli app list-deploys"]);
|
|
688
873
|
});
|
|
@@ -706,9 +891,14 @@ async function runAppPromote(context, deploymentId, appName, projectRef) {
|
|
|
706
891
|
nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${targetDeployment.id}`]
|
|
707
892
|
};
|
|
708
893
|
}
|
|
709
|
-
async function runAppRollback(context, appName, deploymentId, projectRef) {
|
|
894
|
+
async function runAppRollback(context, appName, deploymentId, projectRef, configTarget) {
|
|
710
895
|
ensurePreviewAppMode(context);
|
|
711
|
-
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
|
+
});
|
|
712
902
|
const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName, "rollback");
|
|
713
903
|
const deploymentsResult = await provider.listDeployments(selectedApp.id, { signal: context.runtime.signal }).catch((error) => {
|
|
714
904
|
throw deployFailedError("Failed to list app deployments", error, ["prisma-cli app list-deploys"]);
|
|
@@ -725,7 +915,7 @@ async function runAppRollback(context, appName, deploymentId, projectRef) {
|
|
|
725
915
|
appId: selectedApp.id,
|
|
726
916
|
deploymentId: targetDeployment.id,
|
|
727
917
|
signal: context.runtime.signal,
|
|
728
|
-
progress:
|
|
918
|
+
progress: createPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
|
|
729
919
|
}).catch((error) => {
|
|
730
920
|
throw deployFailedError("Failed to roll back deployment", error, ["prisma-cli app list-deploys"]);
|
|
731
921
|
});
|
|
@@ -750,9 +940,14 @@ async function runAppRollback(context, appName, deploymentId, projectRef) {
|
|
|
750
940
|
nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${targetDeployment.id}`]
|
|
751
941
|
};
|
|
752
942
|
}
|
|
753
|
-
async function runAppRemove(context, appName, projectRef) {
|
|
943
|
+
async function runAppRemove(context, appName, projectRef, configTarget) {
|
|
754
944
|
ensurePreviewAppMode(context);
|
|
755
|
-
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
|
+
});
|
|
756
951
|
const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName, "remove");
|
|
757
952
|
await confirmAppRemoval(context, selectedApp);
|
|
758
953
|
const removedApp = await provider.removeApp(selectedApp.id, { signal: context.runtime.signal }).catch((error) => {
|
|
@@ -776,6 +971,7 @@ async function runAppRemove(context, appName, projectRef) {
|
|
|
776
971
|
}
|
|
777
972
|
async function resolveAppDomainTarget(context, options, commandName = "app domain") {
|
|
778
973
|
ensurePreviewAppMode(context);
|
|
974
|
+
const compute = await resolveComputeManagementContext(context, options?.configTarget, commandName.replace(/^app /, ""));
|
|
779
975
|
const branch = resolveDomainBranch(options?.branchName);
|
|
780
976
|
if (toBranchKind(branch.name) !== "production") throw new CliError({
|
|
781
977
|
code: "BRANCH_NOT_DEPLOYABLE",
|
|
@@ -791,10 +987,11 @@ async function resolveAppDomainTarget(context, options, commandName = "app domai
|
|
|
791
987
|
const { provider, target, projectId } = await requireProviderAndProjectContext(context, options?.projectRef, {
|
|
792
988
|
branch,
|
|
793
989
|
commandName,
|
|
794
|
-
envProjectId
|
|
990
|
+
envProjectId,
|
|
991
|
+
projectDir: compute.projectDir
|
|
795
992
|
});
|
|
796
993
|
const selectedApp = await resolveDomainAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), {
|
|
797
|
-
explicitAppName: options?.appName,
|
|
994
|
+
explicitAppName: options?.appName ?? compute.configAppName,
|
|
798
995
|
explicitAppId: envAppId
|
|
799
996
|
});
|
|
800
997
|
await context.stateStore.setSelectedApp(projectId, {
|
|
@@ -910,7 +1107,7 @@ async function confirmDomainRemoval(context, target, hostname) {
|
|
|
910
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");
|
|
911
1108
|
}
|
|
912
1109
|
function domainCommandError(command, error, hostname) {
|
|
913
|
-
if (error instanceof
|
|
1110
|
+
if (error instanceof DomainApiError) {
|
|
914
1111
|
if (command === "add" && (error.status === 400 || error.status === 422) && isDomainDnsError(error)) return domainDnsNotConfiguredError(hostname, error);
|
|
915
1112
|
if (command === "add" && error.status === 400) return new CliError({
|
|
916
1113
|
code: "DOMAIN_HOSTNAME_INVALID",
|
|
@@ -1091,7 +1288,7 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
|
|
|
1091
1288
|
};
|
|
1092
1289
|
return {
|
|
1093
1290
|
appName: options.explicitAppName,
|
|
1094
|
-
region:
|
|
1291
|
+
region: DEFAULT_REGION,
|
|
1095
1292
|
displayName: options.explicitAppName,
|
|
1096
1293
|
annotation: "set by --app",
|
|
1097
1294
|
firstDeploy: options.firstDeploy
|
|
@@ -1107,6 +1304,25 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
|
|
|
1107
1304
|
firstDeploy: options.firstDeploy
|
|
1108
1305
|
};
|
|
1109
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
|
+
}
|
|
1110
1326
|
const inferredName = await options.inferName();
|
|
1111
1327
|
const matches = findAppsByName(apps, inferredName.name);
|
|
1112
1328
|
if (matches.length > 1) return resolveAmbiguousDeployApp(context, matches, inferredName.name, options.firstDeploy);
|
|
@@ -1119,7 +1335,7 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
|
|
|
1119
1335
|
};
|
|
1120
1336
|
return {
|
|
1121
1337
|
appName: inferredName.name,
|
|
1122
|
-
region:
|
|
1338
|
+
region: DEFAULT_REGION,
|
|
1123
1339
|
displayName: inferredName.name,
|
|
1124
1340
|
annotation: inferredName.source === "package-name" ? "created from package.json" : "created from directory name",
|
|
1125
1341
|
firstDeploy: options.firstDeploy
|
|
@@ -1151,7 +1367,7 @@ async function resolveAmbiguousDeployApp(context, matches, targetName, firstDepl
|
|
|
1151
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");
|
|
1152
1368
|
if (selected === createNew) return {
|
|
1153
1369
|
appName: targetName,
|
|
1154
|
-
region:
|
|
1370
|
+
region: DEFAULT_REGION,
|
|
1155
1371
|
displayName: targetName,
|
|
1156
1372
|
annotation: "created from package.json",
|
|
1157
1373
|
firstDeploy
|
|
@@ -1316,7 +1532,7 @@ async function requirePreviewAppProviderWithClient(context) {
|
|
|
1316
1532
|
if (!client) throw authRequiredError(["prisma-cli auth login"]);
|
|
1317
1533
|
return {
|
|
1318
1534
|
client,
|
|
1319
|
-
provider:
|
|
1535
|
+
provider: createAppProvider(client, createPreviewLogAuthOptions(context.runtime.env, context.runtime.signal))
|
|
1320
1536
|
};
|
|
1321
1537
|
}
|
|
1322
1538
|
function createPreviewLogAuthOptions(env, signal) {
|
|
@@ -1363,18 +1579,24 @@ async function resolveProjectContext(context, client, explicitProject, options)
|
|
|
1363
1579
|
workspace: authState.workspace,
|
|
1364
1580
|
explicitProject,
|
|
1365
1581
|
envProjectId: options?.envProjectId,
|
|
1582
|
+
projectDir: options?.projectDir,
|
|
1366
1583
|
listProjects: () => listRealWorkspaceProjects(client, authState.workspace, context.runtime.signal),
|
|
1367
1584
|
commandName: options?.commandName
|
|
1368
1585
|
});
|
|
1369
1586
|
if (resolvedResult.isErr()) throw projectResolutionErrorToCliError(resolvedResult.error);
|
|
1370
1587
|
const resolved = resolvedResult.value;
|
|
1371
|
-
const
|
|
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
|
+
});
|
|
1372
1594
|
return {
|
|
1373
1595
|
...resolved,
|
|
1374
|
-
branch: {
|
|
1596
|
+
branch: remoteBranch ?? {
|
|
1375
1597
|
id: null,
|
|
1376
|
-
name:
|
|
1377
|
-
kind: toBranchKind(
|
|
1598
|
+
name: requested.name,
|
|
1599
|
+
kind: toBranchKind(requested.name)
|
|
1378
1600
|
}
|
|
1379
1601
|
};
|
|
1380
1602
|
}
|
|
@@ -1559,22 +1781,130 @@ async function resolveDeployBranch(context, explicitBranchName) {
|
|
|
1559
1781
|
annotation: "default"
|
|
1560
1782
|
};
|
|
1561
1783
|
}
|
|
1784
|
+
async function resolveComputeTargetOrThrow(context, configTarget, commandName, options) {
|
|
1785
|
+
let config;
|
|
1786
|
+
if (options?.preloaded !== void 0) config = options.preloaded;
|
|
1787
|
+
else {
|
|
1788
|
+
const loaded = await loadComputeConfig$1(context.runtime.cwd, context.runtime.signal);
|
|
1789
|
+
if (loaded.isErr()) throw computeConfigErrorToCliError(loaded.error, commandName);
|
|
1790
|
+
config = loaded.value;
|
|
1791
|
+
}
|
|
1792
|
+
if (!config) {
|
|
1793
|
+
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");
|
|
1794
|
+
return {
|
|
1795
|
+
config: null,
|
|
1796
|
+
target: null
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1799
|
+
const requestedTarget = configTarget ?? inferComputeTargetFromCwd(config, context.runtime.cwd);
|
|
1800
|
+
const selected = selectComputeDeployTarget(config, requestedTarget);
|
|
1801
|
+
if (selected.isErr()) {
|
|
1802
|
+
if (options?.targetOptional && selected.error instanceof ComputeConfigTargetRequiredError) return {
|
|
1803
|
+
config,
|
|
1804
|
+
target: null
|
|
1805
|
+
};
|
|
1806
|
+
throw computeConfigErrorToCliError(selected.error, commandName);
|
|
1807
|
+
}
|
|
1808
|
+
return {
|
|
1809
|
+
config,
|
|
1810
|
+
target: selected.value
|
|
1811
|
+
};
|
|
1812
|
+
}
|
|
1813
|
+
/**
|
|
1814
|
+
* Compute-config context for app management commands: the project directory
|
|
1815
|
+
* (where `.prisma/local.json` lives) and the config-selected app name, which
|
|
1816
|
+
* ranks below `--app` but above the remembered app selection.
|
|
1817
|
+
*/
|
|
1818
|
+
async function resolveComputeManagementContext(context, configTarget, commandName) {
|
|
1819
|
+
const compute = await resolveComputeTargetOrThrow(context, configTarget, commandName, { targetOptional: true });
|
|
1820
|
+
return {
|
|
1821
|
+
projectDir: compute.config?.configDir ?? context.runtime.cwd,
|
|
1822
|
+
configAppName: compute.target?.name ?? compute.target?.key ?? void 0
|
|
1823
|
+
};
|
|
1824
|
+
}
|
|
1825
|
+
async function resolveComputeAppDir(context, compute) {
|
|
1826
|
+
if (!compute.config || !compute.target) return context.runtime.cwd;
|
|
1827
|
+
const appDir = computeTargetAppDir(compute.config, compute.target);
|
|
1828
|
+
if (!compute.target.root) return appDir;
|
|
1829
|
+
context.runtime.signal.throwIfAborted();
|
|
1830
|
+
try {
|
|
1831
|
+
await access(appDir);
|
|
1832
|
+
context.runtime.signal.throwIfAborted();
|
|
1833
|
+
} catch (error) {
|
|
1834
|
+
if (context.runtime.signal.aborted) throw error;
|
|
1835
|
+
throw new CliError({
|
|
1836
|
+
code: "COMPUTE_CONFIG_INVALID",
|
|
1837
|
+
domain: "app",
|
|
1838
|
+
summary: `App root "${compute.target.root}" does not exist`,
|
|
1839
|
+
why: `${compute.config.relativeConfigPath} points the selected app at "${compute.target.root}", but that directory does not exist.`,
|
|
1840
|
+
fix: `Fix the root path in ${compute.config.relativeConfigPath} or create the directory.`,
|
|
1841
|
+
where: appDir,
|
|
1842
|
+
meta: {
|
|
1843
|
+
appRoot: compute.target.root,
|
|
1844
|
+
appDir
|
|
1845
|
+
},
|
|
1846
|
+
exitCode: 2,
|
|
1847
|
+
nextSteps: ["prisma-cli app deploy"]
|
|
1848
|
+
});
|
|
1849
|
+
}
|
|
1850
|
+
return appDir;
|
|
1851
|
+
}
|
|
1852
|
+
/**
|
|
1853
|
+
* `prisma.app.json` is no longer read or written. A leftover file that
|
|
1854
|
+
* matches the effective settings only warns; one with custom values fails
|
|
1855
|
+
* with migration guidance so builds never silently change.
|
|
1856
|
+
*/
|
|
1857
|
+
async function handleLegacyBuildSettings(context, appDir, effective) {
|
|
1858
|
+
const legacy = await detectLegacyBuildSettings({
|
|
1859
|
+
appPath: appDir,
|
|
1860
|
+
effective,
|
|
1861
|
+
signal: context.runtime.signal
|
|
1862
|
+
});
|
|
1863
|
+
switch (legacy.kind) {
|
|
1864
|
+
case "absent": return [];
|
|
1865
|
+
case "matching": return [`${PRISMA_APP_CONFIG_FILENAME} is no longer used and matches the resolved build settings. Delete it.`];
|
|
1866
|
+
case "invalid": return [`${PRISMA_APP_CONFIG_FILENAME} is no longer used and could not be parsed. Delete it.`];
|
|
1867
|
+
case "custom": {
|
|
1868
|
+
const buildBlock = [
|
|
1869
|
+
"build: {",
|
|
1870
|
+
` command: ${legacy.buildCommand === null ? "null" : JSON.stringify(legacy.buildCommand)},`,
|
|
1871
|
+
` outputDirectory: ${JSON.stringify(legacy.outputDirectory)},`,
|
|
1872
|
+
"}"
|
|
1873
|
+
].join(" ");
|
|
1874
|
+
throw new CliError({
|
|
1875
|
+
code: "BUILD_SETTINGS_MIGRATION_REQUIRED",
|
|
1876
|
+
domain: "app",
|
|
1877
|
+
summary: `${PRISMA_APP_CONFIG_FILENAME} is no longer supported`,
|
|
1878
|
+
why: `${PRISMA_APP_CONFIG_FILENAME} contains custom build settings that differ from the resolved defaults, and the file is no longer read.`,
|
|
1879
|
+
fix: `Move the settings into prisma.compute.ts as \`${buildBlock}\` on this app, then delete ${PRISMA_APP_CONFIG_FILENAME}.`,
|
|
1880
|
+
where: legacy.configPath,
|
|
1881
|
+
meta: {
|
|
1882
|
+
configPath: legacy.configPath,
|
|
1883
|
+
buildCommand: legacy.buildCommand,
|
|
1884
|
+
outputDirectory: legacy.outputDirectory
|
|
1885
|
+
},
|
|
1886
|
+
exitCode: 2,
|
|
1887
|
+
nextSteps: ["prisma-cli app deploy"]
|
|
1888
|
+
});
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1562
1892
|
async function resolveDeployFramework(context, options) {
|
|
1563
|
-
if (options.requestedFramework) return frameworkFromUserFacingValue(options.requestedFramework, "set by --framework");
|
|
1893
|
+
if (options.requestedFramework) return frameworkFromUserFacingValue(options.requestedFramework, options.requestedFrameworkAnnotation ?? "set by --framework");
|
|
1564
1894
|
if (options.entrypoint) return {
|
|
1565
1895
|
key: "bun",
|
|
1566
1896
|
buildType: "bun",
|
|
1567
1897
|
displayName: "Bun",
|
|
1568
|
-
annotation: "set by --entry"
|
|
1898
|
+
annotation: options.entrypointAnnotation ?? "set by --entry"
|
|
1569
1899
|
};
|
|
1570
|
-
const detected = await detectDeployFramework(
|
|
1900
|
+
const detected = await detectDeployFramework(options.appDir, context.runtime.signal);
|
|
1571
1901
|
if (detected) return detected;
|
|
1572
|
-
throw frameworkNotDetectedError(
|
|
1902
|
+
throw frameworkNotDetectedError(options.appDir);
|
|
1573
1903
|
}
|
|
1574
|
-
function resolveDeployRuntime(requestedHttpPort, framework) {
|
|
1904
|
+
function resolveDeployRuntime(requestedHttpPort, requestedHttpPortAnnotation, framework) {
|
|
1575
1905
|
if (requestedHttpPort) return {
|
|
1576
1906
|
port: parseDeployHttpPort(requestedHttpPort),
|
|
1577
|
-
annotation: "set by --http-port"
|
|
1907
|
+
annotation: requestedHttpPortAnnotation ?? "set by --http-port"
|
|
1578
1908
|
};
|
|
1579
1909
|
return {
|
|
1580
1910
|
port: FRAMEWORK_DEFAULT_HTTP_PORT,
|
|
@@ -1589,8 +1919,8 @@ async function resolveDeployEntrypoint(cwd, framework, explicitEntrypoint, signa
|
|
|
1589
1919
|
if (explicitEntrypoint || framework.buildType !== "bun") return explicitEntrypoint;
|
|
1590
1920
|
const packageEntrypoint = readBunPackageEntrypoint(await readBunPackageJson(cwd, signal));
|
|
1591
1921
|
if (packageEntrypoint) return packageEntrypoint;
|
|
1592
|
-
|
|
1593
|
-
|
|
1922
|
+
const defaultEntrypoint = frameworkFromAlias(framework.key)?.defaultEntrypoint;
|
|
1923
|
+
if (!defaultEntrypoint) return;
|
|
1594
1924
|
signal.throwIfAborted();
|
|
1595
1925
|
try {
|
|
1596
1926
|
await access(path.join(cwd, defaultEntrypoint));
|
|
@@ -1604,34 +1934,22 @@ async function resolveDeployEntrypoint(cwd, framework, explicitEntrypoint, signa
|
|
|
1604
1934
|
}
|
|
1605
1935
|
async function detectDeployFramework(cwd, signal) {
|
|
1606
1936
|
const packageJson = await readBunPackageJson(cwd, signal);
|
|
1607
|
-
const
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
};
|
|
1620
|
-
if (hasAnyPackageDependency(packageJson, TANSTACK_START_PACKAGES)) return {
|
|
1621
|
-
key: "tanstack-start",
|
|
1622
|
-
buildType: "tanstack-start",
|
|
1623
|
-
displayName: "TanStack Start",
|
|
1624
|
-
annotation: "detected from package.json"
|
|
1625
|
-
};
|
|
1937
|
+
for (const framework of FRAMEWORKS) {
|
|
1938
|
+
if (framework.detectConfigFiles.length === 0 && framework.detectPackages.length === 0) continue;
|
|
1939
|
+
const configFile = await detectFrameworkConfigFile(cwd, framework, signal);
|
|
1940
|
+
if (!configFile.exists && !hasAnyPackageDependency(packageJson, framework.detectPackages)) continue;
|
|
1941
|
+
const annotation = framework.key === "nextjs" && configFile.standalone ? "standalone output detected" : configFile.exists ? `detected from ${path.basename(configFile.path)}` : "detected from package.json";
|
|
1942
|
+
return {
|
|
1943
|
+
key: framework.key,
|
|
1944
|
+
buildType: framework.buildType,
|
|
1945
|
+
displayName: framework.displayName,
|
|
1946
|
+
annotation
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1626
1949
|
return null;
|
|
1627
1950
|
}
|
|
1628
|
-
async function
|
|
1629
|
-
for (const candidate of
|
|
1630
|
-
"next.config.js",
|
|
1631
|
-
"next.config.mjs",
|
|
1632
|
-
"next.config.ts",
|
|
1633
|
-
"next.config.mts"
|
|
1634
|
-
]) {
|
|
1951
|
+
async function detectFrameworkConfigFile(cwd, framework, signal) {
|
|
1952
|
+
for (const candidate of framework.detectConfigFiles) {
|
|
1635
1953
|
const filePath = path.join(cwd, candidate);
|
|
1636
1954
|
signal.throwIfAborted();
|
|
1637
1955
|
try {
|
|
@@ -1641,7 +1959,8 @@ async function detectNextConfig(cwd, signal) {
|
|
|
1641
1959
|
});
|
|
1642
1960
|
return {
|
|
1643
1961
|
exists: true,
|
|
1644
|
-
standalone: /\boutput\s*:\s*["'`]standalone["'`]/.test(content)
|
|
1962
|
+
standalone: /\boutput\s*:\s*["'`]standalone["'`]/.test(content),
|
|
1963
|
+
path: filePath
|
|
1645
1964
|
};
|
|
1646
1965
|
} catch (error) {
|
|
1647
1966
|
if (signal.aborted) throw error;
|
|
@@ -1650,7 +1969,8 @@ async function detectNextConfig(cwd, signal) {
|
|
|
1650
1969
|
}
|
|
1651
1970
|
return {
|
|
1652
1971
|
exists: false,
|
|
1653
|
-
standalone: false
|
|
1972
|
+
standalone: false,
|
|
1973
|
+
path: null
|
|
1654
1974
|
};
|
|
1655
1975
|
}
|
|
1656
1976
|
function hasPackageDependency(packageJson, dependencyName) {
|
|
@@ -1663,48 +1983,41 @@ function hasDependency(dependencies, dependencyName) {
|
|
|
1663
1983
|
return Boolean(dependencies && typeof dependencies === "object" && dependencyName in dependencies);
|
|
1664
1984
|
}
|
|
1665
1985
|
function frameworkFromUserFacingValue(value, annotation) {
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
}
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
key: "tanstack-start",
|
|
1692
|
-
buildType: "tanstack-start",
|
|
1693
|
-
displayName: "TanStack Start",
|
|
1694
|
-
annotation
|
|
1695
|
-
};
|
|
1696
|
-
default: throw frameworkNotDetectedError(void 0, value);
|
|
1697
|
-
}
|
|
1986
|
+
const framework = frameworkFromAlias(value);
|
|
1987
|
+
if (!framework) throw frameworkNotDetectedError(void 0, value);
|
|
1988
|
+
return {
|
|
1989
|
+
key: framework.key,
|
|
1990
|
+
buildType: framework.buildType,
|
|
1991
|
+
displayName: framework.displayName,
|
|
1992
|
+
annotation
|
|
1993
|
+
};
|
|
1994
|
+
}
|
|
1995
|
+
/**
|
|
1996
|
+
* The nuxt and astro strategies build with their framework CLI and stage
|
|
1997
|
+
* fixed output, so a compute config `build` block has nothing to apply to.
|
|
1998
|
+
* Erroring beats silently ignoring committed settings.
|
|
1999
|
+
*/
|
|
2000
|
+
function assertConfigBackedBuildSettings(buildType) {
|
|
2001
|
+
if (isConfigBackedBuildType(buildType)) return;
|
|
2002
|
+
const displayName = FRAMEWORKS.find((framework) => framework.buildType === buildType)?.displayName ?? buildType;
|
|
2003
|
+
throw new CliError({
|
|
2004
|
+
code: "BUILD_SETTINGS_UNSUPPORTED",
|
|
2005
|
+
domain: "app",
|
|
2006
|
+
summary: `build settings are not supported for ${displayName} apps`,
|
|
2007
|
+
why: `${displayName} deploys run \`${buildType} build\` and package its output automatically.`,
|
|
2008
|
+
fix: "Remove the `build` block from prisma.compute.ts for this app.",
|
|
2009
|
+
exitCode: 2
|
|
2010
|
+
});
|
|
1698
2011
|
}
|
|
1699
2012
|
function frameworkNotDetectedError(cwd, requestedFramework) {
|
|
1700
|
-
const supported =
|
|
2013
|
+
const supported = FRAMEWORKS.map((framework) => framework.displayName).join(", ");
|
|
1701
2014
|
const directory = cwd ? ` in ${formatDeployDirectory(cwd)}` : "";
|
|
1702
2015
|
return new CliError({
|
|
1703
2016
|
code: "FRAMEWORK_NOT_DETECTED",
|
|
1704
2017
|
domain: "app",
|
|
1705
2018
|
summary: requestedFramework ? `Unsupported framework "${requestedFramework}"` : `Cannot detect a supported framework${directory}`,
|
|
1706
2019
|
why: `Supported Beta frameworks: ${supported}.`,
|
|
1707
|
-
fix:
|
|
2020
|
+
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.`,
|
|
1708
2021
|
exitCode: 2,
|
|
1709
2022
|
nextSteps: [
|
|
1710
2023
|
"prisma-cli app deploy --framework nextjs",
|
|
@@ -1717,14 +2030,14 @@ function frameworkNotDetectedError(cwd, requestedFramework) {
|
|
|
1717
2030
|
}
|
|
1718
2031
|
async function maybeRenderDeploySetupBlock(context, details) {
|
|
1719
2032
|
if (context.flags.json || context.flags.quiet) return;
|
|
1720
|
-
const directory =
|
|
2033
|
+
const directory = formatAppDirectoryLabel(context.runtime.cwd, details.appDir);
|
|
1721
2034
|
const prefix = details.includeDirectory ? `Deploying ${directory} to` : "Deploying to";
|
|
1722
2035
|
context.output.stderr.write(`${prefix} ${details.projectName} / ${details.branchName} / ${details.appName}\n\n`);
|
|
1723
2036
|
}
|
|
1724
2037
|
function maybeRenderDeployBuildSettings(context, resolution) {
|
|
1725
2038
|
if (context.flags.json || context.flags.quiet) return;
|
|
1726
2039
|
const settings = resolution.settings;
|
|
1727
|
-
const title = resolution.status === "
|
|
2040
|
+
const title = resolution.status === "config" ? `Using ${resolution.relativeConfigPath}` : "Build settings";
|
|
1728
2041
|
context.output.stderr.write(`${title}\n${renderDeployOutputRows(context.ui, [{
|
|
1729
2042
|
label: "Build Command",
|
|
1730
2043
|
value: settings.buildCommand ?? "none",
|
|
@@ -1761,9 +2074,9 @@ async function maybeCustomizeDeploySettings(context, options) {
|
|
|
1761
2074
|
input: context.runtime.stdin,
|
|
1762
2075
|
output: context.runtime.stderr,
|
|
1763
2076
|
message: `Framework (${options.framework.displayName})`,
|
|
1764
|
-
choices:
|
|
1765
|
-
label:
|
|
1766
|
-
value: framework
|
|
2077
|
+
choices: FRAMEWORKS.map((framework) => ({
|
|
2078
|
+
label: framework.displayName,
|
|
2079
|
+
value: framework.key
|
|
1767
2080
|
}))
|
|
1768
2081
|
}), "set by you");
|
|
1769
2082
|
const requestedPort = await textPrompt({
|
|
@@ -1806,14 +2119,6 @@ function maybeRenderDeploySettingsPreview(context, options) {
|
|
|
1806
2119
|
value: `HTTP ${options.runtime.port}`
|
|
1807
2120
|
}]).join("\n")}\n\n`);
|
|
1808
2121
|
}
|
|
1809
|
-
function frameworkDisplayName(framework) {
|
|
1810
|
-
switch (framework) {
|
|
1811
|
-
case "nextjs": return "Next.js";
|
|
1812
|
-
case "hono": return "Hono";
|
|
1813
|
-
case "tanstack-start": return "TanStack Start";
|
|
1814
|
-
case "bun": return "Bun";
|
|
1815
|
-
}
|
|
1816
|
-
}
|
|
1817
2122
|
function validateDeployHttpPortText(value) {
|
|
1818
2123
|
if (!value?.trim()) return;
|
|
1819
2124
|
try {
|
|
@@ -1827,6 +2132,11 @@ function formatDeployDirectory(cwd) {
|
|
|
1827
2132
|
const basename = path.basename(cwd);
|
|
1828
2133
|
return basename ? `./${basename}` : ".";
|
|
1829
2134
|
}
|
|
2135
|
+
function formatAppDirectoryLabel(cwd, appDir) {
|
|
2136
|
+
if (appDir === cwd) return formatDeployDirectory(cwd);
|
|
2137
|
+
const relative = path.relative(cwd, appDir).split(path.sep).join("/");
|
|
2138
|
+
return relative.startsWith("..") ? relative : `./${relative}`;
|
|
2139
|
+
}
|
|
1830
2140
|
async function readCurrentWorkspaceId(context) {
|
|
1831
2141
|
const state = await context.stateStore.read();
|
|
1832
2142
|
if (state.auth?.workspaceId) return state.auth.workspaceId;
|
|
@@ -1835,26 +2145,36 @@ async function readCurrentWorkspaceId(context) {
|
|
|
1835
2145
|
function normalizeBuildType(requestedBuildType) {
|
|
1836
2146
|
if (!requestedBuildType) return "auto";
|
|
1837
2147
|
if (isPreviewBuildType(requestedBuildType)) return requestedBuildType;
|
|
1838
|
-
throw usageError(`Unsupported build type "${requestedBuildType}"`, `Only ${
|
|
2148
|
+
throw usageError(`Unsupported build type "${requestedBuildType}"`, `Only ${APP_BUILD_TYPES.join(", ")} are supported in the current preview.`, "Pass a supported --build-type value.", getBuildTypeExamples("build"), "app");
|
|
1839
2149
|
}
|
|
1840
2150
|
function isPreviewBuildType(value) {
|
|
1841
|
-
return
|
|
2151
|
+
return APP_BUILD_TYPES.includes(value);
|
|
1842
2152
|
}
|
|
1843
2153
|
function getBuildTypeExamples(commandName) {
|
|
1844
|
-
return
|
|
2154
|
+
return RESOLVED_APP_BUILD_TYPES.map((buildType) => {
|
|
1845
2155
|
return `prisma-cli app ${commandName} --build-type ${buildType}${buildType === "bun" ? " --entry server.ts" : ""}`;
|
|
1846
2156
|
});
|
|
1847
2157
|
}
|
|
1848
2158
|
function assertSupportedEntrypoint(buildType, entrypoint, commandName) {
|
|
1849
|
-
if (buildType !== "auto" && buildType
|
|
2159
|
+
if (buildType !== "auto" && !ENTRYPOINT_BUILD_TYPES.includes(buildType) && entrypoint) {
|
|
1850
2160
|
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");
|
|
1851
2161
|
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");
|
|
1852
2162
|
}
|
|
1853
2163
|
}
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
2164
|
+
/**
|
|
2165
|
+
* Resolves the framework for `app run` with the same detection as deploy, so
|
|
2166
|
+
* a repo that deploys without flags also runs without flags. Local dev server
|
|
2167
|
+
* support is intentionally narrower than deploy build support: only Next.js
|
|
2168
|
+
* and Bun/Hono have dev servers in the current preview.
|
|
2169
|
+
*/
|
|
2170
|
+
async function resolveLocalRunFramework(context, options) {
|
|
2171
|
+
if (LOCAL_DEV_BUILD_TYPES.includes(options.requestedBuildType)) {
|
|
2172
|
+
if (options.configFramework && computeFrameworkToBuildType(options.configFramework) === options.requestedBuildType) return frameworkFromUserFacingValue(options.configFramework, `set by ${COMPUTE_CONFIG_FILENAME$1}`);
|
|
2173
|
+
return frameworkFromUserFacingValue(options.requestedBuildType, "set by --build-type");
|
|
2174
|
+
}
|
|
2175
|
+
const detected = await detectDeployFramework(options.appDir, context.runtime.signal);
|
|
2176
|
+
if (detected && LOCAL_DEV_BUILD_TYPES.includes(detected.buildType)) return detected;
|
|
2177
|
+
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");
|
|
1858
2178
|
}
|
|
1859
2179
|
function parseLocalPort(requestedPort) {
|
|
1860
2180
|
if (!requestedPort) return DEFAULT_LOCAL_DEV_PORT;
|
|
@@ -2075,6 +2395,7 @@ function formatBuildTypeName(buildType) {
|
|
|
2075
2395
|
case "nextjs": return "Next.js";
|
|
2076
2396
|
case "nuxt": return "Nuxt";
|
|
2077
2397
|
case "astro": return "Astro";
|
|
2398
|
+
case "nestjs": return "NestJS";
|
|
2078
2399
|
case "tanstack-start": return "TanStack Start";
|
|
2079
2400
|
case "bun": return "Bun";
|
|
2080
2401
|
case "auto": return "Auto";
|