@prisma/cli 3.0.0-beta.0 → 3.0.0-beta.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 +13 -0
- package/dist/commands/app/index.js +6 -5
- package/dist/commands/project/index.js +28 -2
- package/dist/controllers/app-env.js +6 -8
- package/dist/controllers/app.js +268 -260
- package/dist/controllers/project.js +177 -21
- package/dist/lib/auth/auth-ops.js +49 -8
- package/dist/lib/project/interactive-setup.js +56 -0
- package/dist/lib/project/resolution.js +124 -96
- package/dist/lib/project/setup.js +88 -0
- package/dist/presenters/auth.js +19 -6
- package/dist/presenters/project.js +44 -15
- package/dist/shell/command-arguments.js +6 -0
- package/dist/shell/command-meta.js +36 -3
- package/dist/shell/command-runner.js +4 -2
- package/dist/shell/errors.js +2 -0
- package/dist/shell/output.js +3 -1
- package/dist/use-cases/auth.js +15 -4
- package/package.json +2 -2
package/dist/controllers/app.js
CHANGED
|
@@ -9,10 +9,13 @@ import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
|
9
9
|
import { readAuthState } from "../lib/auth/auth-ops.js";
|
|
10
10
|
import { parseEnvAssignments } from "../lib/app/env-vars.js";
|
|
11
11
|
import { renderDeployOutputRows } from "../lib/app/deploy-output.js";
|
|
12
|
-
import { readBunPackageJson } from "../lib/app/bun-project.js";
|
|
12
|
+
import { readBunPackageEntrypoint, readBunPackageJson } from "../lib/app/bun-project.js";
|
|
13
13
|
import { DEFAULT_LOCAL_DEV_PORT, resolveLocalBuildType, runLocalApp } from "../lib/app/local-dev.js";
|
|
14
|
-
import {
|
|
15
|
-
import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH,
|
|
14
|
+
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
15
|
+
import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, readLocalResolutionPin } from "../lib/project/local-pin.js";
|
|
16
|
+
import { buildProjectSetupNextActions, inferTargetName, projectNotFoundError, resolveDurablePlatformMapping, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
|
|
17
|
+
import { bindProjectToDirectory, projectCreateFailedError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
|
|
18
|
+
import { promptForProjectSetupChoice } from "../lib/project/interactive-setup.js";
|
|
16
19
|
import { PREVIEW_BUILD_TYPES, RESOLVED_PREVIEW_BUILD_TYPES, executePreviewBuild } from "../lib/app/preview-build.js";
|
|
17
20
|
import { PREVIEW_DEFAULT_REGION } from "../lib/app/preview-interaction.js";
|
|
18
21
|
import { createPreviewDeployProgress, createPreviewDeployProgressState, createPreviewPromoteProgress } from "../lib/app/preview-progress.js";
|
|
@@ -28,8 +31,10 @@ import open from "open";
|
|
|
28
31
|
const DEPLOY_FRAMEWORKS = [
|
|
29
32
|
"nextjs",
|
|
30
33
|
"hono",
|
|
31
|
-
"tanstack-start"
|
|
34
|
+
"tanstack-start",
|
|
35
|
+
"bun"
|
|
32
36
|
];
|
|
37
|
+
const TANSTACK_START_PACKAGES = ["@tanstack/react-start", "@tanstack/solid-start"];
|
|
33
38
|
const FRAMEWORK_DEFAULT_HTTP_PORT = 3e3;
|
|
34
39
|
const PRISMA_PROJECT_ID_ENV_VAR = "PRISMA_PROJECT_ID";
|
|
35
40
|
const PRISMA_APP_ID_ENV_VAR = "PRISMA_APP_ID";
|
|
@@ -96,67 +101,65 @@ async function runAppDeploy(context, appName, options) {
|
|
|
96
101
|
ensurePreviewAppMode(context);
|
|
97
102
|
const envProjectId = readDeployEnvOverride(context, PRISMA_PROJECT_ID_ENV_VAR);
|
|
98
103
|
const envAppId = readDeployEnvOverride(context, PRISMA_APP_ID_ENV_VAR);
|
|
99
|
-
|
|
104
|
+
assertExclusiveDeployProjectInputs({
|
|
105
|
+
projectRef: options?.projectRef,
|
|
106
|
+
createProjectName: options?.createProjectName,
|
|
107
|
+
envProjectId
|
|
108
|
+
});
|
|
109
|
+
const skipLocalPin = Boolean(envProjectId || options?.projectRef || options?.createProjectName);
|
|
100
110
|
const localPin = skipLocalPin ? { kind: "missing" } : await readLocalResolutionPin(context.runtime.cwd);
|
|
101
111
|
if (!skipLocalPin && localPin.kind === "invalid") throw localResolutionPinStaleError();
|
|
102
|
-
const explicitBuildType = Boolean(options?.buildType && options.buildType !== "auto");
|
|
103
112
|
const branch = await resolveDeployBranch(context, options?.branchName);
|
|
104
113
|
if (options?.httpPort) parseDeployHttpPort(options.httpPort);
|
|
105
|
-
|
|
114
|
+
assertSupportedEntrypointForRequestedDeployShape({
|
|
106
115
|
requestedFramework: options?.framework,
|
|
107
|
-
|
|
108
|
-
explicitBuildType
|
|
116
|
+
entrypoint: options?.entrypoint
|
|
109
117
|
});
|
|
110
|
-
let runtime = resolveDeployRuntime(options?.httpPort, framework);
|
|
111
|
-
assertSupportedEntrypoint(framework.buildType, options?.entrypoint, "deploy");
|
|
112
|
-
const envVars = toOptionalEnvVars(parseEnvAssignments(options?.envAssignments, { commandName: "deploy" }));
|
|
113
|
-
const firstDeploy = !skipLocalPin && localPin.kind === "missing";
|
|
114
118
|
const { provider, target, projectId } = await requireProviderAndDeployProjectContext(context, options?.projectRef, {
|
|
115
|
-
allowCreate: true,
|
|
116
119
|
branch,
|
|
120
|
+
createProjectName: options?.createProjectName,
|
|
117
121
|
envProjectId,
|
|
118
122
|
localPin
|
|
119
123
|
});
|
|
124
|
+
let localPinResult;
|
|
125
|
+
if (target.localPinAction) {
|
|
126
|
+
const setupResult = await bindProjectToDirectory(context, target.workspace, target.project, target.localPinAction);
|
|
127
|
+
localPinResult = setupResult.localPin;
|
|
128
|
+
maybeRenderProjectLinked(context, setupResult.directory, setupResult.project.name, setupResult.localPin.path);
|
|
129
|
+
}
|
|
130
|
+
let framework = await resolveDeployFramework(context, {
|
|
131
|
+
requestedFramework: options?.framework,
|
|
132
|
+
entrypoint: options?.entrypoint
|
|
133
|
+
});
|
|
134
|
+
let runtime = resolveDeployRuntime(options?.httpPort, framework);
|
|
135
|
+
assertSupportedEntrypoint(framework.buildType, options?.entrypoint, "deploy");
|
|
136
|
+
const envVars = toOptionalEnvVars(parseEnvAssignments(options?.envAssignments, { commandName: "deploy" }));
|
|
120
137
|
const selectedApp = await resolveDeployAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), {
|
|
121
138
|
explicitAppName: appName,
|
|
122
139
|
explicitAppId: envAppId,
|
|
123
|
-
firstDeploy,
|
|
140
|
+
firstDeploy: Boolean(target.localPinAction),
|
|
124
141
|
inferName: () => inferTargetName(context.runtime.cwd)
|
|
125
142
|
});
|
|
126
143
|
await maybeRenderDeploySetupBlock(context, {
|
|
127
|
-
|
|
128
|
-
workspaceName: target.workspace.name,
|
|
144
|
+
includeDirectory: !target.localPinAction,
|
|
129
145
|
projectName: target.project.name,
|
|
130
|
-
projectAnnotation: annotationForProjectResolution(target.resolution),
|
|
131
146
|
branchName: target.branch.name,
|
|
132
|
-
|
|
133
|
-
appName: selectedApp.displayName,
|
|
134
|
-
appAnnotation: selectedApp.annotation,
|
|
135
|
-
framework,
|
|
136
|
-
runtime
|
|
147
|
+
appName: selectedApp.displayName
|
|
137
148
|
});
|
|
138
149
|
const customized = await maybeCustomizeDeploySettings(context, {
|
|
139
150
|
framework,
|
|
140
151
|
runtime,
|
|
141
152
|
firstDeploy: selectedApp.firstDeploy,
|
|
142
153
|
explicitFramework: Boolean(options?.framework),
|
|
143
|
-
|
|
154
|
+
explicitEntrypoint: Boolean(options?.entrypoint),
|
|
144
155
|
explicitHttpPort: Boolean(options?.httpPort)
|
|
145
156
|
});
|
|
146
157
|
framework = customized.framework;
|
|
147
158
|
runtime = customized.runtime;
|
|
148
159
|
const buildType = framework.buildType;
|
|
149
160
|
assertSupportedEntrypoint(buildType, options?.entrypoint, "deploy");
|
|
161
|
+
const entrypoint = await resolveDeployEntrypoint(context.runtime.cwd, framework, options?.entrypoint);
|
|
150
162
|
const portMapping = parseDeployPortMapping(String(runtime.port));
|
|
151
|
-
const shouldWriteLocalPin = firstDeploy && !skipLocalPin;
|
|
152
|
-
if (shouldWriteLocalPin) {
|
|
153
|
-
await writeLocalResolutionPin(context.runtime.cwd, {
|
|
154
|
-
workspaceId: target.workspace.id,
|
|
155
|
-
projectId: target.project.id
|
|
156
|
-
});
|
|
157
|
-
await ensureLocalResolutionPinGitignore(context.runtime.cwd);
|
|
158
|
-
maybeRenderLocalPinBound(context, target.project.name);
|
|
159
|
-
}
|
|
160
163
|
const progressState = createPreviewDeployProgressState();
|
|
161
164
|
const deployStartedAt = Date.now();
|
|
162
165
|
const deployResult = await provider.deployApp({
|
|
@@ -166,7 +169,7 @@ async function runAppDeploy(context, appName, options) {
|
|
|
166
169
|
appId: selectedApp.appId,
|
|
167
170
|
appName: selectedApp.appName,
|
|
168
171
|
region: selectedApp.region,
|
|
169
|
-
entrypoint
|
|
172
|
+
entrypoint,
|
|
170
173
|
buildType,
|
|
171
174
|
portMapping,
|
|
172
175
|
envVars,
|
|
@@ -194,10 +197,7 @@ async function runAppDeploy(context, appName, options) {
|
|
|
194
197
|
},
|
|
195
198
|
deployment: deployResult.deployment,
|
|
196
199
|
durationMs: deployDurationMs,
|
|
197
|
-
localPin:
|
|
198
|
-
path: LOCAL_RESOLUTION_PIN_RELATIVE_PATH,
|
|
199
|
-
written: true
|
|
200
|
-
} : void 0
|
|
200
|
+
localPin: localPinResult
|
|
201
201
|
},
|
|
202
202
|
warnings: [],
|
|
203
203
|
nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${deployResult.deployment.id}`]
|
|
@@ -205,7 +205,7 @@ async function runAppDeploy(context, appName, options) {
|
|
|
205
205
|
}
|
|
206
206
|
async function runAppListDeploys(context, appName, projectRef) {
|
|
207
207
|
ensurePreviewAppMode(context);
|
|
208
|
-
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
208
|
+
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app list-deploys" });
|
|
209
209
|
const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName);
|
|
210
210
|
if (!selectedApp) return {
|
|
211
211
|
command: "app.list-deploys",
|
|
@@ -242,7 +242,7 @@ async function runAppListDeploys(context, appName, projectRef) {
|
|
|
242
242
|
}
|
|
243
243
|
async function runAppShow(context, appName, projectRef) {
|
|
244
244
|
ensurePreviewAppMode(context);
|
|
245
|
-
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
245
|
+
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app show" });
|
|
246
246
|
const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName);
|
|
247
247
|
if (!selectedApp) return {
|
|
248
248
|
command: "app.show",
|
|
@@ -318,7 +318,7 @@ async function runAppShowDeploy(context, deploymentId) {
|
|
|
318
318
|
}
|
|
319
319
|
async function runAppOpen(context, appName, projectRef) {
|
|
320
320
|
ensurePreviewAppMode(context);
|
|
321
|
-
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
321
|
+
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app open" });
|
|
322
322
|
const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName);
|
|
323
323
|
if (!selectedApp) throw noDeploymentsError("No deployments available to open", "The resolved project does not have any deployed app yet.");
|
|
324
324
|
const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
|
|
@@ -352,7 +352,7 @@ async function runAppOpen(context, appName, projectRef) {
|
|
|
352
352
|
}
|
|
353
353
|
async function runAppDomainAdd(context, hostname, options) {
|
|
354
354
|
const normalizedHostname = normalizeDomainHostname(hostname);
|
|
355
|
-
const target = await resolveAppDomainTarget(context, options);
|
|
355
|
+
const target = await resolveAppDomainTarget(context, options, `app domain add ${normalizedHostname}`);
|
|
356
356
|
const added = await target.provider.addDomain({
|
|
357
357
|
appId: target.app.id,
|
|
358
358
|
hostname: normalizedHostname
|
|
@@ -372,7 +372,7 @@ async function runAppDomainAdd(context, hostname, options) {
|
|
|
372
372
|
}
|
|
373
373
|
async function runAppDomainShow(context, hostname, options) {
|
|
374
374
|
const normalizedHostname = normalizeDomainHostname(hostname);
|
|
375
|
-
const target = await resolveAppDomainTarget(context, options);
|
|
375
|
+
const target = await resolveAppDomainTarget(context, options, `app domain show ${normalizedHostname}`);
|
|
376
376
|
const domain = await resolveDomainByHostname(target.provider, target.app.id, normalizedHostname, "show");
|
|
377
377
|
const detail = await target.provider.showDomain(domain.id).catch((error) => {
|
|
378
378
|
throw domainCommandError("show", error, normalizedHostname);
|
|
@@ -389,7 +389,7 @@ async function runAppDomainShow(context, hostname, options) {
|
|
|
389
389
|
}
|
|
390
390
|
async function runAppDomainRemove(context, hostname, options) {
|
|
391
391
|
const normalizedHostname = normalizeDomainHostname(hostname);
|
|
392
|
-
const target = await resolveAppDomainTarget(context, options);
|
|
392
|
+
const target = await resolveAppDomainTarget(context, options, `app domain remove ${normalizedHostname}`);
|
|
393
393
|
const domain = await resolveDomainByHostname(target.provider, target.app.id, normalizedHostname, "remove");
|
|
394
394
|
await confirmDomainRemoval(context, target.resultTarget, normalizedHostname);
|
|
395
395
|
await target.provider.removeDomain(domain.id).catch((error) => {
|
|
@@ -408,7 +408,7 @@ async function runAppDomainRemove(context, hostname, options) {
|
|
|
408
408
|
}
|
|
409
409
|
async function runAppDomainRetry(context, hostname, options) {
|
|
410
410
|
const normalizedHostname = normalizeDomainHostname(hostname);
|
|
411
|
-
const target = await resolveAppDomainTarget(context, options);
|
|
411
|
+
const target = await resolveAppDomainTarget(context, options, `app domain retry ${normalizedHostname}`);
|
|
412
412
|
const domain = await resolveDomainByHostname(target.provider, target.app.id, normalizedHostname, "retry");
|
|
413
413
|
const retried = await target.provider.retryDomain(domain.id).catch((error) => {
|
|
414
414
|
throw domainCommandError("retry", error, normalizedHostname);
|
|
@@ -426,7 +426,7 @@ async function runAppDomainRetry(context, hostname, options) {
|
|
|
426
426
|
async function runAppDomainWait(context, hostname, options) {
|
|
427
427
|
const normalizedHostname = normalizeDomainHostname(hostname);
|
|
428
428
|
const timeoutMs = parseDomainWaitTimeout(options?.timeout);
|
|
429
|
-
const target = await resolveAppDomainTarget(context, options);
|
|
429
|
+
const target = await resolveAppDomainTarget(context, options, `app domain wait ${normalizedHostname}`);
|
|
430
430
|
const domain = await resolveDomainByHostname(target.provider, target.app.id, normalizedHostname, "wait");
|
|
431
431
|
if (!context.flags.json && !context.flags.quiet) context.output.stderr.write([
|
|
432
432
|
`app domain wait -> Waiting for ${normalizedHostname} to become active.`,
|
|
@@ -478,7 +478,7 @@ async function runAppDomainWait(context, hostname, options) {
|
|
|
478
478
|
}
|
|
479
479
|
async function runAppLogs(context, appName, deploymentId, projectRef) {
|
|
480
480
|
ensurePreviewAppMode(context);
|
|
481
|
-
const { provider, target: resolvedTarget, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
481
|
+
const { provider, target: resolvedTarget, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app logs" });
|
|
482
482
|
const target = deploymentId ? await resolveExplicitLogDeployment(context, provider, projectId, resolvedTarget.branch.name, appName, deploymentId) : await resolveLiveLogDeployment(context, provider, projectId, resolvedTarget.branch.name, appName);
|
|
483
483
|
if (!context.flags.json && !context.flags.quiet) {
|
|
484
484
|
const lines = renderCommandHeader(context.ui, {
|
|
@@ -602,7 +602,7 @@ function writeLogRecord(context, record) {
|
|
|
602
602
|
}
|
|
603
603
|
async function runAppPromote(context, deploymentId, appName, projectRef) {
|
|
604
604
|
ensurePreviewAppMode(context);
|
|
605
|
-
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
605
|
+
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app promote" });
|
|
606
606
|
const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName, "promote");
|
|
607
607
|
const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
|
|
608
608
|
throw deployFailedError("Failed to list app deployments", error, ["prisma-cli app list-deploys"]);
|
|
@@ -642,7 +642,7 @@ async function runAppPromote(context, deploymentId, appName, projectRef) {
|
|
|
642
642
|
}
|
|
643
643
|
async function runAppRollback(context, appName, deploymentId, projectRef) {
|
|
644
644
|
ensurePreviewAppMode(context);
|
|
645
|
-
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
645
|
+
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app rollback" });
|
|
646
646
|
const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName, "rollback");
|
|
647
647
|
const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
|
|
648
648
|
throw deployFailedError("Failed to list app deployments", error, ["prisma-cli app list-deploys"]);
|
|
@@ -684,7 +684,7 @@ async function runAppRollback(context, appName, deploymentId, projectRef) {
|
|
|
684
684
|
}
|
|
685
685
|
async function runAppRemove(context, appName, projectRef) {
|
|
686
686
|
ensurePreviewAppMode(context);
|
|
687
|
-
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
687
|
+
const { provider, target, projectId } = await requireProviderAndProjectContext(context, projectRef, { commandName: "app remove" });
|
|
688
688
|
const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), appName, "remove");
|
|
689
689
|
await confirmAppRemoval(context, selectedApp);
|
|
690
690
|
const removedApp = await provider.removeApp(selectedApp.id).catch((error) => {
|
|
@@ -705,7 +705,7 @@ async function runAppRemove(context, appName, projectRef) {
|
|
|
705
705
|
nextSteps: ["prisma-cli app deploy", "prisma-cli app list-deploys"]
|
|
706
706
|
};
|
|
707
707
|
}
|
|
708
|
-
async function resolveAppDomainTarget(context, options) {
|
|
708
|
+
async function resolveAppDomainTarget(context, options, commandName = "app domain") {
|
|
709
709
|
ensurePreviewAppMode(context);
|
|
710
710
|
const branch = resolveDomainBranch(options?.branchName);
|
|
711
711
|
if (toBranchKind(branch.name) !== "production") throw new CliError({
|
|
@@ -719,14 +719,10 @@ async function resolveAppDomainTarget(context, options) {
|
|
|
719
719
|
});
|
|
720
720
|
const envProjectId = readDeployEnvOverride(context, PRISMA_PROJECT_ID_ENV_VAR);
|
|
721
721
|
const envAppId = readDeployEnvOverride(context, PRISMA_APP_ID_ENV_VAR);
|
|
722
|
-
const
|
|
723
|
-
const localPin = skipLocalPin ? { kind: "missing" } : await readLocalResolutionPin(context.runtime.cwd);
|
|
724
|
-
if (!skipLocalPin && localPin.kind === "invalid") throw localResolutionPinStaleError();
|
|
725
|
-
const { provider, target, projectId } = await requireProviderAndDeployProjectContext(context, options?.projectRef, {
|
|
726
|
-
allowCreate: false,
|
|
722
|
+
const { provider, target, projectId } = await requireProviderAndProjectContext(context, options?.projectRef, {
|
|
727
723
|
branch,
|
|
728
|
-
|
|
729
|
-
|
|
724
|
+
commandName,
|
|
725
|
+
envProjectId
|
|
730
726
|
});
|
|
731
727
|
const selectedApp = await resolveDomainAppSelection(context, projectId, await listApps(context, provider, projectId, target.branch.name), {
|
|
732
728
|
explicitAppName: options?.appName,
|
|
@@ -1221,9 +1217,9 @@ async function listApps(context, provider, projectId, branchName) {
|
|
|
1221
1217
|
domain: "project",
|
|
1222
1218
|
summary: "Project not found",
|
|
1223
1219
|
why: `The resolved project "${projectId}" does not exist in the authenticated workspace or is no longer accessible.`,
|
|
1224
|
-
fix: "Pass --project <id-or-name>, or run prisma-cli project show to inspect
|
|
1220
|
+
fix: "Pass --project <id-or-name>, or run prisma-cli project show to inspect this directory's binding.",
|
|
1225
1221
|
exitCode: 1,
|
|
1226
|
-
nextSteps: ["prisma-cli project show", "prisma-cli
|
|
1222
|
+
nextSteps: ["prisma-cli project show", "prisma-cli project link <id-or-name>"]
|
|
1227
1223
|
});
|
|
1228
1224
|
throw deployFailedError("Failed to list apps", error, ["prisma-cli project show"]);
|
|
1229
1225
|
});
|
|
@@ -1258,7 +1254,7 @@ function createPreviewLogAuthOptions(env) {
|
|
|
1258
1254
|
}
|
|
1259
1255
|
async function requireProviderAndProjectContext(context, explicitProject, options) {
|
|
1260
1256
|
const { client, provider } = await requirePreviewAppProviderWithClient(context);
|
|
1261
|
-
const target = await resolveProjectContext(context, client,
|
|
1257
|
+
const target = await resolveProjectContext(context, client, explicitProject, options);
|
|
1262
1258
|
return {
|
|
1263
1259
|
client,
|
|
1264
1260
|
provider,
|
|
@@ -1276,31 +1272,16 @@ async function requireProviderAndDeployProjectContext(context, explicitProject,
|
|
|
1276
1272
|
projectId: target.project.id
|
|
1277
1273
|
};
|
|
1278
1274
|
}
|
|
1279
|
-
async function resolveProjectContext(context, client,
|
|
1275
|
+
async function resolveProjectContext(context, client, explicitProject, options) {
|
|
1280
1276
|
const authState = await requireAuthenticatedAuthState(context);
|
|
1281
1277
|
if (!authState.workspace) throw workspaceRequiredError();
|
|
1282
1278
|
const resolved = await resolveProjectTarget({
|
|
1283
1279
|
context,
|
|
1284
1280
|
workspace: authState.workspace,
|
|
1285
1281
|
explicitProject,
|
|
1282
|
+
envProjectId: options?.envProjectId,
|
|
1286
1283
|
listProjects: () => listRealWorkspaceProjects(client, authState.workspace),
|
|
1287
|
-
|
|
1288
|
-
const project = await provider.createProject({ name }).catch((error) => {
|
|
1289
|
-
throw createProjectOnFirstDeployError({
|
|
1290
|
-
error,
|
|
1291
|
-
inferredName: name,
|
|
1292
|
-
workspaceName: authState.workspace.name
|
|
1293
|
-
});
|
|
1294
|
-
});
|
|
1295
|
-
return {
|
|
1296
|
-
id: project.id,
|
|
1297
|
-
name: project.name,
|
|
1298
|
-
workspace: authState.workspace
|
|
1299
|
-
};
|
|
1300
|
-
} : void 0,
|
|
1301
|
-
allowCreate: options?.allowCreate,
|
|
1302
|
-
prompt: createSelectPromptPort(context),
|
|
1303
|
-
remember: true
|
|
1284
|
+
commandName: options?.commandName
|
|
1304
1285
|
});
|
|
1305
1286
|
const branch = options?.branch ?? await resolveDeployBranch(context, void 0);
|
|
1306
1287
|
return {
|
|
@@ -1316,30 +1297,30 @@ async function resolveDeployProjectContext(context, client, provider, explicitPr
|
|
|
1316
1297
|
if (!workspace) throw workspaceRequiredError();
|
|
1317
1298
|
const branch = options.branch ?? await resolveDeployBranch(context, void 0);
|
|
1318
1299
|
const projects = await listRealWorkspaceProjects(client, workspace);
|
|
1319
|
-
|
|
1320
|
-
const project = await provider.createProject({ name }).catch((error) => {
|
|
1321
|
-
throw createProjectOnFirstDeployError({
|
|
1322
|
-
error,
|
|
1323
|
-
inferredName: name,
|
|
1324
|
-
workspaceName: workspace.name
|
|
1325
|
-
});
|
|
1326
|
-
});
|
|
1327
|
-
return {
|
|
1328
|
-
id: project.id,
|
|
1329
|
-
name: project.name,
|
|
1330
|
-
workspace
|
|
1331
|
-
};
|
|
1332
|
-
} : void 0;
|
|
1333
|
-
if (explicitProject) return withDeployBranch(await resolveProjectTarget({
|
|
1334
|
-
context,
|
|
1300
|
+
if (explicitProject) return withDeployBranch({
|
|
1335
1301
|
workspace,
|
|
1336
|
-
explicitProject,
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1302
|
+
project: toProjectSummary(resolveProjectForSetup(explicitProject, projects, workspace)),
|
|
1303
|
+
resolution: {
|
|
1304
|
+
projectSource: "explicit",
|
|
1305
|
+
targetName: explicitProject,
|
|
1306
|
+
targetNameSource: "explicit"
|
|
1307
|
+
},
|
|
1308
|
+
localPinAction: "linked"
|
|
1309
|
+
}, branch);
|
|
1310
|
+
if (options.createProjectName) {
|
|
1311
|
+
const projectName = options.createProjectName.trim();
|
|
1312
|
+
if (!projectName) throw projectSetupNameRequiredError("app deploy --create-project");
|
|
1313
|
+
return withDeployBranch({
|
|
1314
|
+
workspace,
|
|
1315
|
+
project: toProjectSummary(await createProjectForDeploySetup(provider, projectName, workspace)),
|
|
1316
|
+
resolution: {
|
|
1317
|
+
projectSource: "created",
|
|
1318
|
+
targetName: projectName,
|
|
1319
|
+
targetNameSource: "explicit"
|
|
1320
|
+
},
|
|
1321
|
+
localPinAction: "created"
|
|
1322
|
+
}, branch);
|
|
1323
|
+
}
|
|
1343
1324
|
if (options.envProjectId) {
|
|
1344
1325
|
const project = projects.find((candidate) => candidate.id === options.envProjectId);
|
|
1345
1326
|
if (!project) throw projectNotFoundError(options.envProjectId, workspace);
|
|
@@ -1368,15 +1349,58 @@ async function resolveDeployProjectContext(context, client, provider, explicitPr
|
|
|
1368
1349
|
}
|
|
1369
1350
|
}, branch);
|
|
1370
1351
|
}
|
|
1371
|
-
|
|
1352
|
+
const platformMapping = await resolveDurablePlatformMapping();
|
|
1353
|
+
if (platformMapping && platformMapping.workspace.id === workspace.id) return withDeployBranch({
|
|
1354
|
+
workspace,
|
|
1355
|
+
project: toProjectSummary(platformMapping),
|
|
1356
|
+
resolution: {
|
|
1357
|
+
projectSource: "platform-mapping",
|
|
1358
|
+
targetName: platformMapping.name,
|
|
1359
|
+
targetNameSource: "platform-mapping"
|
|
1360
|
+
}
|
|
1361
|
+
}, branch);
|
|
1362
|
+
if (canPrompt(context) && !context.flags.yes) return withDeployBranch(await resolveInteractiveDeployProjectSetup(context, provider, workspace, projects), branch);
|
|
1363
|
+
throw projectSetupRequiredError(projects, await inferTargetName(context.runtime.cwd));
|
|
1364
|
+
}
|
|
1365
|
+
async function resolveInteractiveDeployProjectSetup(context, provider, workspace, projects) {
|
|
1366
|
+
const setup = await promptForProjectSetupChoice({
|
|
1372
1367
|
context,
|
|
1368
|
+
projects,
|
|
1369
|
+
createProject: (projectName) => createProjectForDeploySetup(provider, projectName, workspace),
|
|
1370
|
+
cancel: {
|
|
1371
|
+
why: "Deploy needs a Project before it can continue.",
|
|
1372
|
+
fix: "Choose an existing Project or create a new one, then rerun deploy.",
|
|
1373
|
+
nextSteps: ["prisma-cli app deploy --project <id-or-name>", "prisma-cli app deploy --create-project <name>"]
|
|
1374
|
+
}
|
|
1375
|
+
});
|
|
1376
|
+
return {
|
|
1373
1377
|
workspace,
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1378
|
+
project: setup.project,
|
|
1379
|
+
resolution: {
|
|
1380
|
+
projectSource: setup.action === "created" ? "created" : "prompt",
|
|
1381
|
+
targetName: setup.targetName,
|
|
1382
|
+
targetNameSource: setup.targetNameSource
|
|
1383
|
+
},
|
|
1384
|
+
localPinAction: setup.action
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
async function createProjectForDeploySetup(provider, projectName, workspace) {
|
|
1388
|
+
const created = await provider.createProject({ name: projectName }).catch((error) => {
|
|
1389
|
+
throw projectCreateFailedError(error, projectName, workspace, {
|
|
1390
|
+
nextSteps: [
|
|
1391
|
+
"prisma-cli project list",
|
|
1392
|
+
"prisma-cli app deploy --project <id-or-name>",
|
|
1393
|
+
`prisma-cli app deploy --create-project ${formatCommandArgument(projectName)}`
|
|
1394
|
+
],
|
|
1395
|
+
permissionFix: "Choose an existing Project with --project, or grant the token permission to create Projects in this workspace.",
|
|
1396
|
+
fallbackFix: "Choose an existing Project with --project, or retry after addressing the platform error above."
|
|
1397
|
+
});
|
|
1398
|
+
});
|
|
1399
|
+
return {
|
|
1400
|
+
id: created.id,
|
|
1401
|
+
name: created.name,
|
|
1402
|
+
workspace
|
|
1403
|
+
};
|
|
1380
1404
|
}
|
|
1381
1405
|
function withDeployBranch(target, branch) {
|
|
1382
1406
|
return {
|
|
@@ -1387,15 +1411,22 @@ function withDeployBranch(target, branch) {
|
|
|
1387
1411
|
}
|
|
1388
1412
|
};
|
|
1389
1413
|
}
|
|
1390
|
-
function toProjectSummary(project) {
|
|
1391
|
-
return {
|
|
1392
|
-
id: project.id,
|
|
1393
|
-
name: project.name
|
|
1394
|
-
};
|
|
1395
|
-
}
|
|
1396
1414
|
function toBranchKind(name) {
|
|
1397
1415
|
return name === "production" || name === "main" ? "production" : "preview";
|
|
1398
1416
|
}
|
|
1417
|
+
function assertExclusiveDeployProjectInputs(options) {
|
|
1418
|
+
const provided = [
|
|
1419
|
+
options.projectRef ? "--project" : null,
|
|
1420
|
+
options.createProjectName ? "--create-project" : null,
|
|
1421
|
+
options.envProjectId ? PRISMA_PROJECT_ID_ENV_VAR : null
|
|
1422
|
+
].filter((value) => Boolean(value));
|
|
1423
|
+
if (provided.length <= 1) return;
|
|
1424
|
+
throw usageError("Project selection is ambiguous", `${provided.join(", ")} cannot be used together.`, "Choose exactly one Project source for this deploy.", [
|
|
1425
|
+
"prisma-cli app deploy --project <id-or-name>",
|
|
1426
|
+
"prisma-cli app deploy --create-project <name>",
|
|
1427
|
+
`unset ${PRISMA_PROJECT_ID_ENV_VAR}`
|
|
1428
|
+
], "project");
|
|
1429
|
+
}
|
|
1399
1430
|
async function resolveDeployBranch(context, explicitBranchName) {
|
|
1400
1431
|
if (explicitBranchName) return {
|
|
1401
1432
|
name: explicitBranchName,
|
|
@@ -1436,15 +1467,12 @@ async function resolveGitHeadPath(gitPath) {
|
|
|
1436
1467
|
}
|
|
1437
1468
|
async function resolveDeployFramework(context, options) {
|
|
1438
1469
|
if (options.requestedFramework) return frameworkFromUserFacingValue(options.requestedFramework, "set by --framework");
|
|
1439
|
-
if (options.
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
annotation: "set by --build-type"
|
|
1446
|
-
};
|
|
1447
|
-
}
|
|
1470
|
+
if (options.entrypoint) return {
|
|
1471
|
+
key: "bun",
|
|
1472
|
+
buildType: "bun",
|
|
1473
|
+
displayName: "Bun",
|
|
1474
|
+
annotation: "set by --entry"
|
|
1475
|
+
};
|
|
1448
1476
|
const detected = await detectDeployFramework(context.runtime.cwd);
|
|
1449
1477
|
if (detected) return detected;
|
|
1450
1478
|
throw frameworkNotDetectedError(context.runtime.cwd);
|
|
@@ -1459,6 +1487,24 @@ function resolveDeployRuntime(requestedHttpPort, framework) {
|
|
|
1459
1487
|
annotation: `${framework.displayName} default`
|
|
1460
1488
|
};
|
|
1461
1489
|
}
|
|
1490
|
+
function assertSupportedEntrypointForRequestedDeployShape(options) {
|
|
1491
|
+
if (!options.requestedFramework) return;
|
|
1492
|
+
assertSupportedEntrypoint(frameworkFromUserFacingValue(options.requestedFramework, "set by --framework").buildType, options.entrypoint, "deploy");
|
|
1493
|
+
}
|
|
1494
|
+
async function resolveDeployEntrypoint(cwd, framework, explicitEntrypoint) {
|
|
1495
|
+
if (explicitEntrypoint || framework.buildType !== "bun") return explicitEntrypoint;
|
|
1496
|
+
const packageEntrypoint = readBunPackageEntrypoint(await readBunPackageJson(cwd));
|
|
1497
|
+
if (packageEntrypoint) return packageEntrypoint;
|
|
1498
|
+
if (framework.key !== "hono") return;
|
|
1499
|
+
const defaultEntrypoint = "src/index.ts";
|
|
1500
|
+
try {
|
|
1501
|
+
await access(path.join(cwd, defaultEntrypoint));
|
|
1502
|
+
return defaultEntrypoint;
|
|
1503
|
+
} catch (error) {
|
|
1504
|
+
if (error.code !== "ENOENT") throw error;
|
|
1505
|
+
return;
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1462
1508
|
async function detectDeployFramework(cwd) {
|
|
1463
1509
|
const packageJson = await readBunPackageJson(cwd);
|
|
1464
1510
|
const nextConfig = await detectNextConfig(cwd);
|
|
@@ -1474,7 +1520,7 @@ async function detectDeployFramework(cwd) {
|
|
|
1474
1520
|
displayName: "Hono",
|
|
1475
1521
|
annotation: "detected from package.json"
|
|
1476
1522
|
};
|
|
1477
|
-
if (
|
|
1523
|
+
if (hasAnyPackageDependency(packageJson, TANSTACK_START_PACKAGES)) return {
|
|
1478
1524
|
key: "tanstack-start",
|
|
1479
1525
|
buildType: "tanstack-start",
|
|
1480
1526
|
displayName: "TanStack Start",
|
|
@@ -1487,7 +1533,8 @@ async function detectNextConfig(cwd) {
|
|
|
1487
1533
|
"next.config.js",
|
|
1488
1534
|
"next.config.mjs",
|
|
1489
1535
|
"next.config.cjs",
|
|
1490
|
-
"next.config.ts"
|
|
1536
|
+
"next.config.ts",
|
|
1537
|
+
"next.config.mts"
|
|
1491
1538
|
]) {
|
|
1492
1539
|
const filePath = path.join(cwd, candidate);
|
|
1493
1540
|
try {
|
|
@@ -1508,6 +1555,9 @@ async function detectNextConfig(cwd) {
|
|
|
1508
1555
|
function hasPackageDependency(packageJson, dependencyName) {
|
|
1509
1556
|
return hasDependency(packageJson?.dependencies, dependencyName) || hasDependency(packageJson?.devDependencies, dependencyName);
|
|
1510
1557
|
}
|
|
1558
|
+
function hasAnyPackageDependency(packageJson, dependencyNames) {
|
|
1559
|
+
return dependencyNames.some((dependencyName) => hasPackageDependency(packageJson, dependencyName));
|
|
1560
|
+
}
|
|
1511
1561
|
function hasDependency(dependencies, dependencyName) {
|
|
1512
1562
|
return Boolean(dependencies && typeof dependencies === "object" && dependencyName in dependencies);
|
|
1513
1563
|
}
|
|
@@ -1527,9 +1577,16 @@ function frameworkFromUserFacingValue(value, annotation) {
|
|
|
1527
1577
|
displayName: "Hono",
|
|
1528
1578
|
annotation
|
|
1529
1579
|
};
|
|
1580
|
+
case "bun": return {
|
|
1581
|
+
key: "bun",
|
|
1582
|
+
buildType: "bun",
|
|
1583
|
+
displayName: "Bun",
|
|
1584
|
+
annotation
|
|
1585
|
+
};
|
|
1530
1586
|
case "tanstack":
|
|
1531
1587
|
case "tanstack-start":
|
|
1532
|
-
case "@tanstack/start":
|
|
1588
|
+
case "@tanstack/react-start":
|
|
1589
|
+
case "@tanstack/solid-start": return {
|
|
1533
1590
|
key: "tanstack-start",
|
|
1534
1591
|
buildType: "tanstack-start",
|
|
1535
1592
|
displayName: "TanStack Start",
|
|
@@ -1539,75 +1596,36 @@ function frameworkFromUserFacingValue(value, annotation) {
|
|
|
1539
1596
|
}
|
|
1540
1597
|
}
|
|
1541
1598
|
function frameworkNotDetectedError(cwd, requestedFramework) {
|
|
1542
|
-
const supported = "Next.js, Hono, TanStack Start";
|
|
1599
|
+
const supported = "Next.js, Hono, TanStack Start, Bun";
|
|
1543
1600
|
const directory = cwd ? ` in ${formatDeployDirectory(cwd)}` : "";
|
|
1544
1601
|
return new CliError({
|
|
1545
1602
|
code: "FRAMEWORK_NOT_DETECTED",
|
|
1546
1603
|
domain: "app",
|
|
1547
1604
|
summary: requestedFramework ? `Unsupported framework "${requestedFramework}"` : `Cannot detect a supported framework${directory}`,
|
|
1548
1605
|
why: `Supported Beta frameworks: ${supported}.`,
|
|
1549
|
-
fix: "Add one of these frameworks as a dependency,
|
|
1606
|
+
fix: "Add one of these frameworks as a dependency, pass --framework <nextjs|hono|tanstack-start|bun>, or pass --entry <path> for a Bun app.",
|
|
1550
1607
|
exitCode: 2,
|
|
1551
1608
|
nextSteps: [
|
|
1552
1609
|
"prisma-cli app deploy --framework nextjs",
|
|
1553
1610
|
"prisma-cli app deploy --framework hono",
|
|
1554
|
-
"prisma-cli app deploy --framework tanstack-start"
|
|
1611
|
+
"prisma-cli app deploy --framework tanstack-start",
|
|
1612
|
+
"prisma-cli app deploy --framework bun --entry server.ts",
|
|
1613
|
+
"prisma-cli app deploy --entry server.ts"
|
|
1555
1614
|
]
|
|
1556
1615
|
});
|
|
1557
1616
|
}
|
|
1558
1617
|
async function maybeRenderDeploySetupBlock(context, details) {
|
|
1559
1618
|
if (context.flags.json || context.flags.quiet) return;
|
|
1560
1619
|
const directory = formatDeployDirectory(context.runtime.cwd);
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
return;
|
|
1564
|
-
}
|
|
1565
|
-
const title = `Setting up your local directory ${formatLocalDirectory(context.runtime.cwd, context.runtime.env)}`;
|
|
1566
|
-
const rows = details.firstDeploy ? [
|
|
1567
|
-
{
|
|
1568
|
-
label: "Workspace",
|
|
1569
|
-
value: details.workspaceName
|
|
1570
|
-
},
|
|
1571
|
-
{
|
|
1572
|
-
label: "Project",
|
|
1573
|
-
value: details.projectName,
|
|
1574
|
-
origin: details.projectAnnotation
|
|
1575
|
-
},
|
|
1576
|
-
{
|
|
1577
|
-
label: "Branch",
|
|
1578
|
-
value: details.branchName,
|
|
1579
|
-
origin: details.branchAnnotation
|
|
1580
|
-
},
|
|
1581
|
-
{
|
|
1582
|
-
label: "App",
|
|
1583
|
-
value: details.appName,
|
|
1584
|
-
origin: details.appAnnotation
|
|
1585
|
-
},
|
|
1586
|
-
{
|
|
1587
|
-
label: "Framework",
|
|
1588
|
-
value: details.framework.displayName,
|
|
1589
|
-
origin: details.framework.annotation
|
|
1590
|
-
},
|
|
1591
|
-
{
|
|
1592
|
-
label: "Runtime",
|
|
1593
|
-
value: `HTTP ${details.runtime.port}`,
|
|
1594
|
-
origin: details.runtime.annotation
|
|
1595
|
-
}
|
|
1596
|
-
] : [];
|
|
1597
|
-
const lines = [
|
|
1598
|
-
title,
|
|
1599
|
-
"",
|
|
1600
|
-
...renderDeployOutputRows(context.ui, rows),
|
|
1601
|
-
""
|
|
1602
|
-
];
|
|
1603
|
-
context.output.stderr.write(`${lines.join("\n")}\n`);
|
|
1620
|
+
const prefix = details.includeDirectory ? `Deploying ${directory} to` : "Deploying to";
|
|
1621
|
+
context.output.stderr.write(`${prefix} ${details.projectName} / ${details.branchName} / ${details.appName}\n\n`);
|
|
1604
1622
|
}
|
|
1605
|
-
function
|
|
1623
|
+
function maybeRenderProjectLinked(context, directory, projectName, localPinPath) {
|
|
1606
1624
|
if (context.flags.json || context.flags.quiet) return;
|
|
1607
|
-
context.output.stderr.write(
|
|
1625
|
+
context.output.stderr.write(`${context.ui.success("✔")} Linked "${directory}" to Project "${projectName}"\nSaved ${localPinPath}\n\n`);
|
|
1608
1626
|
}
|
|
1609
1627
|
async function maybeCustomizeDeploySettings(context, options) {
|
|
1610
|
-
if (!options.firstDeploy || context.flags.yes || options.explicitFramework || options.
|
|
1628
|
+
if (!options.firstDeploy || context.flags.yes || options.explicitFramework || options.explicitEntrypoint || options.explicitHttpPort || !canPrompt(context)) return {
|
|
1611
1629
|
framework: options.framework,
|
|
1612
1630
|
runtime: options.runtime
|
|
1613
1631
|
};
|
|
@@ -1659,24 +1677,12 @@ async function maybeCustomizeDeploySettings(context, options) {
|
|
|
1659
1677
|
runtime
|
|
1660
1678
|
};
|
|
1661
1679
|
}
|
|
1662
|
-
function annotationForProjectResolution(resolution) {
|
|
1663
|
-
switch (resolution.projectSource) {
|
|
1664
|
-
case "explicit": return "set by --project";
|
|
1665
|
-
case "env": return `from ${PRISMA_PROJECT_ID_ENV_VAR}`;
|
|
1666
|
-
case "local-pin": return "from local pin";
|
|
1667
|
-
case "created": return resolution.targetNameSource === "directory-name" ? "created from directory name" : "created from package.json";
|
|
1668
|
-
case "package-name":
|
|
1669
|
-
case "directory-name": return "linked to existing project";
|
|
1670
|
-
case "platform-mapping":
|
|
1671
|
-
case "remembered-local": return "linked to existing project";
|
|
1672
|
-
case "prompt": return "selected by you";
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1675
1680
|
function frameworkDisplayName(framework) {
|
|
1676
1681
|
switch (framework) {
|
|
1677
1682
|
case "nextjs": return "Next.js";
|
|
1678
1683
|
case "hono": return "Hono";
|
|
1679
1684
|
case "tanstack-start": return "TanStack Start";
|
|
1685
|
+
case "bun": return "Bun";
|
|
1680
1686
|
}
|
|
1681
1687
|
}
|
|
1682
1688
|
function validateDeployHttpPortText(value) {
|
|
@@ -1692,15 +1698,6 @@ function formatDeployDirectory(cwd) {
|
|
|
1692
1698
|
const basename = path.basename(cwd);
|
|
1693
1699
|
return basename ? `./${basename}` : ".";
|
|
1694
1700
|
}
|
|
1695
|
-
function formatLocalDirectory(cwd, env) {
|
|
1696
|
-
const resolved = path.resolve(cwd);
|
|
1697
|
-
const home = env.HOME ? path.resolve(env.HOME) : null;
|
|
1698
|
-
if (home && (resolved === home || resolved.startsWith(`${home}${path.sep}`))) {
|
|
1699
|
-
const relative = path.relative(home, resolved);
|
|
1700
|
-
return relative ? `~/${relative}` : "~";
|
|
1701
|
-
}
|
|
1702
|
-
return resolved;
|
|
1703
|
-
}
|
|
1704
1701
|
async function readCurrentWorkspaceId(context) {
|
|
1705
1702
|
const state = await context.stateStore.read();
|
|
1706
1703
|
if (state.auth?.workspaceId) return state.auth.workspaceId;
|
|
@@ -1720,7 +1717,10 @@ function getBuildTypeExamples(commandName) {
|
|
|
1720
1717
|
});
|
|
1721
1718
|
}
|
|
1722
1719
|
function assertSupportedEntrypoint(buildType, entrypoint, commandName) {
|
|
1723
|
-
if (buildType !== "auto" && buildType !== "bun" && entrypoint)
|
|
1720
|
+
if (buildType !== "auto" && buildType !== "bun" && entrypoint) {
|
|
1721
|
+
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");
|
|
1722
|
+
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");
|
|
1723
|
+
}
|
|
1724
1724
|
}
|
|
1725
1725
|
async function requireLocalBuildType(context, buildType, commandName) {
|
|
1726
1726
|
const resolvedBuildType = await resolveLocalBuildType(context.runtime.cwd, buildType);
|
|
@@ -1761,24 +1761,41 @@ function deployFailedError(summary, error, nextSteps) {
|
|
|
1761
1761
|
function appDeployFailedError(error, progress) {
|
|
1762
1762
|
const why = error instanceof Error ? error.message : String(error);
|
|
1763
1763
|
const debug = formatDebugDetails(error);
|
|
1764
|
-
if (progress.buildStarted && !progress.buildCompleted)
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
"",
|
|
1775
|
-
|
|
1776
|
-
"",
|
|
1777
|
-
|
|
1778
|
-
]
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1764
|
+
if (progress.buildStarted && !progress.buildCompleted) {
|
|
1765
|
+
const standaloneOutputFailure = isNextStandaloneOutputFailure(why);
|
|
1766
|
+
const fix = standaloneOutputFailure ? "Add output: \"standalone\" to next.config.*, then rerun deploy." : "Inspect the build output above, fix the error, and redeploy.";
|
|
1767
|
+
const nextSteps = standaloneOutputFailure ? ["Add output: \"standalone\" to next.config.*, then rerun prisma-cli app deploy"] : [];
|
|
1768
|
+
const nextActions = standaloneOutputFailure ? [{
|
|
1769
|
+
kind: "edit-file",
|
|
1770
|
+
journey: "deploy-app",
|
|
1771
|
+
label: "Add Next.js standalone output",
|
|
1772
|
+
reason: "Prisma Compute needs Next.js standalone output to build a deployable server artifact."
|
|
1773
|
+
}, {
|
|
1774
|
+
kind: "run-command",
|
|
1775
|
+
journey: "deploy-app",
|
|
1776
|
+
label: "Rerun deploy",
|
|
1777
|
+
command: "prisma-cli app deploy"
|
|
1778
|
+
}] : [];
|
|
1779
|
+
return new CliError({
|
|
1780
|
+
code: "BUILD_FAILED",
|
|
1781
|
+
domain: "app",
|
|
1782
|
+
summary: "Build failed locally.",
|
|
1783
|
+
why,
|
|
1784
|
+
fix,
|
|
1785
|
+
debug,
|
|
1786
|
+
meta: { phase: "build" },
|
|
1787
|
+
humanLines: [
|
|
1788
|
+
"Build failed locally.",
|
|
1789
|
+
"",
|
|
1790
|
+
`✗ Built ${why}`,
|
|
1791
|
+
"",
|
|
1792
|
+
`Fix: ${fix}`
|
|
1793
|
+
],
|
|
1794
|
+
exitCode: 1,
|
|
1795
|
+
nextSteps,
|
|
1796
|
+
nextActions
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1782
1799
|
if (!progress.buildStarted) return deployFailedError("App deploy failed", error, ["prisma-cli app deploy"]);
|
|
1783
1800
|
const phaseHeadline = progress.containerLive ? "The deployment started, but the app is not ready yet." : "Deploy failed after the build completed.";
|
|
1784
1801
|
const recoveryLines = progress.versionId ? ["See what happened", `prisma-cli app logs --deployment ${progress.versionId}`] : ["Fix", "Retry the command, or rerun with --trace for more detailed diagnostics."];
|
|
@@ -1825,61 +1842,52 @@ function localResolutionPinStaleError() {
|
|
|
1825
1842
|
domain: "project",
|
|
1826
1843
|
summary: "Local project binding is stale",
|
|
1827
1844
|
why: `The target recorded in ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH} is no longer available in the selected workspace.`,
|
|
1828
|
-
fix: `Delete ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH}
|
|
1845
|
+
fix: `Delete ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH}, then choose a Project explicitly.`,
|
|
1829
1846
|
meta: { pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH },
|
|
1830
1847
|
exitCode: 1,
|
|
1831
|
-
nextSteps: [
|
|
1848
|
+
nextSteps: [
|
|
1849
|
+
"prisma-cli project list",
|
|
1850
|
+
"prisma-cli project link <id-or-name>",
|
|
1851
|
+
"prisma-cli app deploy --project <id-or-name>"
|
|
1852
|
+
]
|
|
1832
1853
|
});
|
|
1833
1854
|
}
|
|
1834
1855
|
function readDeployEnvOverride(context, name) {
|
|
1835
1856
|
const value = context.runtime.env[name]?.trim();
|
|
1836
1857
|
return value ? value : void 0;
|
|
1837
1858
|
}
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
* existing project matches the package.json name (or the cwd basename as a
|
|
1841
|
-
* fallback). When the create call fails the user often doesn't realise the
|
|
1842
|
-
* CLI was attempting to create a project at all — they thought the deploy
|
|
1843
|
-
* would find an existing project. Surface that context, and recommend the
|
|
1844
|
-
* explicit `--project` flag as the unambiguous way out.
|
|
1845
|
-
*/
|
|
1846
|
-
function createProjectOnFirstDeployError(options) {
|
|
1847
|
-
const { error, inferredName, workspaceName } = options;
|
|
1848
|
-
const status = extractHttpStatus(error);
|
|
1849
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1850
|
-
const inferredContext = `No existing project matched the package.json name \`${inferredName}\`, so the CLI attempted to create one.`;
|
|
1851
|
-
const nextSteps = ["prisma-cli project list", "prisma-cli app deploy --project <id-or-name>"];
|
|
1852
|
-
if (status === 401 || status === 403) return new CliError({
|
|
1853
|
-
code: "AUTH_FORBIDDEN",
|
|
1854
|
-
domain: "auth",
|
|
1855
|
-
summary: "Could not create a new project for this deploy",
|
|
1856
|
-
why: `${inferredContext} The platform rejected the create (HTTP ${status}).`,
|
|
1857
|
-
fix: `Pass --project <id-or-name> to deploy into an existing project, or grant the service token project-create permission on workspace \`${workspaceName}\`.`,
|
|
1858
|
-
debug: formatDebugDetails(error),
|
|
1859
|
-
exitCode: 1,
|
|
1860
|
-
nextSteps
|
|
1861
|
-
});
|
|
1859
|
+
function projectSetupRequiredError(projects, suggestedName) {
|
|
1860
|
+
const createCommand = `prisma-cli app deploy --create-project ${formatCommandArgument(suggestedName.name)}`;
|
|
1862
1861
|
return new CliError({
|
|
1863
|
-
code: "
|
|
1864
|
-
domain: "
|
|
1865
|
-
summary: "
|
|
1866
|
-
why:
|
|
1867
|
-
fix: "
|
|
1868
|
-
|
|
1862
|
+
code: "PROJECT_SETUP_REQUIRED",
|
|
1863
|
+
domain: "project",
|
|
1864
|
+
summary: "Choose a Project before deploying this directory",
|
|
1865
|
+
why: "This directory is not linked to a Prisma Project, and deploy will not choose or create one implicitly.",
|
|
1866
|
+
fix: "Choose an existing Project with --project, create one with --create-project, or rerun interactively to pick from the setup list.",
|
|
1867
|
+
meta: {
|
|
1868
|
+
candidates: sortProjects(projects).map((project) => ({
|
|
1869
|
+
id: project.id,
|
|
1870
|
+
name: project.name
|
|
1871
|
+
})),
|
|
1872
|
+
suggestedProjectName: suggestedName.name,
|
|
1873
|
+
suggestedProjectNameSource: suggestedName.source,
|
|
1874
|
+
recoveryCommands: ["prisma-cli app deploy --project <id-or-name>", createCommand]
|
|
1875
|
+
},
|
|
1869
1876
|
exitCode: 1,
|
|
1870
|
-
nextSteps
|
|
1877
|
+
nextSteps: [
|
|
1878
|
+
"prisma-cli project list",
|
|
1879
|
+
"prisma-cli app deploy --project <id-or-name>",
|
|
1880
|
+
createCommand
|
|
1881
|
+
],
|
|
1882
|
+
nextActions: buildProjectSetupNextActions({
|
|
1883
|
+
commandName: "app deploy",
|
|
1884
|
+
createCommand,
|
|
1885
|
+
reason: "This directory is not linked to a Prisma Project. Ask the user which Project to use before deploying; package and directory names are setup suggestions only."
|
|
1886
|
+
})
|
|
1871
1887
|
});
|
|
1872
1888
|
}
|
|
1873
|
-
function
|
|
1874
|
-
|
|
1875
|
-
const candidate = error;
|
|
1876
|
-
if (typeof candidate.statusCode === "number") return candidate.statusCode;
|
|
1877
|
-
if (typeof candidate.status === "number") return candidate.status;
|
|
1878
|
-
if (typeof candidate.message === "string") {
|
|
1879
|
-
const match = /\(HTTP (\d{3})\)/.exec(candidate.message);
|
|
1880
|
-
if (match) return Number.parseInt(match[1], 10);
|
|
1881
|
-
}
|
|
1882
|
-
return null;
|
|
1889
|
+
function isNextStandaloneOutputFailure(message) {
|
|
1890
|
+
return /next\.?js/i.test(message) && /standalone output/i.test(message);
|
|
1883
1891
|
}
|
|
1884
1892
|
function noDeploymentsError(summary, why) {
|
|
1885
1893
|
return new CliError({
|