@prisma/cli 3.0.0-dev.97.1 → 8.0.0-rc.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 +3 -14
- package/dist/adapters/local-state.js +14 -3
- package/dist/{lib/auth → auth}/client.js +11 -3
- package/dist/auth/errors.js +50 -0
- package/dist/{lib/auth → auth}/guard.js +7 -6
- package/dist/{lib/auth → auth}/login.js +147 -6
- package/dist/{lib/auth/auth-ops.js → auth/operations.js} +63 -13
- package/dist/auth/recipient.js +42 -0
- package/dist/{adapters → auth}/token-storage.js +28 -7
- package/dist/auth/workspaces.js +171 -0
- package/dist/cli-command.js +14 -0
- package/dist/cli-name.js +12 -0
- package/dist/cli.js +1 -1
- package/dist/cli2.js +25 -8
- package/dist/command-arguments.js +12 -0
- package/dist/commands/agent/index.js +60 -0
- package/dist/commands/app/index.js +11 -6
- package/dist/commands/auth/index.js +2 -3
- package/dist/commands/bucket/index.js +123 -0
- package/dist/commands/build/index.js +29 -0
- package/dist/commands/database/index.js +92 -2
- package/dist/commands/feedback/index.js +20 -0
- package/dist/commands/git/index.js +1 -1
- package/dist/commands/init/index.js +33 -0
- package/dist/commands/project/index.js +54 -5
- package/dist/controllers/agent-setup.js +52 -0
- package/dist/controllers/agent.js +228 -0
- package/dist/controllers/app-env-api.js +3 -2
- package/dist/controllers/app-env-file.js +1 -1
- package/dist/controllers/app-env.js +5 -5
- package/dist/controllers/app.js +423 -358
- package/dist/controllers/auth.js +62 -254
- package/dist/controllers/branch.js +5 -16
- package/dist/controllers/bucket.js +184 -0
- package/dist/controllers/build.js +88 -0
- package/dist/controllers/database.js +230 -85
- package/dist/controllers/feedback.js +90 -0
- package/dist/controllers/init.js +814 -0
- package/dist/controllers/project.js +345 -184
- package/dist/controllers/select-prompt-port.js +1 -0
- package/dist/{shell/errors.js → errors.js} +8 -40
- package/dist/lib/agent/cli-command.js +20 -0
- package/dist/lib/agent/constants.js +12 -0
- package/dist/lib/agent/package-manager.js +99 -0
- package/dist/lib/agent/setup-status.js +83 -0
- package/dist/lib/app/app-provider.js +168 -95
- package/dist/lib/app/branch-database-deploy.js +70 -42
- package/dist/lib/app/branch-database.js +39 -20
- package/dist/lib/app/build-settings.js +8 -3
- package/dist/lib/app/build.js +16 -14
- package/dist/lib/app/bun-project.js +1 -1
- package/dist/lib/app/compute-config.js +29 -31
- package/dist/lib/app/deploy-plan.js +1 -0
- package/dist/lib/app/deploy-progress.js +7 -7
- package/dist/lib/app/env-config.js +1 -1
- package/dist/lib/app/env-file.js +2 -2
- package/dist/lib/app/env-vars.js +1 -1
- package/dist/lib/app/local-dev.js +1 -1
- package/dist/lib/app/production-deploy-gate.js +3 -2
- package/dist/lib/bucket/provider.js +139 -0
- package/dist/lib/database/provider.js +235 -17
- package/dist/lib/diagnostics.js +2 -1
- package/dist/lib/feedback.js +15 -0
- package/dist/lib/git/local-branch.js +1 -1
- package/dist/lib/project/interactive-setup.js +6 -5
- package/dist/lib/project/local-pin.js +1 -1
- package/dist/lib/project/provider.js +93 -0
- package/dist/lib/project/resolution.js +11 -8
- package/dist/lib/project/setup.js +9 -6
- package/dist/lib/version.js +3 -2
- package/dist/lib/workspace-id.js +18 -0
- package/dist/payload-B88Qvzxk-CrtTXSOe.js +34 -0
- package/dist/presenters/agent.js +74 -0
- package/dist/presenters/app.js +33 -7
- package/dist/presenters/auth.js +3 -2
- package/dist/presenters/bucket.js +174 -0
- package/dist/presenters/database.js +193 -5
- package/dist/presenters/feedback.js +26 -0
- package/dist/presenters/init.js +30 -0
- package/dist/presenters/project.js +98 -4
- package/dist/shell/cli-command.js +2 -0
- package/dist/shell/command-meta.js +303 -4
- package/dist/shell/command-runner.js +13 -6
- package/dist/shell/help.js +6 -5
- package/dist/shell/output.js +65 -3
- package/dist/shell/prompt.js +12 -5
- package/dist/shell/runtime.js +4 -21
- package/dist/state-dir.js +12 -0
- package/dist/{shell/update-check.js → update-check.js} +6 -5
- package/dist/v8/cli.js +14699 -0
- package/dist/v8/sender.js +192 -0
- package/package.json +21 -13
- package/dist/adapters/mock-api.js +0 -136
- package/dist/lib/app/app-interaction.js +0 -5
- package/dist/shell/command-arguments.js +0 -6
- package/dist/use-cases/auth.js +0 -145
- package/dist/use-cases/branch.js +0 -47
- package/dist/use-cases/create-cli-gateways.js +0 -68
- package/dist/use-cases/project.js +0 -30
package/dist/controllers/app.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { CliError, authRequiredError, featureUnavailableError, usageError, workspaceRequiredError } from "../shell/errors.js";
|
|
4
|
-
import { confirmPrompt, selectPrompt, textPrompt } from "../shell/prompt.js";
|
|
5
|
-
import { DEFAULT_REGION } from "../lib/app/app-interaction.js";
|
|
6
|
-
import { PRISMA_APP_CONFIG_FILENAME, detectLegacyBuildSettings, resolveConfiguredAppBuildSettings, resolveInferredAppBuildSettings } from "../lib/app/build-settings.js";
|
|
7
|
-
import { APP_BUILD_TYPES, RESOLVED_APP_BUILD_TYPES, executeAppBuild } from "../lib/app/build.js";
|
|
8
|
-
import { envVarNames, parseEnvInputs } from "../lib/app/env-vars.js";
|
|
9
|
-
import { DomainApiError, createAppProvider } from "../lib/app/app-provider.js";
|
|
1
|
+
import { formatCommandArgument } from "../command-arguments.js";
|
|
2
|
+
import { CliError, authRequiredError, featureUnavailableError, usageError, workspaceRequiredError } from "../errors.js";
|
|
10
3
|
import { renderCommandHeader } from "../shell/ui.js";
|
|
4
|
+
import { getApiBaseUrl } from "../auth/client.js";
|
|
5
|
+
import { sameWorkspaceId } from "../lib/workspace-id.js";
|
|
6
|
+
import { FileTokenStorage } from "../auth/token-storage.js";
|
|
7
|
+
import { authenticatedManagementApiClient } from "../auth/guard.js";
|
|
8
|
+
import { readAuthState } from "../auth/operations.js";
|
|
11
9
|
import { canPrompt } from "../shell/runtime.js";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
10
|
+
import { writeJsonEvent } from "../shell/output.js";
|
|
11
|
+
import { APP_BUILD_TYPES, APP_BUILD_TYPE_LABELS, RESOLVED_APP_BUILD_TYPES, executeAppBuild } from "../lib/app/build.js";
|
|
12
|
+
import { envVarNames, parseEnvInputs } from "../lib/app/env-vars.js";
|
|
13
|
+
import { DomainApiError, createAppProvider } from "../lib/app/app-provider.js";
|
|
14
|
+
import { confirmPrompt, selectPrompt, textPrompt } from "../shell/prompt.js";
|
|
16
15
|
import { maybeSetupBranchDatabase } from "../lib/app/branch-database-deploy.js";
|
|
16
|
+
import { PRISMA_APP_CONFIG_FILENAME, detectLegacyBuildSettings, resolveConfiguredAppBuildSettings, resolveInferredAppBuildSettings } from "../lib/app/build-settings.js";
|
|
17
17
|
import { readBunPackageEntrypoint, readBunPackageJson } from "../lib/app/bun-project.js";
|
|
18
|
-
import {
|
|
18
|
+
import { computeConfigErrorToCliError, computeFrameworkToBuildType, loadComputeConfig as loadComputeConfig$1, mergeComputeDeployInputs, mergeComputeLocalInputs } from "../lib/app/compute-config.js";
|
|
19
19
|
import { renderDeployOutputRows, renderDeploySettingsPreview } from "../lib/app/deploy-output.js";
|
|
20
20
|
import { describeDeployAllFailure, perAppInputsForDeployAll, planAppDeploy } from "../lib/app/deploy-plan.js";
|
|
21
21
|
import { createDeployProgress, createDeployProgressState, createPromoteProgress } from "../lib/app/deploy-progress.js";
|
|
@@ -23,26 +23,41 @@ import { formatDomainFailureFix } from "../lib/app/domain-guidance.js";
|
|
|
23
23
|
import { DEFAULT_LOCAL_DEV_PORT, runLocalApp } from "../lib/app/local-dev.js";
|
|
24
24
|
import { enforceProductionDeployGate } from "../lib/app/production-deploy-gate.js";
|
|
25
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
26
|
import { readLocalGitBranch } from "../lib/git/local-branch.js";
|
|
27
|
+
import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, readLocalResolutionPin } from "../lib/project/local-pin.js";
|
|
28
|
+
import { buildProjectSetupNextActions, inferTargetName, localProjectWorkspaceMismatchError, projectNotFoundError, projectResolutionErrorToCliError, resolveDurablePlatformMapping, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
|
|
29
|
+
import { bindProjectToDirectory, projectCreateFailedError, projectDirectoryBindingErrorToCliError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
|
|
29
30
|
import { promptForProjectSetupChoice } from "../lib/project/interactive-setup.js";
|
|
30
|
-
import {
|
|
31
|
+
import { maybePromptForAgentSetup } from "./agent-setup.js";
|
|
31
32
|
import { createSelectPromptPort } from "./select-prompt-port.js";
|
|
32
33
|
import { requireAuthenticatedAuthState } from "./auth.js";
|
|
33
34
|
import { listRealWorkspaceProjects } from "./project.js";
|
|
34
|
-
import { ENTRYPOINT_BUILD_TYPES, FRAMEWORKS, LOCAL_DEV_BUILD_TYPES, frameworkByKey, frameworkFromAlias, isConfigBackedBuildType } from "@prisma/compute-sdk/config";
|
|
35
|
-
import { access, readFile } from "node:fs/promises";
|
|
36
35
|
import path from "node:path";
|
|
37
|
-
import {
|
|
36
|
+
import { access } from "node:fs/promises";
|
|
37
|
+
import { COMPUTE_CONFIG_FILENAME, COMPUTE_REGIONS, ComputeConfigTargetRequiredError, ENTRYPOINT_BUILD_TYPES, FRAMEWORKS, LOCAL_DEV_BUILD_TYPES, computeTargetAppDir, frameworkByKey, frameworkFromAlias, inferComputeTargetFromCwd, isConfigBackedBuildType, selectComputeDeployTarget } from "@prisma/compute-sdk/config";
|
|
38
|
+
import { SERVICE_TOKEN_ENV_VAR } from "@prisma/cli-engine";
|
|
38
39
|
import open from "open";
|
|
40
|
+
import { detectComputeAppFromDirectory } from "@prisma/compute-sdk/config/directory";
|
|
41
|
+
import { matchError } from "better-result";
|
|
39
42
|
//#region src/controllers/app.ts
|
|
40
43
|
const FRAMEWORK_DEFAULT_HTTP_PORT = 3e3;
|
|
41
44
|
const PRISMA_PROJECT_ID_ENV_VAR = "PRISMA_PROJECT_ID";
|
|
42
45
|
const PRISMA_APP_ID_ENV_VAR = "PRISMA_APP_ID";
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
const COMPUTE_REGION_IDS = new Set(COMPUTE_REGIONS);
|
|
47
|
+
const APP_COMMAND_PREFIX = /^app /;
|
|
48
|
+
const TRAILING_DOT = /\.$/;
|
|
49
|
+
const DOMAIN_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
50
|
+
const CNAME_TO_PHRASE = /\bcname(?:s)?\s+to\b/;
|
|
51
|
+
const PRISMA_BUILD_HOSTNAME = /\b((?:[a-z0-9-]+\.)+prisma\.build)\b/i;
|
|
52
|
+
const WAIT_TIMEOUT_DURATION = /^(\d+)(ms|s|m|h)$/;
|
|
53
|
+
const WAIT_TIMEOUT_UNIT_MULTIPLIER_MS = {
|
|
54
|
+
ms: 1,
|
|
55
|
+
s: 1e3,
|
|
56
|
+
m: 60 * 1e3,
|
|
57
|
+
h: 3600 * 1e3
|
|
58
|
+
};
|
|
59
|
+
const NEXTJS_MENTION = /next\.?js/i;
|
|
60
|
+
const STANDALONE_OUTPUT_MENTION = /standalone output/i;
|
|
46
61
|
async function runAppBuild(context, options) {
|
|
47
62
|
const compute = await resolveComputeTargetOrThrow(context, options?.configTarget, "build");
|
|
48
63
|
const merged = mergeComputeLocalInputs({
|
|
@@ -102,7 +117,7 @@ async function runAppRun(context, options) {
|
|
|
102
117
|
},
|
|
103
118
|
target: compute.target
|
|
104
119
|
});
|
|
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
|
|
120
|
+
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} 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
121
|
const appDir = await resolveComputeAppDir(context, compute);
|
|
107
122
|
const buildType = normalizeBuildType(merged.buildType);
|
|
108
123
|
assertSupportedEntrypoint(buildType, merged.entrypoint, "run");
|
|
@@ -110,7 +125,8 @@ async function runAppRun(context, options) {
|
|
|
110
125
|
const framework = await resolveLocalRunFramework(context, {
|
|
111
126
|
requestedBuildType: buildType,
|
|
112
127
|
configFramework: compute.target?.framework ?? null,
|
|
113
|
-
appDir
|
|
128
|
+
appDir,
|
|
129
|
+
entrypoint: merged.entrypoint
|
|
114
130
|
});
|
|
115
131
|
const entrypoint = framework.buildType === "bun" ? await resolveDeployEntrypoint(appDir, framework, merged.entrypoint, context.runtime.signal) : merged.entrypoint;
|
|
116
132
|
let runResult;
|
|
@@ -141,7 +157,6 @@ async function runAppRun(context, options) {
|
|
|
141
157
|
};
|
|
142
158
|
}
|
|
143
159
|
async function runAppDeploy(context, appName, options) {
|
|
144
|
-
ensurePreviewAppMode(context);
|
|
145
160
|
const loaded = await loadComputeConfig$1(context.runtime.cwd, context.runtime.signal);
|
|
146
161
|
if (loaded.isErr()) throw computeConfigErrorToCliError(loaded.error, "deploy");
|
|
147
162
|
const config = loaded.value;
|
|
@@ -154,7 +169,7 @@ async function runAppDeploy(context, appName, options) {
|
|
|
154
169
|
return runSingleAppDeploy(context, appName, options, config);
|
|
155
170
|
}
|
|
156
171
|
async function runAppDeployAll(context, config, plannedTargets, appName, options) {
|
|
157
|
-
assertNoPerAppInputsForDeployAll(context,
|
|
172
|
+
assertNoPerAppInputsForDeployAll(context, plannedTargets, appName, options);
|
|
158
173
|
const deployments = [];
|
|
159
174
|
const warnings = [];
|
|
160
175
|
for (const planned of plannedTargets) {
|
|
@@ -172,7 +187,7 @@ async function runAppDeployAll(context, config, plannedTargets, appName, options
|
|
|
172
187
|
});
|
|
173
188
|
warnings.push(...single.warnings);
|
|
174
189
|
} catch (error) {
|
|
175
|
-
throw deployAllFailedError(error,
|
|
190
|
+
throw deployAllFailedError(error, plannedTargets, planned.index, deployments);
|
|
176
191
|
}
|
|
177
192
|
}
|
|
178
193
|
return {
|
|
@@ -182,12 +197,13 @@ async function runAppDeployAll(context, config, plannedTargets, appName, options
|
|
|
182
197
|
nextSteps: ["prisma-cli app list-deploys <app>"]
|
|
183
198
|
};
|
|
184
199
|
}
|
|
185
|
-
function assertNoPerAppInputsForDeployAll(context,
|
|
200
|
+
function assertNoPerAppInputsForDeployAll(context, plannedTargets, appName, options) {
|
|
186
201
|
const used = perAppInputsForDeployAll({
|
|
187
202
|
appName,
|
|
188
203
|
framework: options?.framework,
|
|
189
204
|
entrypoint: options?.entrypoint,
|
|
190
205
|
httpPort: options?.httpPort,
|
|
206
|
+
region: options?.region,
|
|
191
207
|
envAssignments: options?.envAssignments,
|
|
192
208
|
appIdEnvVar: {
|
|
193
209
|
name: PRISMA_APP_ID_ENV_VAR,
|
|
@@ -195,17 +211,17 @@ function assertNoPerAppInputsForDeployAll(context, config, appName, options) {
|
|
|
195
211
|
}
|
|
196
212
|
});
|
|
197
213
|
if (used.length === 0) return;
|
|
198
|
-
const
|
|
199
|
-
throw usageError(`Deploying all apps does not accept ${used.join(", ")}`, `Without a target, app deploy deploys every configured app (${
|
|
214
|
+
const targetKeys = plannedTargets.map((target) => target.targetKey);
|
|
215
|
+
throw usageError(`Deploying all apps does not accept ${used.join(", ")}`, `Without a target, app deploy deploys every configured app (${targetKeys.join(", ")}), 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.", targetKeys.map((target) => `prisma-cli app deploy ${target}`), "app");
|
|
200
216
|
}
|
|
201
217
|
function maybeRenderDeployAllTargetHeader(context, planned) {
|
|
202
218
|
if (context.flags.json || context.flags.quiet) return;
|
|
203
219
|
context.output.stderr.write(`${planned.index > 0 ? "\n" : ""}── ${planned.targetKey} (${planned.index + 1}/${planned.total}) ──\n\n`);
|
|
204
220
|
}
|
|
205
|
-
function deployAllFailedError(error,
|
|
221
|
+
function deployAllFailedError(error, plannedTargets, failedIndex, deployments) {
|
|
206
222
|
if (!(error instanceof CliError)) return error;
|
|
207
223
|
const failure = describeDeployAllFailure({
|
|
208
|
-
targetKeys:
|
|
224
|
+
targetKeys: plannedTargets.map((target) => target.targetKey),
|
|
209
225
|
failedIndex,
|
|
210
226
|
completed: deployments.map(({ target, result }) => ({
|
|
211
227
|
target,
|
|
@@ -255,18 +271,25 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
255
271
|
framework: options?.framework,
|
|
256
272
|
entrypoint: options?.entrypoint,
|
|
257
273
|
httpPort: options?.httpPort,
|
|
274
|
+
region: options?.region,
|
|
258
275
|
envInputs: options?.envAssignments
|
|
259
276
|
},
|
|
260
277
|
target: computeConfig.target,
|
|
261
|
-
configFilename: computeConfig.config?.relativeConfigPath ?? COMPUTE_CONFIG_FILENAME
|
|
278
|
+
configFilename: computeConfig.config?.relativeConfigPath ?? COMPUTE_CONFIG_FILENAME
|
|
262
279
|
});
|
|
263
280
|
const appDir = await resolveComputeAppDir(context, computeConfig);
|
|
264
281
|
const projectDir = computeConfig.config?.configDir ?? context.runtime.cwd;
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
282
|
+
const agentSetupWarnings = await maybePromptForAgentSetup(context, projectDir);
|
|
283
|
+
const localPin = await readDeployLocalPin({
|
|
284
|
+
projectDir,
|
|
285
|
+
signal: context.runtime.signal,
|
|
286
|
+
envProjectId,
|
|
287
|
+
projectRef: options?.projectRef,
|
|
288
|
+
createProjectName: options?.createProjectName
|
|
289
|
+
});
|
|
268
290
|
const branch = await resolveDeployBranch(context, options?.branchName);
|
|
269
291
|
if (merged.httpPort) parseDeployHttpPort(merged.httpPort.value);
|
|
292
|
+
const deployRegion = normalizeDeployRegionInput(merged.region);
|
|
270
293
|
assertSupportedEntrypointForRequestedDeployShape({
|
|
271
294
|
requestedFramework: merged.framework?.value,
|
|
272
295
|
entrypoint: merged.entrypoint?.value
|
|
@@ -274,17 +297,11 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
274
297
|
const { provider, target, projectId } = await requireProviderAndDeployProjectContext(context, options?.projectRef, {
|
|
275
298
|
branch,
|
|
276
299
|
createProjectName: options?.createProjectName,
|
|
300
|
+
createProjectRegion: deployRegion?.value,
|
|
277
301
|
envProjectId,
|
|
278
302
|
localPin
|
|
279
303
|
});
|
|
280
|
-
|
|
281
|
-
if (target.localPinAction) {
|
|
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);
|
|
287
|
-
}
|
|
304
|
+
const localPinResult = await bindDeployProjectDirectory(context, target, projectDir);
|
|
288
305
|
let framework = await resolveDeployFramework(context, {
|
|
289
306
|
requestedFramework: merged.framework?.value,
|
|
290
307
|
requestedFrameworkAnnotation: merged.framework?.annotation,
|
|
@@ -299,6 +316,7 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
299
316
|
explicitAppName: appName,
|
|
300
317
|
explicitAppId: envAppId,
|
|
301
318
|
configAppName: merged.configAppName,
|
|
319
|
+
configRegion: deployRegion,
|
|
302
320
|
firstDeploy: Boolean(target.localPinAction),
|
|
303
321
|
inferName: () => inferTargetName(appDir, context.runtime.signal)
|
|
304
322
|
});
|
|
@@ -319,7 +337,8 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
319
337
|
});
|
|
320
338
|
framework = customized.framework;
|
|
321
339
|
runtime = customized.runtime;
|
|
322
|
-
const
|
|
340
|
+
const noPromote = options?.noPromote === true;
|
|
341
|
+
const productionDeployGate = noPromote ? { firstProductionDeploy: false } : await enforceProductionDeployGate(context, provider, {
|
|
323
342
|
appId: selectedApp.appId,
|
|
324
343
|
appName: selectedApp.displayName,
|
|
325
344
|
branchKind: target.branch.kind,
|
|
@@ -328,15 +347,9 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
328
347
|
const buildType = framework.buildType;
|
|
329
348
|
assertSupportedEntrypoint(buildType, merged.entrypoint?.value, "deploy");
|
|
330
349
|
const entrypoint = await resolveDeployEntrypoint(appDir, framework, merged.entrypoint?.value, context.runtime.signal);
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
buildType,
|
|
335
|
-
configured: computeConfig.target.build,
|
|
336
|
-
configPath: computeConfig.config.configPath,
|
|
337
|
-
signal: context.runtime.signal
|
|
338
|
-
}) : await resolveInferredAppBuildSettings({
|
|
339
|
-
appPath: appDir,
|
|
350
|
+
const buildSettingsResolution = await resolveDeployBuildSettings({
|
|
351
|
+
computeConfig,
|
|
352
|
+
appDir,
|
|
340
353
|
buildType,
|
|
341
354
|
signal: context.runtime.signal
|
|
342
355
|
});
|
|
@@ -363,6 +376,7 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
363
376
|
buildSettings: buildSettingsResolution.settings,
|
|
364
377
|
portMapping,
|
|
365
378
|
envVars,
|
|
379
|
+
skipPromote: noPromote,
|
|
366
380
|
interaction: void 0,
|
|
367
381
|
signal: context.runtime.signal,
|
|
368
382
|
progress: createDeployProgress(context.output.stderr, context.ui, !context.flags.json && !context.flags.quiet, progressState)
|
|
@@ -370,11 +384,7 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
370
384
|
throw appDeployFailedError(error, progressState);
|
|
371
385
|
});
|
|
372
386
|
const deployDurationMs = Date.now() - deployStartedAt;
|
|
373
|
-
await context
|
|
374
|
-
id: deployResult.app.id,
|
|
375
|
-
name: deployResult.app.name
|
|
376
|
-
});
|
|
377
|
-
await context.stateStore.setKnownLiveDeployment(projectId, deployResult.app.id, deployResult.deployment.id);
|
|
387
|
+
await cacheDeployedApp(context, projectId, deployResult);
|
|
378
388
|
return {
|
|
379
389
|
command: "app.deploy",
|
|
380
390
|
result: {
|
|
@@ -388,9 +398,10 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
388
398
|
name: deployResult.app.name
|
|
389
399
|
},
|
|
390
400
|
deployment: deployResult.deployment,
|
|
401
|
+
promoted: deployResult.promoted,
|
|
391
402
|
deploySettings: {
|
|
392
403
|
config: {
|
|
393
|
-
path:
|
|
404
|
+
path: computeConfig.config?.relativeConfigPath ?? null,
|
|
394
405
|
status: buildSettingsResolution.status
|
|
395
406
|
},
|
|
396
407
|
buildCommand: {
|
|
@@ -407,20 +418,62 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
407
418
|
name: framework.displayName,
|
|
408
419
|
source: framework.annotation
|
|
409
420
|
},
|
|
410
|
-
entrypoint: entrypoint ?? null,
|
|
421
|
+
entrypoint: entrypoint ?? buildSettingsResolution.settings.entrypoint ?? null,
|
|
411
422
|
httpPort: runtime.port,
|
|
412
|
-
region: selectedApp.region ?? null,
|
|
423
|
+
region: deployResult.app.region ?? selectedApp.region ?? null,
|
|
424
|
+
regionSource: deployRegion?.annotation ?? null,
|
|
413
425
|
envVars: envVarNames(envVars)
|
|
414
426
|
},
|
|
415
427
|
durationMs: deployDurationMs,
|
|
416
428
|
localPin: localPinResult
|
|
417
429
|
},
|
|
418
|
-
warnings: [
|
|
419
|
-
|
|
430
|
+
warnings: [
|
|
431
|
+
...agentSetupWarnings,
|
|
432
|
+
...legacyWarnings,
|
|
433
|
+
...branchDatabaseSetup.warnings
|
|
434
|
+
],
|
|
435
|
+
nextSteps: deployResult.promoted ? ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${deployResult.deployment.id}`] : [`prisma-cli app promote ${deployResult.deployment.id}`, `prisma-cli app show-deploy ${deployResult.deployment.id}`]
|
|
420
436
|
};
|
|
421
437
|
}
|
|
438
|
+
async function readDeployLocalPin(options) {
|
|
439
|
+
if (options.envProjectId || options.projectRef || options.createProjectName) return { kind: "missing" };
|
|
440
|
+
const readResult = await readLocalResolutionPin(options.projectDir, options.signal);
|
|
441
|
+
if (readResult.isErr()) throw localPinReadErrorToDeployError(readResult.error);
|
|
442
|
+
return readResult.value;
|
|
443
|
+
}
|
|
444
|
+
async function bindDeployProjectDirectory(context, target, projectDir) {
|
|
445
|
+
if (!target.localPinAction) return;
|
|
446
|
+
const setupResult = await bindProjectToDirectory(context, target.workspace, target.project, target.localPinAction, projectDir);
|
|
447
|
+
if (setupResult.isErr()) throw projectDirectoryBindingErrorToCliError(setupResult.error);
|
|
448
|
+
const projectSetup = setupResult.value;
|
|
449
|
+
maybeRenderProjectLinked(context, projectSetup.directory, projectSetup.project.name, projectSetup.localPin.path);
|
|
450
|
+
return projectSetup.localPin;
|
|
451
|
+
}
|
|
452
|
+
async function cacheDeployedApp(context, projectId, deployResult) {
|
|
453
|
+
await context.stateStore.setSelectedApp(projectId, {
|
|
454
|
+
id: deployResult.app.id,
|
|
455
|
+
name: deployResult.app.name
|
|
456
|
+
});
|
|
457
|
+
const knownLiveDeploymentId = deployResult.promoted ? deployResult.deployment.id : deployResult.app.liveDeploymentId;
|
|
458
|
+
if (knownLiveDeploymentId) await context.stateStore.setKnownLiveDeployment(projectId, deployResult.app.id, knownLiveDeploymentId);
|
|
459
|
+
}
|
|
460
|
+
async function resolveDeployBuildSettings(options) {
|
|
461
|
+
const { computeConfig, appDir, buildType, signal } = options;
|
|
462
|
+
if (computeConfig.target?.build) assertConfigBackedBuildSettings(buildType);
|
|
463
|
+
if (computeConfig.config && computeConfig.target?.build && isConfigBackedBuildType(buildType)) return resolveConfiguredAppBuildSettings({
|
|
464
|
+
appPath: appDir,
|
|
465
|
+
buildType,
|
|
466
|
+
configured: computeConfig.target.build,
|
|
467
|
+
configPath: computeConfig.config.configPath,
|
|
468
|
+
signal
|
|
469
|
+
});
|
|
470
|
+
return resolveInferredAppBuildSettings({
|
|
471
|
+
appPath: appDir,
|
|
472
|
+
buildType,
|
|
473
|
+
signal
|
|
474
|
+
});
|
|
475
|
+
}
|
|
422
476
|
async function runAppListDeploys(context, appName, projectRef, configTarget) {
|
|
423
|
-
ensurePreviewAppMode(context);
|
|
424
477
|
const compute = await resolveComputeManagementContext(context, configTarget, "list-deploys");
|
|
425
478
|
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, {
|
|
426
479
|
commandName: "app list-deploys",
|
|
@@ -463,7 +516,6 @@ async function runAppListDeploys(context, appName, projectRef, configTarget) {
|
|
|
463
516
|
};
|
|
464
517
|
}
|
|
465
518
|
async function runAppShow(context, appName, projectRef, configTarget) {
|
|
466
|
-
ensurePreviewAppMode(context);
|
|
467
519
|
const compute = await resolveComputeManagementContext(context, configTarget, "show");
|
|
468
520
|
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, {
|
|
469
521
|
commandName: "app show",
|
|
@@ -511,7 +563,6 @@ async function runAppShow(context, appName, projectRef, configTarget) {
|
|
|
511
563
|
};
|
|
512
564
|
}
|
|
513
565
|
async function runAppShowDeploy(context, deploymentId) {
|
|
514
|
-
ensurePreviewAppMode(context);
|
|
515
566
|
const deployment = await (await requirePreviewAppProvider(context)).showDeployment(deploymentId, { signal: context.runtime.signal }).catch((error) => {
|
|
516
567
|
throw deployFailedError("Failed to show deployment", error, ["prisma-cli app list-deploys"]);
|
|
517
568
|
});
|
|
@@ -527,7 +578,7 @@ async function runAppShowDeploy(context, deploymentId) {
|
|
|
527
578
|
const workspaceId = deployment?.app ? await readCurrentWorkspaceId(context) : null;
|
|
528
579
|
const rememberedProject = workspaceId ? await context.stateStore.readRememberedProject(workspaceId) : null;
|
|
529
580
|
const knownLiveDeploymentId = deployment?.app && rememberedProject ? await context.stateStore.readKnownLiveDeployment(rememberedProject.id, deployment.app.id) : null;
|
|
530
|
-
const
|
|
581
|
+
const liveDeploymentId = deployment.app?.liveDeploymentId || knownLiveDeploymentId;
|
|
531
582
|
return {
|
|
532
583
|
command: "app.show-deploy",
|
|
533
584
|
result: {
|
|
@@ -537,17 +588,16 @@ async function runAppShowDeploy(context, deploymentId) {
|
|
|
537
588
|
} : null,
|
|
538
589
|
deployment: {
|
|
539
590
|
...deployment.deployment,
|
|
540
|
-
live:
|
|
591
|
+
live: liveDeploymentId ? deployment.deployment.id === liveDeploymentId : deployment.deployment.live
|
|
541
592
|
}
|
|
542
593
|
},
|
|
543
594
|
warnings: [],
|
|
544
595
|
nextSteps: []
|
|
545
596
|
};
|
|
546
597
|
}
|
|
547
|
-
async function runAppOpen(context,
|
|
548
|
-
ensurePreviewAppMode(context);
|
|
598
|
+
async function runAppOpen(context, appNameArg, projectRef, configTarget) {
|
|
549
599
|
const compute = await resolveComputeManagementContext(context, configTarget, "open");
|
|
550
|
-
appName =
|
|
600
|
+
const appName = appNameArg ?? compute.configAppName;
|
|
551
601
|
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, {
|
|
552
602
|
commandName: "app open",
|
|
553
603
|
projectDir: compute.projectDir
|
|
@@ -715,10 +765,9 @@ async function runAppDomainWait(context, hostname, options) {
|
|
|
715
765
|
});
|
|
716
766
|
}
|
|
717
767
|
}
|
|
718
|
-
async function runAppLogs(context,
|
|
719
|
-
ensurePreviewAppMode(context);
|
|
768
|
+
async function runAppLogs(context, appNameArg, deploymentId, projectRef, configTarget) {
|
|
720
769
|
const compute = await resolveComputeManagementContext(context, configTarget, "logs");
|
|
721
|
-
appName =
|
|
770
|
+
const appName = appNameArg ?? compute.configAppName;
|
|
722
771
|
const { provider, target: resolvedTarget, projectId } = await requireProviderAndProjectContext(context, projectRef, {
|
|
723
772
|
commandName: "app logs",
|
|
724
773
|
projectDir: compute.projectDir
|
|
@@ -844,10 +893,9 @@ function writeLogRecord(context, record) {
|
|
|
844
893
|
if (!record.text.endsWith("\n")) context.output.stdout.write("\n");
|
|
845
894
|
}
|
|
846
895
|
}
|
|
847
|
-
async function runAppPromote(context, deploymentId,
|
|
848
|
-
ensurePreviewAppMode(context);
|
|
896
|
+
async function runAppPromote(context, deploymentId, appNameArg, projectRef, configTarget) {
|
|
849
897
|
const compute = await resolveComputeManagementContext(context, configTarget, "promote");
|
|
850
|
-
appName =
|
|
898
|
+
const appName = appNameArg ?? compute.configAppName;
|
|
851
899
|
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, {
|
|
852
900
|
commandName: "app promote",
|
|
853
901
|
projectDir: compute.projectDir
|
|
@@ -891,10 +939,9 @@ async function runAppPromote(context, deploymentId, appName, projectRef, configT
|
|
|
891
939
|
nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${targetDeployment.id}`]
|
|
892
940
|
};
|
|
893
941
|
}
|
|
894
|
-
async function runAppRollback(context,
|
|
895
|
-
ensurePreviewAppMode(context);
|
|
942
|
+
async function runAppRollback(context, appNameArg, deploymentId, projectRef, configTarget) {
|
|
896
943
|
const compute = await resolveComputeManagementContext(context, configTarget, "rollback");
|
|
897
|
-
appName =
|
|
944
|
+
const appName = appNameArg ?? compute.configAppName;
|
|
898
945
|
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, {
|
|
899
946
|
commandName: "app rollback",
|
|
900
947
|
projectDir: compute.projectDir
|
|
@@ -940,11 +987,18 @@ async function runAppRollback(context, appName, deploymentId, projectRef, config
|
|
|
940
987
|
nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${targetDeployment.id}`]
|
|
941
988
|
};
|
|
942
989
|
}
|
|
943
|
-
|
|
944
|
-
|
|
990
|
+
/**
|
|
991
|
+
* Removes an app and every deployment it owns in the resolved branch.
|
|
992
|
+
*
|
|
993
|
+
* @param branchName Scopes the removal to this branch. When omitted the branch
|
|
994
|
+
* is inferred from the local Git branch, falling back to the production branch.
|
|
995
|
+
*/
|
|
996
|
+
async function runAppRemove(context, appNameArg, projectRef, configTarget, branchName) {
|
|
945
997
|
const compute = await resolveComputeManagementContext(context, configTarget, "remove");
|
|
946
|
-
appName =
|
|
998
|
+
const appName = appNameArg ?? compute.configAppName;
|
|
999
|
+
if (branchName !== void 0 && branchName.trim() === "") throw usageError("The --branch value cannot be empty", "app remove scopes the removal to the given branch; an empty --branch would silently fall back to the inferred (possibly production) branch.", "Pass a non-empty branch name, e.g. --branch <branch>, or omit --branch to use the inferred branch.", ["prisma-cli app remove --app <name> --branch <branch>"], "app");
|
|
947
1000
|
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, {
|
|
1001
|
+
branch: branchName !== void 0 ? await resolveDeployBranch(context, branchName) : void 0,
|
|
948
1002
|
commandName: "app remove",
|
|
949
1003
|
projectDir: compute.projectDir
|
|
950
1004
|
});
|
|
@@ -970,8 +1024,7 @@ async function runAppRemove(context, appName, projectRef, configTarget) {
|
|
|
970
1024
|
};
|
|
971
1025
|
}
|
|
972
1026
|
async function resolveAppDomainTarget(context, options, commandName = "app domain") {
|
|
973
|
-
|
|
974
|
-
const compute = await resolveComputeManagementContext(context, options?.configTarget, commandName.replace(/^app /, ""));
|
|
1027
|
+
const compute = await resolveComputeManagementContext(context, options?.configTarget, commandName.replace(APP_COMMAND_PREFIX, ""));
|
|
975
1028
|
const branch = resolveDomainBranch(options?.branchName);
|
|
976
1029
|
if (toBranchKind(branch.name) !== "production") throw new CliError({
|
|
977
1030
|
code: "BRANCH_NOT_DEPLOYABLE",
|
|
@@ -1036,7 +1089,7 @@ async function resolveDomainByHostname(provider, appId, hostname, command, signa
|
|
|
1036
1089
|
throw domainNotFoundError(hostname);
|
|
1037
1090
|
}
|
|
1038
1091
|
function normalizeDomainHostname(hostname) {
|
|
1039
|
-
const normalized = hostname.trim().replace(
|
|
1092
|
+
const normalized = hostname.trim().replace(TRAILING_DOT, "").toLowerCase();
|
|
1040
1093
|
if (!isValidDomainHostname(normalized)) throw new CliError({
|
|
1041
1094
|
code: "DOMAIN_HOSTNAME_INVALID",
|
|
1042
1095
|
domain: "app",
|
|
@@ -1053,10 +1106,10 @@ function isValidDomainHostname(hostname) {
|
|
|
1053
1106
|
if (hostname.includes("://") || hostname.includes("/") || hostname.includes(":") || hostname.startsWith("*.")) return false;
|
|
1054
1107
|
const labels = hostname.split(".");
|
|
1055
1108
|
if (labels.length < 2) return false;
|
|
1056
|
-
return labels.every((label) =>
|
|
1109
|
+
return labels.every((label) => DOMAIN_LABEL.test(label));
|
|
1057
1110
|
}
|
|
1058
1111
|
function sameDomainHostname(left, right) {
|
|
1059
|
-
return left.trim().replace(
|
|
1112
|
+
return left.trim().replace(TRAILING_DOT, "").toLowerCase() === right.trim().replace(TRAILING_DOT, "").toLowerCase();
|
|
1060
1113
|
}
|
|
1061
1114
|
function toAppDomainSummary(domain) {
|
|
1062
1115
|
return {
|
|
@@ -1064,7 +1117,7 @@ function toAppDomainSummary(domain) {
|
|
|
1064
1117
|
type: domain.type,
|
|
1065
1118
|
url: domain.url,
|
|
1066
1119
|
hostname: domain.hostname,
|
|
1067
|
-
|
|
1120
|
+
appId: domain.appId,
|
|
1068
1121
|
status: domain.status,
|
|
1069
1122
|
foundryStatus: domain.foundryStatus,
|
|
1070
1123
|
failureReason: domain.failureReason,
|
|
@@ -1102,55 +1155,15 @@ async function confirmDomainRemoval(context, target, hostname) {
|
|
|
1102
1155
|
if (!await confirmPrompt({
|
|
1103
1156
|
input: context.runtime.stdin,
|
|
1104
1157
|
output: context.output.stderr,
|
|
1158
|
+
signal: context.runtime.signal,
|
|
1105
1159
|
message: `Detach ${hostname} from App "${target.app.name}"?`,
|
|
1106
1160
|
initialValue: false
|
|
1107
1161
|
})) 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");
|
|
1108
1162
|
}
|
|
1109
1163
|
function domainCommandError(command, error, hostname) {
|
|
1110
1164
|
if (error instanceof DomainApiError) {
|
|
1111
|
-
|
|
1112
|
-
if (
|
|
1113
|
-
code: "DOMAIN_HOSTNAME_INVALID",
|
|
1114
|
-
domain: "app",
|
|
1115
|
-
summary: `Invalid custom domain "${hostname}"`,
|
|
1116
|
-
why: error.message,
|
|
1117
|
-
fix: "Pass a valid hostname like shop.acme.com and make sure DNS can be verified.",
|
|
1118
|
-
debug: formatDebugDetails(error),
|
|
1119
|
-
exitCode: 2,
|
|
1120
|
-
nextSteps: ["prisma-cli app domain add shop.acme.com"]
|
|
1121
|
-
});
|
|
1122
|
-
if (command === "add" && (error.status === 429 || isDomainQuotaError(error))) return new CliError({
|
|
1123
|
-
code: "DOMAIN_QUOTA_EXCEEDED",
|
|
1124
|
-
domain: "app",
|
|
1125
|
-
summary: "Custom domain quota exceeded",
|
|
1126
|
-
why: error.message,
|
|
1127
|
-
fix: "Remove an existing custom domain before adding another one.",
|
|
1128
|
-
debug: formatDebugDetails(error),
|
|
1129
|
-
exitCode: 1,
|
|
1130
|
-
nextSteps: ["prisma-cli app domain remove <hostname>"]
|
|
1131
|
-
});
|
|
1132
|
-
if (command === "add" && error.status === 409) return domainAlreadyRegisteredError(hostname, error);
|
|
1133
|
-
if (command === "add" && error.status === 422) return new CliError({
|
|
1134
|
-
code: "NO_DEPLOYMENTS",
|
|
1135
|
-
domain: "app",
|
|
1136
|
-
summary: "Custom domain requires a live production deployment",
|
|
1137
|
-
why: "The selected production app does not have a promoted version that can receive a custom domain.",
|
|
1138
|
-
fix: "Deploy the app to the production branch, then rerun the domain command.",
|
|
1139
|
-
debug: formatDebugDetails(error),
|
|
1140
|
-
exitCode: 1,
|
|
1141
|
-
nextSteps: ["prisma-cli app deploy --branch production", `prisma-cli app domain add ${hostname}`]
|
|
1142
|
-
});
|
|
1143
|
-
if ((command === "show" || command === "remove" || command === "retry" || command === "wait") && error.status === 404) return domainNotFoundError(hostname);
|
|
1144
|
-
if (command === "retry" && error.status === 409) return new CliError({
|
|
1145
|
-
code: "DOMAIN_RETRY_NOT_ELIGIBLE",
|
|
1146
|
-
domain: "app",
|
|
1147
|
-
summary: `Custom domain "${hostname}" is not eligible for retry`,
|
|
1148
|
-
why: error.message,
|
|
1149
|
-
fix: "Wait for the current verification or TLS step to finish, then rerun retry if the domain fails.",
|
|
1150
|
-
debug: formatDebugDetails(error),
|
|
1151
|
-
exitCode: 1,
|
|
1152
|
-
nextSteps: [`prisma-cli app domain show ${hostname}`]
|
|
1153
|
-
});
|
|
1165
|
+
const apiError = command === "add" ? domainAddApiError(hostname, error) : domainLookupApiError(command, hostname, error);
|
|
1166
|
+
if (apiError) return apiError;
|
|
1154
1167
|
}
|
|
1155
1168
|
return new CliError({
|
|
1156
1169
|
code: "DEPLOY_FAILED",
|
|
@@ -1163,6 +1176,55 @@ function domainCommandError(command, error, hostname) {
|
|
|
1163
1176
|
nextSteps: [`prisma-cli app domain show ${hostname}`]
|
|
1164
1177
|
});
|
|
1165
1178
|
}
|
|
1179
|
+
function domainAddApiError(hostname, error) {
|
|
1180
|
+
if ((error.status === 400 || error.status === 422) && isDomainDnsError(error)) return domainDnsNotConfiguredError(hostname, error);
|
|
1181
|
+
if (error.status === 400) return new CliError({
|
|
1182
|
+
code: "DOMAIN_HOSTNAME_INVALID",
|
|
1183
|
+
domain: "app",
|
|
1184
|
+
summary: `Invalid custom domain "${hostname}"`,
|
|
1185
|
+
why: error.message,
|
|
1186
|
+
fix: "Pass a valid hostname like shop.acme.com and make sure DNS can be verified.",
|
|
1187
|
+
debug: formatDebugDetails(error),
|
|
1188
|
+
exitCode: 2,
|
|
1189
|
+
nextSteps: ["prisma-cli app domain add shop.acme.com"]
|
|
1190
|
+
});
|
|
1191
|
+
if (error.status === 429 || isDomainQuotaError(error)) return new CliError({
|
|
1192
|
+
code: "DOMAIN_QUOTA_EXCEEDED",
|
|
1193
|
+
domain: "app",
|
|
1194
|
+
summary: "Custom domain quota exceeded",
|
|
1195
|
+
why: error.message,
|
|
1196
|
+
fix: "Remove an existing custom domain before adding another one.",
|
|
1197
|
+
debug: formatDebugDetails(error),
|
|
1198
|
+
exitCode: 1,
|
|
1199
|
+
nextSteps: ["prisma-cli app domain remove <hostname>"]
|
|
1200
|
+
});
|
|
1201
|
+
if (error.status === 409) return domainAlreadyRegisteredError(hostname, error);
|
|
1202
|
+
if (error.status === 422) return new CliError({
|
|
1203
|
+
code: "NO_DEPLOYMENTS",
|
|
1204
|
+
domain: "app",
|
|
1205
|
+
summary: "Custom domain requires a live production deployment",
|
|
1206
|
+
why: "The selected production app does not have a promoted version that can receive a custom domain.",
|
|
1207
|
+
fix: "Deploy the app to the production branch, then rerun the domain command.",
|
|
1208
|
+
debug: formatDebugDetails(error),
|
|
1209
|
+
exitCode: 1,
|
|
1210
|
+
nextSteps: ["prisma-cli app deploy --branch production", `prisma-cli app domain add ${hostname}`]
|
|
1211
|
+
});
|
|
1212
|
+
return null;
|
|
1213
|
+
}
|
|
1214
|
+
function domainLookupApiError(command, hostname, error) {
|
|
1215
|
+
if (error.status === 404) return domainNotFoundError(hostname);
|
|
1216
|
+
if (command === "retry" && error.status === 409) return new CliError({
|
|
1217
|
+
code: "DOMAIN_RETRY_NOT_ELIGIBLE",
|
|
1218
|
+
domain: "app",
|
|
1219
|
+
summary: `Custom domain "${hostname}" is not eligible for retry`,
|
|
1220
|
+
why: error.message,
|
|
1221
|
+
fix: "Wait for the current verification or TLS step to finish, then rerun retry if the domain fails.",
|
|
1222
|
+
debug: formatDebugDetails(error),
|
|
1223
|
+
exitCode: 1,
|
|
1224
|
+
nextSteps: [`prisma-cli app domain show ${hostname}`]
|
|
1225
|
+
});
|
|
1226
|
+
return null;
|
|
1227
|
+
}
|
|
1166
1228
|
function isDomainQuotaError(error) {
|
|
1167
1229
|
if (error.status !== 409) return false;
|
|
1168
1230
|
const text = `${error.message} ${error.hint ?? ""}`.toLowerCase();
|
|
@@ -1182,7 +1244,7 @@ function domainAlreadyRegisteredError(hostname, error) {
|
|
|
1182
1244
|
}
|
|
1183
1245
|
function isDomainDnsError(error) {
|
|
1184
1246
|
const text = `${error.message} ${error.hint ?? ""}`.toLowerCase();
|
|
1185
|
-
return text.includes("dns is not configured") || text.includes("dns verification failed") || text.includes("no cname") || text.includes("cname record") || text.includes("no a/aaaa") ||
|
|
1247
|
+
return text.includes("dns is not configured") || text.includes("dns verification failed") || text.includes("no cname") || text.includes("cname record") || text.includes("no a/aaaa") || CNAME_TO_PHRASE.test(text);
|
|
1186
1248
|
}
|
|
1187
1249
|
function domainDnsNotConfiguredError(hostname, error) {
|
|
1188
1250
|
const target = extractDomainDnsTarget(error);
|
|
@@ -1200,7 +1262,7 @@ function domainDnsNotConfiguredError(hostname, error) {
|
|
|
1200
1262
|
}
|
|
1201
1263
|
function extractDomainDnsTarget(error) {
|
|
1202
1264
|
const text = `${error.hint ?? ""} ${error.message}`;
|
|
1203
|
-
return
|
|
1265
|
+
return PRISMA_BUILD_HOSTNAME.exec(text)?.[1]?.toLowerCase() ?? null;
|
|
1204
1266
|
}
|
|
1205
1267
|
function domainNotFoundError(hostname) {
|
|
1206
1268
|
return new CliError({
|
|
@@ -1221,11 +1283,9 @@ function parseDomainWaitTimeout(value) {
|
|
|
1221
1283
|
if (!value) return 900 * 1e3;
|
|
1222
1284
|
const trimmed = value.trim().toLowerCase();
|
|
1223
1285
|
if (trimmed === "0") return 0;
|
|
1224
|
-
const match =
|
|
1286
|
+
const match = WAIT_TIMEOUT_DURATION.exec(trimmed);
|
|
1225
1287
|
if (!match) throw usageError(`Invalid timeout "${value}"`, "Timeout must be a duration such as 0, 30s, 15m, or 1h.", "Pass --timeout 15m, or --timeout 0 to poll once.", ["prisma-cli app domain wait shop.acme.com --timeout 15m"], "app");
|
|
1226
|
-
|
|
1227
|
-
const unit = match[2];
|
|
1228
|
-
return amount * (unit === "h" ? 3600 * 1e3 : unit === "m" ? 60 * 1e3 : unit === "s" ? 1e3 : 1);
|
|
1288
|
+
return Number.parseInt(match[1], 10) * (WAIT_TIMEOUT_UNIT_MULTIPLIER_MS[match[2]] ?? 1);
|
|
1229
1289
|
}
|
|
1230
1290
|
function readDomainWaitPollIntervalMs(context) {
|
|
1231
1291
|
const raw = context.runtime.env.PRISMA_CLI_DOMAIN_WAIT_POLL_MS;
|
|
@@ -1276,27 +1336,19 @@ async function sleep(milliseconds, signal) {
|
|
|
1276
1336
|
});
|
|
1277
1337
|
}
|
|
1278
1338
|
async function resolveDeployAppSelection(context, projectId, apps, options) {
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
};
|
|
1289
|
-
return {
|
|
1290
|
-
appName: options.explicitAppName,
|
|
1291
|
-
region: DEFAULT_REGION,
|
|
1292
|
-
displayName: options.explicitAppName,
|
|
1293
|
-
annotation: "set by --app",
|
|
1294
|
-
firstDeploy: options.firstDeploy
|
|
1295
|
-
};
|
|
1296
|
-
}
|
|
1339
|
+
const newAppRegion = deployNewAppRegion(options.configRegion);
|
|
1340
|
+
if (options.explicitAppName) return resolveDeployAppByName(context, apps, {
|
|
1341
|
+
name: options.explicitAppName,
|
|
1342
|
+
matchedAnnotation: "set by --app",
|
|
1343
|
+
newAnnotation: "set by --app",
|
|
1344
|
+
requestedRegion: options.configRegion,
|
|
1345
|
+
newAppRegion,
|
|
1346
|
+
firstDeploy: options.firstDeploy
|
|
1347
|
+
});
|
|
1297
1348
|
if (options.explicitAppId) {
|
|
1298
1349
|
const matched = apps.find((app) => app.id === options.explicitAppId);
|
|
1299
1350
|
if (!matched) throw usageError("Selected app does not exist in the resolved project", `The app "${options.explicitAppId}" from ${PRISMA_APP_ID_ENV_VAR} could not be found in resolved project "${projectId}".`, `Unset ${PRISMA_APP_ID_ENV_VAR}, pass --app <name>, or choose an app from prisma-cli app list-deploys.`, ["prisma-cli app list-deploys"], "app");
|
|
1351
|
+
assertDeployRegionMatchesExistingApp(matched, options.configRegion);
|
|
1300
1352
|
return {
|
|
1301
1353
|
appId: matched.id,
|
|
1302
1354
|
displayName: matched.name,
|
|
@@ -1306,42 +1358,52 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
|
|
|
1306
1358
|
}
|
|
1307
1359
|
if (options.configAppName) {
|
|
1308
1360
|
const configName = options.configAppName;
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
annotation: configName.annotation,
|
|
1361
|
+
return resolveDeployAppByName(context, apps, {
|
|
1362
|
+
name: configName.value,
|
|
1363
|
+
matchedAnnotation: configName.annotation,
|
|
1364
|
+
newAnnotation: configName.annotation,
|
|
1365
|
+
requestedRegion: options.configRegion,
|
|
1366
|
+
newAppRegion,
|
|
1316
1367
|
firstDeploy: options.firstDeploy
|
|
1317
|
-
};
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
const inferredName = await options.inferName();
|
|
1371
|
+
const newAnnotation = inferredName.source === "package-name" ? "created from package.json" : "created from directory name";
|
|
1372
|
+
return resolveDeployAppByName(context, apps, {
|
|
1373
|
+
name: inferredName.name,
|
|
1374
|
+
matchedAnnotation: "existing app on this branch",
|
|
1375
|
+
newAnnotation,
|
|
1376
|
+
requestedRegion: options.configRegion,
|
|
1377
|
+
newAppRegion,
|
|
1378
|
+
firstDeploy: options.firstDeploy
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
async function resolveDeployAppByName(context, apps, options) {
|
|
1382
|
+
const matches = findAppsByName(apps, options.name);
|
|
1383
|
+
if (matches.length > 1) return resolveAmbiguousDeployApp(context, matches, options.name, options.requestedRegion, options.newAppRegion, options.firstDeploy);
|
|
1384
|
+
const matched = matches[0];
|
|
1385
|
+
if (matched) {
|
|
1386
|
+
assertDeployRegionMatchesExistingApp(matched, options.requestedRegion);
|
|
1318
1387
|
return {
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
annotation: configName.annotation,
|
|
1388
|
+
appId: matched.id,
|
|
1389
|
+
displayName: matched.name,
|
|
1390
|
+
annotation: options.matchedAnnotation,
|
|
1323
1391
|
firstDeploy: options.firstDeploy
|
|
1324
1392
|
};
|
|
1325
1393
|
}
|
|
1326
|
-
const inferredName = await options.inferName();
|
|
1327
|
-
const matches = findAppsByName(apps, inferredName.name);
|
|
1328
|
-
if (matches.length > 1) return resolveAmbiguousDeployApp(context, matches, inferredName.name, options.firstDeploy);
|
|
1329
|
-
const matched = matches[0];
|
|
1330
|
-
if (matched) return {
|
|
1331
|
-
appId: matched.id,
|
|
1332
|
-
displayName: matched.name,
|
|
1333
|
-
annotation: "existing app on this branch",
|
|
1334
|
-
firstDeploy: options.firstDeploy
|
|
1335
|
-
};
|
|
1336
1394
|
return {
|
|
1337
|
-
appName:
|
|
1338
|
-
region:
|
|
1339
|
-
displayName:
|
|
1340
|
-
annotation:
|
|
1395
|
+
appName: options.name,
|
|
1396
|
+
region: options.newAppRegion,
|
|
1397
|
+
displayName: options.name,
|
|
1398
|
+
annotation: options.newAnnotation,
|
|
1341
1399
|
firstDeploy: options.firstDeploy
|
|
1342
1400
|
};
|
|
1343
1401
|
}
|
|
1344
|
-
|
|
1402
|
+
function assertDeployRegionMatchesExistingApp(app, requestedRegion) {
|
|
1403
|
+
if (requestedRegion?.annotation !== "set by --region" || !app.region || app.region === requestedRegion.value) return;
|
|
1404
|
+
throw usageError("App already exists in another region", `The selected app "${app.name}" is in region "${app.region}", but --region requested "${requestedRegion.value}".`, "Remove --region to deploy the existing app, or pass --app <new-name> to create a new app in that region.", [`prisma-cli app deploy --app ${formatCommandArgument(app.name)}`, `prisma-cli app deploy --app <new-name> --region ${formatCommandArgument(requestedRegion.value)}`], "app");
|
|
1405
|
+
}
|
|
1406
|
+
async function resolveAmbiguousDeployApp(context, matches, targetName, requestedRegion, newAppRegion, firstDeploy) {
|
|
1345
1407
|
if (canPrompt(context)) {
|
|
1346
1408
|
const createNew = "__create_new_app__";
|
|
1347
1409
|
const cancel = "__cancel__";
|
|
@@ -1367,11 +1429,12 @@ async function resolveAmbiguousDeployApp(context, matches, targetName, firstDepl
|
|
|
1367
1429
|
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");
|
|
1368
1430
|
if (selected === createNew) return {
|
|
1369
1431
|
appName: targetName,
|
|
1370
|
-
region:
|
|
1432
|
+
region: newAppRegion,
|
|
1371
1433
|
displayName: targetName,
|
|
1372
1434
|
annotation: "created from package.json",
|
|
1373
1435
|
firstDeploy
|
|
1374
1436
|
};
|
|
1437
|
+
assertDeployRegionMatchesExistingApp(selected, requestedRegion);
|
|
1375
1438
|
return {
|
|
1376
1439
|
appId: selected.id,
|
|
1377
1440
|
displayName: selected.name,
|
|
@@ -1393,6 +1456,9 @@ async function resolveAmbiguousDeployApp(context, matches, targetName, firstDepl
|
|
|
1393
1456
|
nextSteps: ["prisma-cli app deploy --app <name>"]
|
|
1394
1457
|
});
|
|
1395
1458
|
}
|
|
1459
|
+
function deployNewAppRegion(configRegion) {
|
|
1460
|
+
return configRegion?.value;
|
|
1461
|
+
}
|
|
1396
1462
|
async function resolveExistingAppSelection(context, projectId, apps, explicitAppName) {
|
|
1397
1463
|
if (explicitAppName) {
|
|
1398
1464
|
const matched = findAppByName(apps, explicitAppName);
|
|
@@ -1435,6 +1501,7 @@ async function confirmAppRemoval(context, app) {
|
|
|
1435
1501
|
await textPrompt({
|
|
1436
1502
|
input: context.runtime.stdin,
|
|
1437
1503
|
output: context.output.stderr,
|
|
1504
|
+
signal: context.runtime.signal,
|
|
1438
1505
|
message: `Type ${app.name} to confirm app removal`,
|
|
1439
1506
|
placeholder: app.name,
|
|
1440
1507
|
validate: (value) => value === app.name ? void 0 : `Type "${app.name}" to confirm removal.`
|
|
@@ -1467,13 +1534,21 @@ function requireDeploymentForApp(deployments, deploymentId, appName) {
|
|
|
1467
1534
|
nextSteps: ["prisma-cli app list-deploys"]
|
|
1468
1535
|
});
|
|
1469
1536
|
}
|
|
1537
|
+
/**
|
|
1538
|
+
* Resolves the app's live deployment from the app pointer, the provider's live
|
|
1539
|
+
* flag, then locally cached state.
|
|
1540
|
+
*
|
|
1541
|
+
* @returns the live deployment id, or null when no authoritative signal exists.
|
|
1542
|
+
* Callers must treat null as "not known to be live" rather than assuming the
|
|
1543
|
+
* newest deployment is live.
|
|
1544
|
+
*/
|
|
1470
1545
|
async function resolveCurrentLiveDeploymentId(context, projectId, app, deployments) {
|
|
1471
1546
|
if (app.liveDeploymentId && deployments.some((deployment) => deployment.id === app.liveDeploymentId)) return app.liveDeploymentId;
|
|
1472
1547
|
const providerLiveDeployment = deployments.find((deployment) => deployment.live === true);
|
|
1473
1548
|
if (providerLiveDeployment) return providerLiveDeployment.id;
|
|
1474
1549
|
const knownLiveDeploymentId = await context.stateStore.readKnownLiveDeployment(projectId, app.id);
|
|
1475
1550
|
if (knownLiveDeploymentId && deployments.some((deployment) => deployment.id === knownLiveDeploymentId)) return knownLiveDeploymentId;
|
|
1476
|
-
return
|
|
1551
|
+
return null;
|
|
1477
1552
|
}
|
|
1478
1553
|
function buildAppShowNextSteps(liveUrl, liveDeployment, deployments) {
|
|
1479
1554
|
const nextSteps = [];
|
|
@@ -1528,7 +1603,7 @@ async function requirePreviewAppProvider(context) {
|
|
|
1528
1603
|
return provider;
|
|
1529
1604
|
}
|
|
1530
1605
|
async function requirePreviewAppProviderWithClient(context) {
|
|
1531
|
-
const client = await
|
|
1606
|
+
const client = await authenticatedManagementApiClient(context.runtime.env, context.runtime.signal);
|
|
1532
1607
|
if (!client) throw authRequiredError(["prisma-cli auth login"]);
|
|
1533
1608
|
return {
|
|
1534
1609
|
client,
|
|
@@ -1572,15 +1647,15 @@ async function requireProviderAndDeployProjectContext(context, explicitProject,
|
|
|
1572
1647
|
};
|
|
1573
1648
|
}
|
|
1574
1649
|
async function resolveProjectContext(context, client, explicitProject, options) {
|
|
1575
|
-
const
|
|
1576
|
-
if (!
|
|
1650
|
+
const workspace = (await requireAuthenticatedAuthState(context)).workspace;
|
|
1651
|
+
if (!workspace) throw workspaceRequiredError();
|
|
1577
1652
|
const resolvedResult = await resolveProjectTarget({
|
|
1578
1653
|
context,
|
|
1579
|
-
workspace
|
|
1654
|
+
workspace,
|
|
1580
1655
|
explicitProject,
|
|
1581
1656
|
envProjectId: options?.envProjectId,
|
|
1582
1657
|
projectDir: options?.projectDir,
|
|
1583
|
-
listProjects: () => listRealWorkspaceProjects(client,
|
|
1658
|
+
listProjects: () => listRealWorkspaceProjects(client, context.runtime.signal),
|
|
1584
1659
|
commandName: options?.commandName
|
|
1585
1660
|
});
|
|
1586
1661
|
if (resolvedResult.isErr()) throw projectResolutionErrorToCliError(resolvedResult.error);
|
|
@@ -1604,7 +1679,7 @@ async function resolveDeployProjectContext(context, client, provider, explicitPr
|
|
|
1604
1679
|
const workspace = (await requireAuthenticatedAuthState(context)).workspace;
|
|
1605
1680
|
if (!workspace) throw workspaceRequiredError();
|
|
1606
1681
|
const branch = options.branch ?? await resolveDeployBranch(context, void 0);
|
|
1607
|
-
const projects = await listRealWorkspaceProjects(client,
|
|
1682
|
+
const projects = await listRealWorkspaceProjects(client, context.runtime.signal);
|
|
1608
1683
|
if (explicitProject) return withRemoteDeployBranch(provider, {
|
|
1609
1684
|
workspace,
|
|
1610
1685
|
project: toProjectSummary(resolveProjectForSetup(explicitProject, projects, workspace)),
|
|
@@ -1615,54 +1690,12 @@ async function resolveDeployProjectContext(context, client, provider, explicitPr
|
|
|
1615
1690
|
},
|
|
1616
1691
|
localPinAction: "linked"
|
|
1617
1692
|
}, branch, context.runtime.signal);
|
|
1618
|
-
if (options.createProjectName)
|
|
1619
|
-
|
|
1620
|
-
if (!projectName) throw projectSetupNameRequiredError("app deploy --create-project");
|
|
1621
|
-
return withRemoteDeployBranch(provider, {
|
|
1622
|
-
workspace,
|
|
1623
|
-
project: toProjectSummary(await createProjectForDeploySetup(provider, projectName, workspace, context.runtime.signal)),
|
|
1624
|
-
resolution: {
|
|
1625
|
-
projectSource: "created",
|
|
1626
|
-
targetName: projectName,
|
|
1627
|
-
targetNameSource: "explicit"
|
|
1628
|
-
},
|
|
1629
|
-
localPinAction: "created"
|
|
1630
|
-
}, branch, context.runtime.signal);
|
|
1631
|
-
}
|
|
1632
|
-
if (options.envProjectId) {
|
|
1633
|
-
const project = projects.find((candidate) => candidate.id === options.envProjectId);
|
|
1634
|
-
if (!project) throw projectNotFoundError(options.envProjectId, workspace);
|
|
1635
|
-
return withRemoteDeployBranch(provider, {
|
|
1636
|
-
workspace,
|
|
1637
|
-
project: toProjectSummary(project),
|
|
1638
|
-
resolution: {
|
|
1639
|
-
projectSource: "env",
|
|
1640
|
-
targetName: options.envProjectId,
|
|
1641
|
-
targetNameSource: "env"
|
|
1642
|
-
}
|
|
1643
|
-
}, branch, context.runtime.signal);
|
|
1644
|
-
}
|
|
1693
|
+
if (options.createProjectName) return withRemoteDeployBranch(provider, await resolveCreatedDeployProject(provider, options.createProjectName, workspace, context.runtime.signal, options.createProjectRegion), branch, context.runtime.signal);
|
|
1694
|
+
if (options.envProjectId) return withRemoteDeployBranch(provider, resolveEnvDeployProject(options.envProjectId, projects, workspace), branch, context.runtime.signal);
|
|
1645
1695
|
const localPin = options.localPin;
|
|
1646
|
-
if (localPin.kind === "present")
|
|
1647
|
-
if (localPin.pin.workspaceId !== workspace.id) throw localProjectWorkspaceMismatchError({
|
|
1648
|
-
pinnedWorkspaceId: localPin.pin.workspaceId,
|
|
1649
|
-
pinnedProjectId: localPin.pin.projectId,
|
|
1650
|
-
activeWorkspace: workspace
|
|
1651
|
-
});
|
|
1652
|
-
const project = projects.find((candidate) => candidate.id === localPin.pin.projectId);
|
|
1653
|
-
if (!project) throw localResolutionPinStaleError();
|
|
1654
|
-
return withRemoteDeployBranch(provider, {
|
|
1655
|
-
workspace,
|
|
1656
|
-
project: toProjectSummary(project),
|
|
1657
|
-
resolution: {
|
|
1658
|
-
projectSource: "local-pin",
|
|
1659
|
-
targetName: project.name,
|
|
1660
|
-
targetNameSource: "local-pin"
|
|
1661
|
-
}
|
|
1662
|
-
}, branch, context.runtime.signal);
|
|
1663
|
-
}
|
|
1696
|
+
if (localPin.kind === "present") return withRemoteDeployBranch(provider, resolveLocalPinDeployProject(localPin.pin, projects, workspace), branch, context.runtime.signal);
|
|
1664
1697
|
const platformMapping = await resolveDurablePlatformMapping();
|
|
1665
|
-
if (platformMapping && platformMapping.workspace.id
|
|
1698
|
+
if (platformMapping && sameWorkspaceId(platformMapping.workspace.id, workspace.id)) return withRemoteDeployBranch(provider, {
|
|
1666
1699
|
workspace,
|
|
1667
1700
|
project: toProjectSummary(platformMapping),
|
|
1668
1701
|
resolution: {
|
|
@@ -1671,14 +1704,59 @@ async function resolveDeployProjectContext(context, client, provider, explicitPr
|
|
|
1671
1704
|
targetNameSource: "platform-mapping"
|
|
1672
1705
|
}
|
|
1673
1706
|
}, branch, context.runtime.signal);
|
|
1674
|
-
if (canPrompt(context) && !context.flags.yes) return withRemoteDeployBranch(provider, await resolveInteractiveDeployProjectSetup(context, provider, workspace, projects), branch, context.runtime.signal);
|
|
1707
|
+
if (canPrompt(context) && !context.flags.yes) return withRemoteDeployBranch(provider, await resolveInteractiveDeployProjectSetup(context, provider, workspace, projects, options.createProjectRegion), branch, context.runtime.signal);
|
|
1675
1708
|
throw projectSetupRequiredError(projects, await inferTargetName(context.runtime.cwd, context.runtime.signal));
|
|
1676
1709
|
}
|
|
1677
|
-
async function
|
|
1710
|
+
async function resolveCreatedDeployProject(provider, createProjectName, workspace, signal, createProjectRegion) {
|
|
1711
|
+
const projectName = createProjectName.trim();
|
|
1712
|
+
if (!projectName) throw projectSetupNameRequiredError("app deploy --create-project");
|
|
1713
|
+
return {
|
|
1714
|
+
workspace,
|
|
1715
|
+
project: toProjectSummary(await createProjectForDeploySetup(provider, projectName, workspace, signal, createProjectRegion)),
|
|
1716
|
+
resolution: {
|
|
1717
|
+
projectSource: "created",
|
|
1718
|
+
targetName: projectName,
|
|
1719
|
+
targetNameSource: "explicit"
|
|
1720
|
+
},
|
|
1721
|
+
localPinAction: "created"
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
function resolveEnvDeployProject(envProjectId, projects, workspace) {
|
|
1725
|
+
const project = projects.find((candidate) => candidate.id === envProjectId);
|
|
1726
|
+
if (!project) throw projectNotFoundError(envProjectId, workspace);
|
|
1727
|
+
return {
|
|
1728
|
+
workspace,
|
|
1729
|
+
project: toProjectSummary(project),
|
|
1730
|
+
resolution: {
|
|
1731
|
+
projectSource: "env",
|
|
1732
|
+
targetName: envProjectId,
|
|
1733
|
+
targetNameSource: "env"
|
|
1734
|
+
}
|
|
1735
|
+
};
|
|
1736
|
+
}
|
|
1737
|
+
function resolveLocalPinDeployProject(pin, projects, workspace) {
|
|
1738
|
+
if (!sameWorkspaceId(pin.workspaceId, workspace.id)) throw localProjectWorkspaceMismatchError({
|
|
1739
|
+
pinnedWorkspaceId: pin.workspaceId,
|
|
1740
|
+
pinnedProjectId: pin.projectId,
|
|
1741
|
+
activeWorkspace: workspace
|
|
1742
|
+
});
|
|
1743
|
+
const project = projects.find((candidate) => candidate.id === pin.projectId);
|
|
1744
|
+
if (!project) throw localResolutionPinStaleError();
|
|
1745
|
+
return {
|
|
1746
|
+
workspace,
|
|
1747
|
+
project: toProjectSummary(project),
|
|
1748
|
+
resolution: {
|
|
1749
|
+
projectSource: "local-pin",
|
|
1750
|
+
targetName: project.name,
|
|
1751
|
+
targetNameSource: "local-pin"
|
|
1752
|
+
}
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
async function resolveInteractiveDeployProjectSetup(context, provider, workspace, projects, createProjectRegion) {
|
|
1678
1756
|
const setup = await promptForProjectSetupChoice({
|
|
1679
1757
|
context,
|
|
1680
1758
|
projects,
|
|
1681
|
-
createProject: (projectName) => createProjectForDeploySetup(provider, projectName, workspace, context.runtime.signal),
|
|
1759
|
+
createProject: (projectName) => createProjectForDeploySetup(provider, projectName, workspace, context.runtime.signal, createProjectRegion),
|
|
1682
1760
|
cancel: {
|
|
1683
1761
|
why: "Deploy needs a Project before it can continue.",
|
|
1684
1762
|
fix: "Choose an existing Project or create a new one, then rerun deploy.",
|
|
@@ -1696,9 +1774,10 @@ async function resolveInteractiveDeployProjectSetup(context, provider, workspace
|
|
|
1696
1774
|
localPinAction: setup.action
|
|
1697
1775
|
};
|
|
1698
1776
|
}
|
|
1699
|
-
async function createProjectForDeploySetup(provider, projectName, workspace, signal) {
|
|
1777
|
+
async function createProjectForDeploySetup(provider, projectName, workspace, signal, region) {
|
|
1700
1778
|
const created = await provider.createProject({
|
|
1701
1779
|
name: projectName,
|
|
1780
|
+
region,
|
|
1702
1781
|
signal
|
|
1703
1782
|
}).catch((error) => {
|
|
1704
1783
|
throw projectCreateFailedError(error, projectName, workspace, {
|
|
@@ -1714,6 +1793,7 @@ async function createProjectForDeploySetup(provider, projectName, workspace, sig
|
|
|
1714
1793
|
return {
|
|
1715
1794
|
id: created.id,
|
|
1716
1795
|
name: created.name,
|
|
1796
|
+
...created.defaultRegion != null ? { defaultRegion: created.defaultRegion } : {},
|
|
1717
1797
|
workspace
|
|
1718
1798
|
};
|
|
1719
1799
|
}
|
|
@@ -1794,7 +1874,7 @@ async function resolveComputeTargetOrThrow(context, configTarget, commandName, o
|
|
|
1794
1874
|
config = loaded.value;
|
|
1795
1875
|
}
|
|
1796
1876
|
if (!config) {
|
|
1797
|
-
if (configTarget) throw usageError(`App target "${configTarget}" requires a compute config file`, `No ${COMPUTE_CONFIG_FILENAME
|
|
1877
|
+
if (configTarget) throw usageError(`App target "${configTarget}" requires a compute config file`, `No ${COMPUTE_CONFIG_FILENAME} exists in the current directory, so there are no named app targets.`, `Create ${COMPUTE_CONFIG_FILENAME} with an apps entry named "${configTarget}", or rerun without the target argument.`, [`prisma-cli app ${commandName}`], "app");
|
|
1798
1878
|
return {
|
|
1799
1879
|
config: null,
|
|
1800
1880
|
target: null
|
|
@@ -1937,55 +2017,21 @@ async function resolveDeployEntrypoint(cwd, framework, explicitEntrypoint, signa
|
|
|
1937
2017
|
}
|
|
1938
2018
|
}
|
|
1939
2019
|
async function detectDeployFramework(cwd, signal) {
|
|
1940
|
-
const
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
buildType: framework.buildType,
|
|
1949
|
-
displayName: framework.displayName,
|
|
1950
|
-
annotation
|
|
1951
|
-
};
|
|
1952
|
-
}
|
|
1953
|
-
return null;
|
|
1954
|
-
}
|
|
1955
|
-
async function detectFrameworkConfigFile(cwd, framework, signal) {
|
|
1956
|
-
for (const candidate of framework.detectConfigFiles) {
|
|
1957
|
-
const filePath = path.join(cwd, candidate);
|
|
1958
|
-
signal.throwIfAborted();
|
|
1959
|
-
try {
|
|
1960
|
-
const content = await readFile(filePath, {
|
|
1961
|
-
encoding: "utf8",
|
|
1962
|
-
signal
|
|
1963
|
-
});
|
|
1964
|
-
return {
|
|
1965
|
-
exists: true,
|
|
1966
|
-
standalone: /\boutput\s*:\s*["'`]standalone["'`]/.test(content),
|
|
1967
|
-
path: filePath
|
|
1968
|
-
};
|
|
1969
|
-
} catch (error) {
|
|
1970
|
-
if (signal.aborted) throw error;
|
|
1971
|
-
if (error.code !== "ENOENT") throw error;
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
2020
|
+
const detected = await detectComputeAppFromDirectory({
|
|
2021
|
+
appPath: cwd,
|
|
2022
|
+
signal
|
|
2023
|
+
});
|
|
2024
|
+
if (!detected) return null;
|
|
2025
|
+
let annotation = "detected from package.json";
|
|
2026
|
+
if (detected.configFile?.standaloneOutput) annotation = "standalone output detected";
|
|
2027
|
+
else if (detected.configFile) annotation = `detected from ${path.basename(detected.configFile.path)}`;
|
|
1974
2028
|
return {
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
2029
|
+
key: detected.framework,
|
|
2030
|
+
buildType: detected.buildType,
|
|
2031
|
+
displayName: detected.frameworkName,
|
|
2032
|
+
annotation
|
|
1978
2033
|
};
|
|
1979
2034
|
}
|
|
1980
|
-
function hasPackageDependency(packageJson, dependencyName) {
|
|
1981
|
-
return hasDependency(packageJson?.dependencies, dependencyName) || hasDependency(packageJson?.devDependencies, dependencyName);
|
|
1982
|
-
}
|
|
1983
|
-
function hasAnyPackageDependency(packageJson, dependencyNames) {
|
|
1984
|
-
return dependencyNames.some((dependencyName) => hasPackageDependency(packageJson, dependencyName));
|
|
1985
|
-
}
|
|
1986
|
-
function hasDependency(dependencies, dependencyName) {
|
|
1987
|
-
return Boolean(dependencies && typeof dependencies === "object" && dependencyName in dependencies);
|
|
1988
|
-
}
|
|
1989
2035
|
function frameworkFromUserFacingValue(value, annotation) {
|
|
1990
2036
|
const framework = frameworkFromAlias(value);
|
|
1991
2037
|
if (!framework) throw frameworkNotDetectedError(void 0, value);
|
|
@@ -1996,11 +2042,6 @@ function frameworkFromUserFacingValue(value, annotation) {
|
|
|
1996
2042
|
annotation
|
|
1997
2043
|
};
|
|
1998
2044
|
}
|
|
1999
|
-
/**
|
|
2000
|
-
* The nuxt and astro strategies build with their framework CLI and stage
|
|
2001
|
-
* fixed output, so a compute config `build` block has nothing to apply to.
|
|
2002
|
-
* Erroring beats silently ignoring committed settings.
|
|
2003
|
-
*/
|
|
2004
2045
|
function assertConfigBackedBuildSettings(buildType) {
|
|
2005
2046
|
if (isConfigBackedBuildType(buildType)) return;
|
|
2006
2047
|
const displayName = FRAMEWORKS.find((framework) => framework.buildType === buildType)?.displayName ?? buildType;
|
|
@@ -2042,15 +2083,23 @@ function maybeRenderDeployBuildSettings(context, resolution) {
|
|
|
2042
2083
|
if (context.flags.json || context.flags.quiet) return;
|
|
2043
2084
|
const settings = resolution.settings;
|
|
2044
2085
|
const title = resolution.status === "config" ? `Using ${resolution.relativeConfigPath}` : "Build settings";
|
|
2045
|
-
context.output.stderr.write(`${title}\n${renderDeployOutputRows(context.ui, [
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2086
|
+
context.output.stderr.write(`${title}\n${renderDeployOutputRows(context.ui, [
|
|
2087
|
+
{
|
|
2088
|
+
label: "Build Command",
|
|
2089
|
+
value: settings.buildCommand ?? "none",
|
|
2090
|
+
origin: settings.buildCommandSource ?? void 0
|
|
2091
|
+
},
|
|
2092
|
+
{
|
|
2093
|
+
label: "Output Directory",
|
|
2094
|
+
value: settings.outputDirectory,
|
|
2095
|
+
origin: settings.outputDirectorySource ?? void 0
|
|
2096
|
+
},
|
|
2097
|
+
...settings.entrypoint ? [{
|
|
2098
|
+
label: "Entrypoint",
|
|
2099
|
+
value: settings.entrypoint,
|
|
2100
|
+
origin: settings.entrypointSource ?? void 0
|
|
2101
|
+
}] : []
|
|
2102
|
+
]).join("\n")}\n\n`);
|
|
2054
2103
|
}
|
|
2055
2104
|
function maybeRenderProjectLinked(context, directory, projectName, localPinPath) {
|
|
2056
2105
|
if (context.flags.json || context.flags.quiet) return;
|
|
@@ -2068,6 +2117,7 @@ async function maybeCustomizeDeploySettings(context, options) {
|
|
|
2068
2117
|
if (!await confirmPrompt({
|
|
2069
2118
|
input: context.runtime.stdin,
|
|
2070
2119
|
output: context.runtime.stderr,
|
|
2120
|
+
signal: context.runtime.signal,
|
|
2071
2121
|
message: "Customize build settings?",
|
|
2072
2122
|
initialValue: false
|
|
2073
2123
|
})) return {
|
|
@@ -2077,6 +2127,7 @@ async function maybeCustomizeDeploySettings(context, options) {
|
|
|
2077
2127
|
const framework = frameworkFromUserFacingValue(await selectPrompt({
|
|
2078
2128
|
input: context.runtime.stdin,
|
|
2079
2129
|
output: context.runtime.stderr,
|
|
2130
|
+
signal: context.runtime.signal,
|
|
2080
2131
|
message: `Framework (${options.framework.displayName})`,
|
|
2081
2132
|
choices: FRAMEWORKS.map((framework) => ({
|
|
2082
2133
|
label: framework.displayName,
|
|
@@ -2086,6 +2137,7 @@ async function maybeCustomizeDeploySettings(context, options) {
|
|
|
2086
2137
|
const requestedPort = await textPrompt({
|
|
2087
2138
|
input: context.runtime.stdin,
|
|
2088
2139
|
output: context.runtime.stderr,
|
|
2140
|
+
signal: context.runtime.signal,
|
|
2089
2141
|
message: `HTTP port (${options.runtime.port})`,
|
|
2090
2142
|
placeholder: String(options.runtime.port),
|
|
2091
2143
|
validate: validateDeployHttpPortText
|
|
@@ -2149,7 +2201,7 @@ async function readCurrentWorkspaceId(context) {
|
|
|
2149
2201
|
function normalizeBuildType(requestedBuildType) {
|
|
2150
2202
|
if (!requestedBuildType) return "auto";
|
|
2151
2203
|
if (isPreviewBuildType(requestedBuildType)) return requestedBuildType;
|
|
2152
|
-
throw usageError(`Unsupported build type "${requestedBuildType}"`, `Only ${
|
|
2204
|
+
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");
|
|
2153
2205
|
}
|
|
2154
2206
|
function isPreviewBuildType(value) {
|
|
2155
2207
|
return APP_BUILD_TYPES.includes(value);
|
|
@@ -2172,8 +2224,9 @@ function assertSupportedEntrypoint(buildType, entrypoint, commandName) {
|
|
|
2172
2224
|
* and Bun/Hono have dev servers in the current preview.
|
|
2173
2225
|
*/
|
|
2174
2226
|
async function resolveLocalRunFramework(context, options) {
|
|
2227
|
+
if (options.requestedBuildType === "auto" && options.entrypoint) return frameworkFromUserFacingValue("bun", "set by --entry");
|
|
2175
2228
|
if (LOCAL_DEV_BUILD_TYPES.includes(options.requestedBuildType)) {
|
|
2176
|
-
if (options.configFramework && computeFrameworkToBuildType(options.configFramework) === options.requestedBuildType) return frameworkFromUserFacingValue(options.configFramework, `set by ${COMPUTE_CONFIG_FILENAME
|
|
2229
|
+
if (options.configFramework && computeFrameworkToBuildType(options.configFramework) === options.requestedBuildType) return frameworkFromUserFacingValue(options.configFramework, `set by ${COMPUTE_CONFIG_FILENAME}`);
|
|
2177
2230
|
return frameworkFromUserFacingValue(options.requestedBuildType, "set by --build-type");
|
|
2178
2231
|
}
|
|
2179
2232
|
const detected = await detectDeployFramework(options.appDir, context.runtime.signal);
|
|
@@ -2195,9 +2248,18 @@ function parseDeployHttpPort(requestedPort) {
|
|
|
2195
2248
|
if (!Number.isInteger(port) || port <= 0 || port > 65535) throw usageError(`Invalid HTTP port "${requestedPort}"`, "HTTP port must be an integer between 1 and 65535.", "Pass --http-port <number> with a valid port value.", ["prisma-cli app deploy --http-port 3000"], "app");
|
|
2196
2249
|
return port;
|
|
2197
2250
|
}
|
|
2198
|
-
function
|
|
2199
|
-
|
|
2200
|
-
|
|
2251
|
+
function parseDeployRegion(requestedRegion, source) {
|
|
2252
|
+
const region = requestedRegion.trim();
|
|
2253
|
+
if (region.length === 0) throw usageError("Invalid app region", `The app region ${source} must be a non-empty region id.`, "Pass a Prisma Compute region id.", ["prisma-cli app deploy --region eu-central-1"], "app");
|
|
2254
|
+
if (!COMPUTE_REGION_IDS.has(region)) throw usageError("Invalid app region", `The app region ${source} must be one of: ${COMPUTE_REGIONS.join(", ")}.`, "Pass a supported Prisma Compute region id.", ["prisma-cli app deploy --region eu-central-1"], "app");
|
|
2255
|
+
return region;
|
|
2256
|
+
}
|
|
2257
|
+
function normalizeDeployRegionInput(region) {
|
|
2258
|
+
if (!region) return;
|
|
2259
|
+
return {
|
|
2260
|
+
...region,
|
|
2261
|
+
value: parseDeployRegion(region.value, region.annotation)
|
|
2262
|
+
};
|
|
2201
2263
|
}
|
|
2202
2264
|
function deployFailedError(summary, error, nextSteps) {
|
|
2203
2265
|
return new CliError({
|
|
@@ -2211,47 +2273,53 @@ function deployFailedError(summary, error, nextSteps) {
|
|
|
2211
2273
|
nextSteps
|
|
2212
2274
|
});
|
|
2213
2275
|
}
|
|
2276
|
+
function describeStalledDeployPhase(progress) {
|
|
2277
|
+
if (progress.uploadCompleted) return "The artifact uploaded, but the deployment did not start.";
|
|
2278
|
+
if (progress.archiveReady) return "The app built locally, but the artifact did not finish uploading.";
|
|
2279
|
+
return "The app built locally, but the deployment did not start.";
|
|
2280
|
+
}
|
|
2281
|
+
function localBuildFailedError(why, debug) {
|
|
2282
|
+
const standaloneOutputFailure = isNextStandaloneOutputFailure(why);
|
|
2283
|
+
const fix = standaloneOutputFailure ? "Add output: \"standalone\" to next.config.*, then rerun deploy." : "Inspect the build output above, fix the error, and redeploy.";
|
|
2284
|
+
const nextSteps = standaloneOutputFailure ? ["Add output: \"standalone\" to next.config.*, then rerun prisma-cli app deploy"] : [];
|
|
2285
|
+
const nextActions = standaloneOutputFailure ? [{
|
|
2286
|
+
kind: "edit-file",
|
|
2287
|
+
journey: "deploy-app",
|
|
2288
|
+
label: "Add Next.js standalone output",
|
|
2289
|
+
reason: "Prisma Compute needs Next.js standalone output to build a deployable server artifact."
|
|
2290
|
+
}, {
|
|
2291
|
+
kind: "run-command",
|
|
2292
|
+
journey: "deploy-app",
|
|
2293
|
+
label: "Rerun deploy",
|
|
2294
|
+
command: "prisma-cli app deploy"
|
|
2295
|
+
}] : [];
|
|
2296
|
+
return new CliError({
|
|
2297
|
+
code: "BUILD_FAILED",
|
|
2298
|
+
domain: "app",
|
|
2299
|
+
summary: "Build failed locally.",
|
|
2300
|
+
why,
|
|
2301
|
+
fix,
|
|
2302
|
+
debug,
|
|
2303
|
+
meta: { phase: "build" },
|
|
2304
|
+
humanLines: [
|
|
2305
|
+
"Build failed locally.",
|
|
2306
|
+
"",
|
|
2307
|
+
`✗ Built ${why}`,
|
|
2308
|
+
"",
|
|
2309
|
+
`Fix: ${fix}`
|
|
2310
|
+
],
|
|
2311
|
+
exitCode: 1,
|
|
2312
|
+
nextSteps,
|
|
2313
|
+
nextActions
|
|
2314
|
+
});
|
|
2315
|
+
}
|
|
2214
2316
|
function appDeployFailedError(error, progress) {
|
|
2215
2317
|
const why = error instanceof Error ? error.message : String(error);
|
|
2216
2318
|
const debug = formatDebugDetails(error);
|
|
2217
|
-
if (progress.buildStarted && !progress.buildCompleted)
|
|
2218
|
-
const standaloneOutputFailure = isNextStandaloneOutputFailure(why);
|
|
2219
|
-
const fix = standaloneOutputFailure ? "Add output: \"standalone\" to next.config.*, then rerun deploy." : "Inspect the build output above, fix the error, and redeploy.";
|
|
2220
|
-
const nextSteps = standaloneOutputFailure ? ["Add output: \"standalone\" to next.config.*, then rerun prisma-cli app deploy"] : [];
|
|
2221
|
-
const nextActions = standaloneOutputFailure ? [{
|
|
2222
|
-
kind: "edit-file",
|
|
2223
|
-
journey: "deploy-app",
|
|
2224
|
-
label: "Add Next.js standalone output",
|
|
2225
|
-
reason: "Prisma Compute needs Next.js standalone output to build a deployable server artifact."
|
|
2226
|
-
}, {
|
|
2227
|
-
kind: "run-command",
|
|
2228
|
-
journey: "deploy-app",
|
|
2229
|
-
label: "Rerun deploy",
|
|
2230
|
-
command: "prisma-cli app deploy"
|
|
2231
|
-
}] : [];
|
|
2232
|
-
return new CliError({
|
|
2233
|
-
code: "BUILD_FAILED",
|
|
2234
|
-
domain: "app",
|
|
2235
|
-
summary: "Build failed locally.",
|
|
2236
|
-
why,
|
|
2237
|
-
fix,
|
|
2238
|
-
debug,
|
|
2239
|
-
meta: { phase: "build" },
|
|
2240
|
-
humanLines: [
|
|
2241
|
-
"Build failed locally.",
|
|
2242
|
-
"",
|
|
2243
|
-
`✗ Built ${why}`,
|
|
2244
|
-
"",
|
|
2245
|
-
`Fix: ${fix}`
|
|
2246
|
-
],
|
|
2247
|
-
exitCode: 1,
|
|
2248
|
-
nextSteps,
|
|
2249
|
-
nextActions
|
|
2250
|
-
});
|
|
2251
|
-
}
|
|
2319
|
+
if (progress.buildStarted && !progress.buildCompleted) return localBuildFailedError(why, debug);
|
|
2252
2320
|
if (!progress.buildStarted) return deployFailedError("App deploy failed", error, ["prisma-cli app deploy"]);
|
|
2253
2321
|
const phaseHeadline = progress.containerLive ? "The deployment started, but the app is not ready yet." : "Deploy failed after the build completed.";
|
|
2254
|
-
const recoveryLines = progress.
|
|
2322
|
+
const recoveryLines = progress.deploymentId ? ["See what happened", `prisma-cli app logs --deployment ${progress.deploymentId}`] : ["Fix", "Retry the command, or rerun with --trace for more detailed diagnostics."];
|
|
2255
2323
|
const urlLines = progress.deploymentUrl ? [
|
|
2256
2324
|
"",
|
|
2257
2325
|
"URL",
|
|
@@ -2268,7 +2336,7 @@ function appDeployFailedError(error, progress) {
|
|
|
2268
2336
|
] : [
|
|
2269
2337
|
phaseHeadline,
|
|
2270
2338
|
"",
|
|
2271
|
-
progress
|
|
2339
|
+
describeStalledDeployPhase(progress),
|
|
2272
2340
|
"",
|
|
2273
2341
|
...recoveryLines
|
|
2274
2342
|
];
|
|
@@ -2277,11 +2345,11 @@ function appDeployFailedError(error, progress) {
|
|
|
2277
2345
|
domain: "app",
|
|
2278
2346
|
summary: phaseHeadline,
|
|
2279
2347
|
why,
|
|
2280
|
-
fix: progress.
|
|
2348
|
+
fix: progress.deploymentId ? `Inspect logs with prisma-cli app logs --deployment ${progress.deploymentId}.` : "Retry the command, or rerun with --trace for more detailed diagnostics.",
|
|
2281
2349
|
debug,
|
|
2282
2350
|
meta: {
|
|
2283
2351
|
phase: progress.containerLive ? "runtime_ready" : "deploy",
|
|
2284
|
-
deploymentId: progress.
|
|
2352
|
+
deploymentId: progress.deploymentId,
|
|
2285
2353
|
deploymentUrl: progress.deploymentUrl
|
|
2286
2354
|
},
|
|
2287
2355
|
humanLines,
|
|
@@ -2352,7 +2420,7 @@ function projectSetupRequiredError(projects, suggestedName) {
|
|
|
2352
2420
|
});
|
|
2353
2421
|
}
|
|
2354
2422
|
function isNextStandaloneOutputFailure(message) {
|
|
2355
|
-
return
|
|
2423
|
+
return NEXTJS_MENTION.test(message) && STANDALONE_OUTPUT_MENTION.test(message);
|
|
2356
2424
|
}
|
|
2357
2425
|
function noDeploymentsError(summary, why) {
|
|
2358
2426
|
return new CliError({
|
|
@@ -2395,15 +2463,12 @@ function isAutoBuildDetectionError(error) {
|
|
|
2395
2463
|
return error instanceof Error && error.message.startsWith("Entrypoint is required.");
|
|
2396
2464
|
}
|
|
2397
2465
|
function formatBuildTypeName(buildType) {
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
case "nestjs": return "NestJS";
|
|
2403
|
-
case "tanstack-start": return "TanStack Start";
|
|
2404
|
-
case "bun": return "Bun";
|
|
2405
|
-
case "auto": return "Auto";
|
|
2466
|
+
if (buildType === "auto") return "Auto";
|
|
2467
|
+
for (let index = FRAMEWORKS.length - 1; index >= 0; index -= 1) {
|
|
2468
|
+
const framework = FRAMEWORKS[index];
|
|
2469
|
+
if (framework?.buildType === buildType) return framework.displayName;
|
|
2406
2470
|
}
|
|
2471
|
+
return buildType;
|
|
2407
2472
|
}
|
|
2408
2473
|
function removeFailedError(summary, error, nextSteps) {
|
|
2409
2474
|
return new CliError({
|
|
@@ -2440,4 +2505,4 @@ function toOptionalEnvVars(envVars) {
|
|
|
2440
2505
|
return Object.keys(envVars).length > 0 ? envVars : void 0;
|
|
2441
2506
|
}
|
|
2442
2507
|
//#endregion
|
|
2443
|
-
export { runAppBuild, runAppDeploy, runAppDomainAdd, runAppDomainRemove, runAppDomainRetry, runAppDomainShow, runAppDomainWait, runAppListDeploys, runAppLogs, runAppOpen, runAppPromote, runAppRemove, runAppRollback, runAppRun, runAppShow, runAppShowDeploy };
|
|
2508
|
+
export { detectDeployFramework, runAppBuild, runAppDeploy, runAppDomainAdd, runAppDomainRemove, runAppDomainRetry, runAppDomainShow, runAppDomainWait, runAppListDeploys, runAppLogs, runAppOpen, runAppPromote, runAppRemove, runAppRollback, runAppRun, runAppShow, runAppShowDeploy };
|