@prisma/cli 3.0.0-dev.88.1 → 3.0.0-dev.91.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/dist/commands/app/index.js +2 -2
- package/dist/controllers/app-env.js +1 -1
- package/dist/controllers/app.js +35 -28
- package/dist/controllers/project.js +3 -3
- package/dist/lib/app/app-interaction.js +5 -0
- package/dist/lib/app/{preview-provider.js → app-provider.js} +9 -9
- package/dist/lib/app/{preview-branch-database.js → branch-database-api.js} +1 -1
- package/dist/lib/app/build-settings.js +93 -0
- package/dist/lib/app/build.js +80 -0
- package/dist/lib/app/bun-project.js +2 -3
- package/dist/lib/app/{preview-progress.js → deploy-progress.js} +5 -5
- package/dist/lib/app/read-branch.js +30 -0
- package/package.json +2 -2
- package/dist/lib/app/preview-build-settings.js +0 -376
- package/dist/lib/app/preview-build.js +0 -501
- package/dist/lib/app/preview-interaction.js +0 -5
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { usageError } from "../../shell/errors.js";
|
|
2
|
+
import { APP_BUILD_TYPES } from "../../lib/app/build.js";
|
|
2
3
|
import { attachCommandDescriptor } from "../../shell/command-meta.js";
|
|
3
4
|
import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
|
|
4
5
|
import { configureRuntimeCommand } from "../../shell/runtime.js";
|
|
5
|
-
import { PREVIEW_BUILD_TYPES } from "../../lib/app/preview-build.js";
|
|
6
6
|
import { runAppBuild, runAppDeploy, runAppDomainAdd, runAppDomainRemove, runAppDomainRetry, runAppDomainShow, runAppDomainWait, runAppListDeploys, runAppLogs, runAppOpen, runAppPromote, runAppRemove, runAppRollback, runAppRun, runAppShow, runAppShowDeploy } from "../../controllers/app.js";
|
|
7
7
|
import { isAppDeployAllResult, renderAppBuild, renderAppDeploy, renderAppDeployAll, renderAppDomainAdd, renderAppDomainRemove, renderAppDomainRetry, renderAppDomainShow, renderAppListDeploys, renderAppOpen, renderAppPromote, renderAppRemove, renderAppRollback, renderAppRun, renderAppShow, renderAppShowDeploy, serializeAppBuild, serializeAppDeploy, serializeAppDeployAll, serializeAppDomainAdd, serializeAppDomainRemove, serializeAppDomainRetry, serializeAppDomainShow, serializeAppListDeploys, serializeAppOpen, serializeAppPromote, serializeAppRemove, serializeAppRollback, serializeAppRun, serializeAppShow, serializeAppShowDeploy } from "../../presenters/app.js";
|
|
8
8
|
import { runCommand, runStreamingCommand } from "../../shell/command-runner.js";
|
|
@@ -28,7 +28,7 @@ function createAppCommand(runtime) {
|
|
|
28
28
|
}
|
|
29
29
|
function createBuildCommand(runtime) {
|
|
30
30
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("build"), runtime), "app.build");
|
|
31
|
-
command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps").addOption(new Option("--entry <path>", "Entrypoint path for Bun or auto builds")).addOption(new Option("--build-type <type>", "Local build type").choices([...
|
|
31
|
+
command.argument("[app]", "App target from prisma.compute.ts when the config defines multiple apps").addOption(new Option("--entry <path>", "Entrypoint path for Bun or auto builds")).addOption(new Option("--build-type <type>", "Local build type").choices([...APP_BUILD_TYPES]).default("auto"));
|
|
32
32
|
addGlobalFlags(command);
|
|
33
33
|
command.action(async (configTarget, options) => {
|
|
34
34
|
const entry = options.entry;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CliError, authRequiredError, usageError, workspaceRequiredError } from "../shell/errors.js";
|
|
2
|
-
import { projectResolutionErrorToCliError, resolveProjectTarget } from "../lib/project/resolution.js";
|
|
3
2
|
import { formatScopeLabel, parseKeyValuePositional, resolveEnvScope } from "../lib/app/env-config.js";
|
|
4
3
|
import { readEnvFileAssignments } from "../lib/app/env-file.js";
|
|
4
|
+
import { projectResolutionErrorToCliError, resolveProjectTarget } from "../lib/project/resolution.js";
|
|
5
5
|
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
6
6
|
import { readLocalGitBranch } from "../lib/git/local-branch.js";
|
|
7
7
|
import { requireAuthenticatedAuthState } from "./auth.js";
|
package/dist/controllers/app.js
CHANGED
|
@@ -2,6 +2,11 @@ import { SERVICE_TOKEN_ENV_VAR, getApiBaseUrl } from "../lib/auth/client.js";
|
|
|
2
2
|
import { FileTokenStorage } from "../adapters/token-storage.js";
|
|
3
3
|
import { CliError, authRequiredError, featureUnavailableError, usageError, workspaceRequiredError } from "../shell/errors.js";
|
|
4
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";
|
|
5
10
|
import { renderCommandHeader } from "../shell/ui.js";
|
|
6
11
|
import { canPrompt } from "../shell/runtime.js";
|
|
7
12
|
import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, readLocalResolutionPin } from "../lib/project/local-pin.js";
|
|
@@ -13,15 +18,11 @@ import { readBunPackageEntrypoint, readBunPackageJson } from "../lib/app/bun-pro
|
|
|
13
18
|
import { COMPUTE_CONFIG_FILENAME as COMPUTE_CONFIG_FILENAME$1, ComputeConfigTargetRequiredError, computeConfigErrorToCliError, computeFrameworkToBuildType, computeTargetAppDir, inferComputeTargetFromCwd, loadComputeConfig as loadComputeConfig$1, mergeComputeDeployInputs, mergeComputeLocalInputs, selectComputeDeployTarget } from "../lib/app/compute-config.js";
|
|
14
19
|
import { renderDeployOutputRows, renderDeploySettingsPreview } from "../lib/app/deploy-output.js";
|
|
15
20
|
import { describeDeployAllFailure, perAppInputsForDeployAll, planAppDeploy } from "../lib/app/deploy-plan.js";
|
|
21
|
+
import { createDeployProgress, createDeployProgressState, createPromoteProgress } from "../lib/app/deploy-progress.js";
|
|
16
22
|
import { formatDomainFailureFix } from "../lib/app/domain-guidance.js";
|
|
17
|
-
import { envVarNames, parseEnvInputs } from "../lib/app/env-vars.js";
|
|
18
23
|
import { DEFAULT_LOCAL_DEV_PORT, runLocalApp } from "../lib/app/local-dev.js";
|
|
19
|
-
import { PRISMA_APP_CONFIG_FILENAME, detectLegacyBuildSettings, resolveConfiguredPreviewBuildSettings, resolveInferredPreviewBuildSettings } from "../lib/app/preview-build-settings.js";
|
|
20
|
-
import { PREVIEW_BUILD_TYPES, RESOLVED_PREVIEW_BUILD_TYPES, executePreviewBuild } from "../lib/app/preview-build.js";
|
|
21
|
-
import { PREVIEW_DEFAULT_REGION } from "../lib/app/preview-interaction.js";
|
|
22
|
-
import { createPreviewDeployProgress, createPreviewDeployProgressState, createPreviewPromoteProgress } from "../lib/app/preview-progress.js";
|
|
23
|
-
import { PreviewDomainApiError, createPreviewAppProvider } from "../lib/app/preview-provider.js";
|
|
24
24
|
import { enforceProductionDeployGate } from "../lib/app/production-deploy-gate.js";
|
|
25
|
+
import { resolveReadBranch } from "../lib/app/read-branch.js";
|
|
25
26
|
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
26
27
|
import { readAuthState } from "../lib/auth/auth-ops.js";
|
|
27
28
|
import { readLocalGitBranch } from "../lib/git/local-branch.js";
|
|
@@ -60,7 +61,7 @@ async function runAppBuild(context, options) {
|
|
|
60
61
|
}
|
|
61
62
|
assertSupportedEntrypoint(buildType, merged.entrypoint, "build");
|
|
62
63
|
if (compute.target?.build && buildType !== "auto") assertConfigBackedBuildSettings(buildType);
|
|
63
|
-
const buildSettings = compute.config && compute.target?.build && isConfigBackedBuildType(buildType) ? (await
|
|
64
|
+
const buildSettings = compute.config && compute.target?.build && isConfigBackedBuildType(buildType) ? (await resolveConfiguredAppBuildSettings({
|
|
64
65
|
appPath: appDir,
|
|
65
66
|
buildType,
|
|
66
67
|
configured: compute.target.build,
|
|
@@ -68,7 +69,7 @@ async function runAppBuild(context, options) {
|
|
|
68
69
|
signal: context.runtime.signal
|
|
69
70
|
})).settings : void 0;
|
|
70
71
|
try {
|
|
71
|
-
const { artifact, buildType: actualBuildType } = await
|
|
72
|
+
const { artifact, buildType: actualBuildType } = await executeAppBuild({
|
|
72
73
|
appPath: appDir,
|
|
73
74
|
entrypoint: merged.entrypoint,
|
|
74
75
|
buildType,
|
|
@@ -86,7 +87,7 @@ async function runAppBuild(context, options) {
|
|
|
86
87
|
nextSteps: ["prisma-cli app deploy"]
|
|
87
88
|
};
|
|
88
89
|
} catch (error) {
|
|
89
|
-
if (buildType === "auto" && isAutoBuildDetectionError(error)) throw usageError("App build requires an explicit framework when detection is ambiguous", `This preview auto-detects clear project shapes for ${
|
|
90
|
+
if (buildType === "auto" && isAutoBuildDetectionError(error)) throw usageError("App build requires an explicit framework when detection is ambiguous", `This preview auto-detects clear project shapes for ${RESOLVED_APP_BUILD_TYPES.map(formatBuildTypeName).join(", ")}.`, "Pass a supported --build-type value, or pass --entry <path> for a Bun app.", getBuildTypeExamples("build"), "app");
|
|
90
91
|
throw buildFailedError("Local app build failed", error);
|
|
91
92
|
}
|
|
92
93
|
}
|
|
@@ -328,13 +329,13 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
328
329
|
assertSupportedEntrypoint(buildType, merged.entrypoint?.value, "deploy");
|
|
329
330
|
const entrypoint = await resolveDeployEntrypoint(appDir, framework, merged.entrypoint?.value, context.runtime.signal);
|
|
330
331
|
if (computeConfig.target?.build) assertConfigBackedBuildSettings(buildType);
|
|
331
|
-
const buildSettingsResolution = computeConfig.config && computeConfig.target?.build && isConfigBackedBuildType(buildType) ? await
|
|
332
|
+
const buildSettingsResolution = computeConfig.config && computeConfig.target?.build && isConfigBackedBuildType(buildType) ? await resolveConfiguredAppBuildSettings({
|
|
332
333
|
appPath: appDir,
|
|
333
334
|
buildType,
|
|
334
335
|
configured: computeConfig.target.build,
|
|
335
336
|
configPath: computeConfig.config.configPath,
|
|
336
337
|
signal: context.runtime.signal
|
|
337
|
-
}) : await
|
|
338
|
+
}) : await resolveInferredAppBuildSettings({
|
|
338
339
|
appPath: appDir,
|
|
339
340
|
buildType,
|
|
340
341
|
signal: context.runtime.signal
|
|
@@ -348,7 +349,7 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
348
349
|
firstProductionDeploy: productionDeployGate.firstProductionDeploy,
|
|
349
350
|
projectDir
|
|
350
351
|
});
|
|
351
|
-
const progressState =
|
|
352
|
+
const progressState = createDeployProgressState();
|
|
352
353
|
const deployStartedAt = Date.now();
|
|
353
354
|
const deployResult = await provider.deployApp({
|
|
354
355
|
cwd: appDir,
|
|
@@ -364,7 +365,7 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
|
|
|
364
365
|
envVars,
|
|
365
366
|
interaction: void 0,
|
|
366
367
|
signal: context.runtime.signal,
|
|
367
|
-
progress:
|
|
368
|
+
progress: createDeployProgress(context.output.stderr, context.ui, !context.flags.json && !context.flags.quiet, progressState)
|
|
368
369
|
}).catch((error) => {
|
|
369
370
|
throw appDeployFailedError(error, progressState);
|
|
370
371
|
});
|
|
@@ -866,7 +867,7 @@ async function runAppPromote(context, deploymentId, appName, projectRef, configT
|
|
|
866
867
|
appId: selectedApp.id,
|
|
867
868
|
deploymentId: targetDeployment.id,
|
|
868
869
|
signal: context.runtime.signal,
|
|
869
|
-
progress:
|
|
870
|
+
progress: createPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
|
|
870
871
|
}).catch((error) => {
|
|
871
872
|
throw deployFailedError("Failed to promote deployment", error, ["prisma-cli app list-deploys"]);
|
|
872
873
|
});
|
|
@@ -914,7 +915,7 @@ async function runAppRollback(context, appName, deploymentId, projectRef, config
|
|
|
914
915
|
appId: selectedApp.id,
|
|
915
916
|
deploymentId: targetDeployment.id,
|
|
916
917
|
signal: context.runtime.signal,
|
|
917
|
-
progress:
|
|
918
|
+
progress: createPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
|
|
918
919
|
}).catch((error) => {
|
|
919
920
|
throw deployFailedError("Failed to roll back deployment", error, ["prisma-cli app list-deploys"]);
|
|
920
921
|
});
|
|
@@ -1106,7 +1107,7 @@ async function confirmDomainRemoval(context, target, hostname) {
|
|
|
1106
1107
|
})) throw usageError("Custom domain removal canceled", "The command was canceled before the domain was detached.", "Rerun the command and confirm removal, or pass --yes.", [`prisma-cli app domain remove ${hostname} --app ${target.app.name} --yes`], "app");
|
|
1107
1108
|
}
|
|
1108
1109
|
function domainCommandError(command, error, hostname) {
|
|
1109
|
-
if (error instanceof
|
|
1110
|
+
if (error instanceof DomainApiError) {
|
|
1110
1111
|
if (command === "add" && (error.status === 400 || error.status === 422) && isDomainDnsError(error)) return domainDnsNotConfiguredError(hostname, error);
|
|
1111
1112
|
if (command === "add" && error.status === 400) return new CliError({
|
|
1112
1113
|
code: "DOMAIN_HOSTNAME_INVALID",
|
|
@@ -1287,7 +1288,7 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
|
|
|
1287
1288
|
};
|
|
1288
1289
|
return {
|
|
1289
1290
|
appName: options.explicitAppName,
|
|
1290
|
-
region:
|
|
1291
|
+
region: DEFAULT_REGION,
|
|
1291
1292
|
displayName: options.explicitAppName,
|
|
1292
1293
|
annotation: "set by --app",
|
|
1293
1294
|
firstDeploy: options.firstDeploy
|
|
@@ -1316,7 +1317,7 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
|
|
|
1316
1317
|
};
|
|
1317
1318
|
return {
|
|
1318
1319
|
appName: configName.value,
|
|
1319
|
-
region:
|
|
1320
|
+
region: DEFAULT_REGION,
|
|
1320
1321
|
displayName: configName.value,
|
|
1321
1322
|
annotation: configName.annotation,
|
|
1322
1323
|
firstDeploy: options.firstDeploy
|
|
@@ -1334,7 +1335,7 @@ async function resolveDeployAppSelection(context, projectId, apps, options) {
|
|
|
1334
1335
|
};
|
|
1335
1336
|
return {
|
|
1336
1337
|
appName: inferredName.name,
|
|
1337
|
-
region:
|
|
1338
|
+
region: DEFAULT_REGION,
|
|
1338
1339
|
displayName: inferredName.name,
|
|
1339
1340
|
annotation: inferredName.source === "package-name" ? "created from package.json" : "created from directory name",
|
|
1340
1341
|
firstDeploy: options.firstDeploy
|
|
@@ -1366,7 +1367,7 @@ async function resolveAmbiguousDeployApp(context, matches, targetName, firstDepl
|
|
|
1366
1367
|
if (selected === cancel) throw usageError("App selection canceled", "The command was canceled before an app was selected.", "Re-run the command and choose an app, or pass --app <name>.", ["prisma-cli app deploy --app <name>"], "app");
|
|
1367
1368
|
if (selected === createNew) return {
|
|
1368
1369
|
appName: targetName,
|
|
1369
|
-
region:
|
|
1370
|
+
region: DEFAULT_REGION,
|
|
1370
1371
|
displayName: targetName,
|
|
1371
1372
|
annotation: "created from package.json",
|
|
1372
1373
|
firstDeploy
|
|
@@ -1531,7 +1532,7 @@ async function requirePreviewAppProviderWithClient(context) {
|
|
|
1531
1532
|
if (!client) throw authRequiredError(["prisma-cli auth login"]);
|
|
1532
1533
|
return {
|
|
1533
1534
|
client,
|
|
1534
|
-
provider:
|
|
1535
|
+
provider: createAppProvider(client, createPreviewLogAuthOptions(context.runtime.env, context.runtime.signal))
|
|
1535
1536
|
};
|
|
1536
1537
|
}
|
|
1537
1538
|
function createPreviewLogAuthOptions(env, signal) {
|
|
@@ -1584,13 +1585,18 @@ async function resolveProjectContext(context, client, explicitProject, options)
|
|
|
1584
1585
|
});
|
|
1585
1586
|
if (resolvedResult.isErr()) throw projectResolutionErrorToCliError(resolvedResult.error);
|
|
1586
1587
|
const resolved = resolvedResult.value;
|
|
1587
|
-
const
|
|
1588
|
+
const requested = options?.branch ?? await resolveDeployBranch(context, void 0);
|
|
1589
|
+
const remoteBranch = options?.branch ? null : await resolveReadBranch(client, {
|
|
1590
|
+
projectId: resolved.project.id,
|
|
1591
|
+
branchName: requested.name,
|
|
1592
|
+
signal: context.runtime.signal
|
|
1593
|
+
});
|
|
1588
1594
|
return {
|
|
1589
1595
|
...resolved,
|
|
1590
|
-
branch: {
|
|
1596
|
+
branch: remoteBranch ?? {
|
|
1591
1597
|
id: null,
|
|
1592
|
-
name:
|
|
1593
|
-
kind: toBranchKind(
|
|
1598
|
+
name: requested.name,
|
|
1599
|
+
kind: toBranchKind(requested.name)
|
|
1594
1600
|
}
|
|
1595
1601
|
};
|
|
1596
1602
|
}
|
|
@@ -2139,13 +2145,13 @@ async function readCurrentWorkspaceId(context) {
|
|
|
2139
2145
|
function normalizeBuildType(requestedBuildType) {
|
|
2140
2146
|
if (!requestedBuildType) return "auto";
|
|
2141
2147
|
if (isPreviewBuildType(requestedBuildType)) return requestedBuildType;
|
|
2142
|
-
throw usageError(`Unsupported build type "${requestedBuildType}"`, `Only ${
|
|
2148
|
+
throw usageError(`Unsupported build type "${requestedBuildType}"`, `Only ${APP_BUILD_TYPES.join(", ")} are supported in the current preview.`, "Pass a supported --build-type value.", getBuildTypeExamples("build"), "app");
|
|
2143
2149
|
}
|
|
2144
2150
|
function isPreviewBuildType(value) {
|
|
2145
|
-
return
|
|
2151
|
+
return APP_BUILD_TYPES.includes(value);
|
|
2146
2152
|
}
|
|
2147
2153
|
function getBuildTypeExamples(commandName) {
|
|
2148
|
-
return
|
|
2154
|
+
return RESOLVED_APP_BUILD_TYPES.map((buildType) => {
|
|
2149
2155
|
return `prisma-cli app ${commandName} --build-type ${buildType}${buildType === "bun" ? " --entry server.ts" : ""}`;
|
|
2150
2156
|
});
|
|
2151
2157
|
}
|
|
@@ -2389,6 +2395,7 @@ function formatBuildTypeName(buildType) {
|
|
|
2389
2395
|
case "nextjs": return "Next.js";
|
|
2390
2396
|
case "nuxt": return "Nuxt";
|
|
2391
2397
|
case "astro": return "Astro";
|
|
2398
|
+
case "nestjs": return "NestJS";
|
|
2392
2399
|
case "tanstack-start": return "TanStack Start";
|
|
2393
2400
|
case "bun": return "Bun";
|
|
2394
2401
|
case "auto": return "Auto";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { CliError, authRequiredError, featureUnavailableError, usageError, workspaceRequiredError } from "../shell/errors.js";
|
|
2
|
+
import { createAppProvider } from "../lib/app/app-provider.js";
|
|
2
3
|
import { renderSummaryLine } from "../shell/ui.js";
|
|
3
4
|
import { canPrompt } from "../shell/runtime.js";
|
|
4
5
|
import { readLocalResolutionPin } from "../lib/project/local-pin.js";
|
|
5
6
|
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
6
7
|
import { buildProjectSetupNextActions, inferTargetName, inspectProjectBinding, projectResolutionErrorToCliError, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
|
|
7
8
|
import { bindProjectToDirectory, isValidProjectSetupName, projectCreateFailedError, projectDirectoryBindingErrorToCliError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
|
|
8
|
-
import { createPreviewAppProvider } from "../lib/app/preview-provider.js";
|
|
9
9
|
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
10
10
|
import { promptForProjectSetupChoice } from "../lib/project/interactive-setup.js";
|
|
11
11
|
import { createCliUseCaseGateways } from "../use-cases/create-cli-gateways.js";
|
|
@@ -104,7 +104,7 @@ async function runProjectCreate(context, projectName) {
|
|
|
104
104
|
if (!isRealMode(context)) throw featureUnavailableError("Project create is not available in fixture mode", "Creating Projects requires live platform integration.", "Rerun without fixture mode enabled to create a Project.", ["prisma-cli auth login"], "project");
|
|
105
105
|
const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
|
|
106
106
|
if (!client) throw authRequiredError();
|
|
107
|
-
const provider =
|
|
107
|
+
const provider = createAppProvider(client);
|
|
108
108
|
const name = projectName.trim();
|
|
109
109
|
const created = await provider.createProject({
|
|
110
110
|
name,
|
|
@@ -136,7 +136,7 @@ async function runProjectLink(context, projectRef) {
|
|
|
136
136
|
if (isRealMode(context)) {
|
|
137
137
|
const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
|
|
138
138
|
if (!client) throw authRequiredError();
|
|
139
|
-
provider =
|
|
139
|
+
provider = createAppProvider(client);
|
|
140
140
|
projects = await listRealWorkspaceProjects(client, workspace, context.runtime.signal);
|
|
141
141
|
} else projects = listFixtureWorkspaceProjects(context, workspace);
|
|
142
142
|
let result;
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
+
import { createBranchDatabase, createEnvironmentVariable, deleteBranchDatabase, deleteEnvironmentVariable, listEnvironmentVariables, updateEnvironmentVariable } from "./branch-database-api.js";
|
|
2
|
+
import { AppBuildStrategy } from "./build.js";
|
|
1
3
|
import { envVarNames } from "./env-vars.js";
|
|
2
|
-
import { PreviewBuildStrategy } from "./preview-build.js";
|
|
3
|
-
import { createBranchDatabase, createEnvironmentVariable, deleteBranchDatabase, deleteEnvironmentVariable, listEnvironmentVariables, updateEnvironmentVariable } from "./preview-branch-database.js";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { ApiError, CancelledError, ComputeClient, streamLogs } from "@prisma/compute-sdk";
|
|
6
|
-
//#region src/lib/app/
|
|
7
|
-
var
|
|
6
|
+
//#region src/lib/app/app-provider.ts
|
|
7
|
+
var DomainApiError = class extends Error {
|
|
8
8
|
status;
|
|
9
9
|
code;
|
|
10
10
|
hint;
|
|
11
11
|
constructor(options) {
|
|
12
12
|
super(`${options.summary}: ${options.message}${options.hint ? ` ${options.hint}` : ""}`);
|
|
13
|
-
this.name = "
|
|
13
|
+
this.name = "DomainApiError";
|
|
14
14
|
this.status = options.status;
|
|
15
15
|
this.code = options.code ?? null;
|
|
16
16
|
this.hint = options.hint ?? null;
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
|
-
function
|
|
19
|
+
function createAppProvider(client, options) {
|
|
20
20
|
const sdk = new ComputeClient(client);
|
|
21
21
|
return {
|
|
22
22
|
async createProject(options) {
|
|
@@ -161,7 +161,7 @@ function createPreviewAppProvider(client, options) {
|
|
|
161
161
|
region: options.region
|
|
162
162
|
};
|
|
163
163
|
const deployResult = await sdk.deploy({
|
|
164
|
-
strategy: new
|
|
164
|
+
strategy: new AppBuildStrategy({
|
|
165
165
|
appPath: path.resolve(options.cwd),
|
|
166
166
|
entrypoint: options.entrypoint,
|
|
167
167
|
buildType: options.buildType,
|
|
@@ -491,7 +491,7 @@ function apiCallError(summary, response, error) {
|
|
|
491
491
|
return /* @__PURE__ */ new Error(`${summary}: ${message}${hint}`);
|
|
492
492
|
}
|
|
493
493
|
function domainApiCallError(summary, response, error) {
|
|
494
|
-
return new
|
|
494
|
+
return new DomainApiError({
|
|
495
495
|
summary,
|
|
496
496
|
status: response.status,
|
|
497
497
|
code: error.error?.code ?? null,
|
|
@@ -541,4 +541,4 @@ function toAbsoluteUrl(url) {
|
|
|
541
541
|
return url.startsWith("https://") || url.startsWith("http://") ? url : `https://${url}`;
|
|
542
542
|
}
|
|
543
543
|
//#endregion
|
|
544
|
-
export {
|
|
544
|
+
export { DomainApiError, createAppProvider };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { resolveBuildSettings, resolveConfiguredBuildSettings } from "@prisma/compute-sdk";
|
|
4
|
+
//#region src/lib/app/build-settings.ts
|
|
5
|
+
/** Legacy build-settings file: no longer read or written, only detected for migration. */
|
|
6
|
+
const PRISMA_APP_CONFIG_FILENAME = "prisma.app.json";
|
|
7
|
+
/**
|
|
8
|
+
* Detects a leftover `prisma.app.json`. The file is no longer used: one that
|
|
9
|
+
* matches the effective settings is reported for deletion, one with custom
|
|
10
|
+
* values must be migrated to the compute config so builds never silently
|
|
11
|
+
* change.
|
|
12
|
+
*/
|
|
13
|
+
async function detectLegacyBuildSettings(options) {
|
|
14
|
+
const configPath = path.join(options.appPath, PRISMA_APP_CONFIG_FILENAME);
|
|
15
|
+
let content;
|
|
16
|
+
try {
|
|
17
|
+
options.signal?.throwIfAborted();
|
|
18
|
+
content = await readFile(configPath, {
|
|
19
|
+
encoding: "utf8",
|
|
20
|
+
signal: options.signal
|
|
21
|
+
});
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (options.signal?.aborted) throw error;
|
|
24
|
+
return { kind: "absent" };
|
|
25
|
+
}
|
|
26
|
+
let legacy;
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(content);
|
|
29
|
+
const buildCommand = parsed.buildCommand === null || typeof parsed.buildCommand === "string" ? typeof parsed.buildCommand === "string" ? parsed.buildCommand.trim() || null : null : void 0;
|
|
30
|
+
const outputDirectory = typeof parsed.outputDirectory === "string" ? normalizeRelativePath(parsed.outputDirectory) : void 0;
|
|
31
|
+
if (buildCommand === void 0 || !outputDirectory) return {
|
|
32
|
+
kind: "invalid",
|
|
33
|
+
configPath
|
|
34
|
+
};
|
|
35
|
+
legacy = {
|
|
36
|
+
buildCommand,
|
|
37
|
+
outputDirectory
|
|
38
|
+
};
|
|
39
|
+
} catch {
|
|
40
|
+
return {
|
|
41
|
+
kind: "invalid",
|
|
42
|
+
configPath
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return legacy.buildCommand === options.effective.buildCommand && legacy.outputDirectory === options.effective.outputDirectory ? {
|
|
46
|
+
kind: "matching",
|
|
47
|
+
configPath
|
|
48
|
+
} : {
|
|
49
|
+
kind: "custom",
|
|
50
|
+
configPath,
|
|
51
|
+
...legacy
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** Resolves build settings purely from framework inference; nothing is read or written. */
|
|
55
|
+
async function resolveInferredAppBuildSettings(options) {
|
|
56
|
+
return {
|
|
57
|
+
status: "inferred",
|
|
58
|
+
configPath: null,
|
|
59
|
+
relativeConfigPath: null,
|
|
60
|
+
settings: await resolveBuildSettings(options)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Resolves build settings when the compute config owns them: configured
|
|
65
|
+
* fields win, omitted fields fall back to framework defaults.
|
|
66
|
+
*/
|
|
67
|
+
async function resolveConfiguredAppBuildSettings(options) {
|
|
68
|
+
const configFilename = path.basename(options.configPath);
|
|
69
|
+
const settings = await resolveConfiguredBuildSettings({
|
|
70
|
+
appPath: options.appPath,
|
|
71
|
+
buildType: options.buildType,
|
|
72
|
+
configured: options.configured,
|
|
73
|
+
source: `set by ${configFilename}`,
|
|
74
|
+
signal: options.signal
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
status: "config",
|
|
78
|
+
configPath: options.configPath,
|
|
79
|
+
relativeConfigPath: configFilename,
|
|
80
|
+
settings
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function normalizeRelativePath(value) {
|
|
84
|
+
const raw = value.trim().replace(/\\/g, "/");
|
|
85
|
+
if (raw.length === 0 || raw.split("/").includes("..")) return;
|
|
86
|
+
if (/^[A-Za-z]:/.test(raw)) return;
|
|
87
|
+
const normalized = path.posix.normalize(raw);
|
|
88
|
+
const segments = normalized.split("/");
|
|
89
|
+
if (path.win32.isAbsolute(value) || path.posix.isAbsolute(normalized) || segments.includes("..")) return;
|
|
90
|
+
return normalized === "." ? "." : normalized;
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
export { PRISMA_APP_CONFIG_FILENAME, detectLegacyBuildSettings, resolveConfiguredAppBuildSettings, resolveInferredAppBuildSettings };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import "./build-settings.js";
|
|
2
|
+
import "node:fs/promises";
|
|
3
|
+
import "node:path";
|
|
4
|
+
import { normalizeArtifactSymlinks, resolveBuildStrategy } from "@prisma/compute-sdk";
|
|
5
|
+
//#region src/lib/app/build.ts
|
|
6
|
+
const APP_BUILD_TYPES = [
|
|
7
|
+
"auto",
|
|
8
|
+
"bun",
|
|
9
|
+
"nextjs",
|
|
10
|
+
"nuxt",
|
|
11
|
+
"astro",
|
|
12
|
+
"nestjs",
|
|
13
|
+
"tanstack-start"
|
|
14
|
+
];
|
|
15
|
+
const RESOLVED_APP_BUILD_TYPES = APP_BUILD_TYPES.filter((buildType) => buildType !== "auto");
|
|
16
|
+
var AppBuildStrategy = class {
|
|
17
|
+
#appPath;
|
|
18
|
+
#entrypoint;
|
|
19
|
+
#buildType;
|
|
20
|
+
#signal;
|
|
21
|
+
#buildSettings;
|
|
22
|
+
constructor(options) {
|
|
23
|
+
this.#appPath = options.appPath;
|
|
24
|
+
this.#entrypoint = options.entrypoint;
|
|
25
|
+
this.#buildType = options.buildType ?? "auto";
|
|
26
|
+
this.#signal = options.signal;
|
|
27
|
+
this.#buildSettings = options.buildSettings;
|
|
28
|
+
}
|
|
29
|
+
async canBuild(signal = this.#signal) {
|
|
30
|
+
const { strategy } = await resolveAppBuildStrategy({
|
|
31
|
+
appPath: this.#appPath,
|
|
32
|
+
entrypoint: this.#entrypoint,
|
|
33
|
+
buildType: this.#buildType,
|
|
34
|
+
signal,
|
|
35
|
+
buildSettings: this.#buildSettings
|
|
36
|
+
});
|
|
37
|
+
return strategy.canBuild(signal);
|
|
38
|
+
}
|
|
39
|
+
async execute(signal = this.#signal) {
|
|
40
|
+
const { artifact } = await executeAppBuild({
|
|
41
|
+
appPath: this.#appPath,
|
|
42
|
+
entrypoint: this.#entrypoint,
|
|
43
|
+
buildType: this.#buildType,
|
|
44
|
+
signal,
|
|
45
|
+
buildSettings: this.#buildSettings
|
|
46
|
+
});
|
|
47
|
+
return artifact;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
async function executeAppBuild(options) {
|
|
51
|
+
const { strategy, buildType } = await resolveAppBuildStrategy({
|
|
52
|
+
appPath: options.appPath,
|
|
53
|
+
entrypoint: options.entrypoint,
|
|
54
|
+
buildType: options.buildType ?? "auto",
|
|
55
|
+
signal: options.signal,
|
|
56
|
+
buildSettings: options.buildSettings
|
|
57
|
+
});
|
|
58
|
+
const artifact = await strategy.execute(options.signal);
|
|
59
|
+
try {
|
|
60
|
+
await normalizeArtifactSymlinks(artifact.directory, options.appPath, options.signal);
|
|
61
|
+
return {
|
|
62
|
+
artifact,
|
|
63
|
+
buildType
|
|
64
|
+
};
|
|
65
|
+
} catch (error) {
|
|
66
|
+
await artifact.cleanup?.().catch(() => void 0);
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function resolveAppBuildStrategy(options) {
|
|
71
|
+
return resolveBuildStrategy({
|
|
72
|
+
appPath: options.appPath,
|
|
73
|
+
buildType: options.buildType,
|
|
74
|
+
entrypoint: options.entrypoint,
|
|
75
|
+
buildSettings: options.buildSettings,
|
|
76
|
+
signal: options.signal
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { APP_BUILD_TYPES, AppBuildStrategy, RESOLVED_APP_BUILD_TYPES, executeAppBuild };
|
|
@@ -21,13 +21,12 @@ async function readBunPackageJson(appPath, signal) {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
function readBunPackageEntrypoint(packageJson) {
|
|
24
|
-
|
|
25
|
-
if (typeof packageJson?.module === "string") return packageJson.module;
|
|
24
|
+
return typeof packageJson?.main === "string" ? packageJson.main : void 0;
|
|
26
25
|
}
|
|
27
26
|
async function resolveBunEntrypoint(appPath, explicitEntrypoint, signal) {
|
|
28
27
|
const packageJson = await readBunPackageJson(appPath, signal);
|
|
29
28
|
const candidate = explicitEntrypoint ?? readBunPackageEntrypoint(packageJson);
|
|
30
|
-
if (!candidate) throw new Error("Entrypoint is required. Pass --entry or define package.json main
|
|
29
|
+
if (!candidate) throw new Error("Entrypoint is required. Pass --entry or define package.json main.");
|
|
31
30
|
if (path.isAbsolute(candidate)) throw new Error("Entrypoint must be a relative path.");
|
|
32
31
|
const normalized = path.normalize(candidate);
|
|
33
32
|
if (normalized.startsWith("..") || path.isAbsolute(normalized) || normalized.includes(`${path.sep}..${path.sep}`)) throw new Error("Entrypoint must not escape the app directory.");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { renderDeployOutputRows } from "./deploy-output.js";
|
|
2
|
-
//#region src/lib/app/
|
|
3
|
-
function
|
|
2
|
+
//#region src/lib/app/deploy-progress.ts
|
|
3
|
+
function createDeployProgressState() {
|
|
4
4
|
return {
|
|
5
5
|
buildStarted: false,
|
|
6
6
|
buildCompleted: false,
|
|
@@ -13,7 +13,7 @@ function createPreviewDeployProgressState() {
|
|
|
13
13
|
promotedUrl: null
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
-
function
|
|
16
|
+
function createDeployProgress(output, ui, enabled, state = createDeployProgressState()) {
|
|
17
17
|
const write = (line) => {
|
|
18
18
|
if (!enabled) return;
|
|
19
19
|
output.write(`${line}\n`);
|
|
@@ -63,7 +63,7 @@ function createPreviewDeployProgress(output, ui, enabled, state = createPreviewD
|
|
|
63
63
|
function formatArtifactSize(byteLength) {
|
|
64
64
|
return `${(byteLength / 1024 / 1024).toFixed(1)} MB`;
|
|
65
65
|
}
|
|
66
|
-
function
|
|
66
|
+
function createPromoteProgress(output, enabled) {
|
|
67
67
|
if (!enabled) return;
|
|
68
68
|
const write = (line) => {
|
|
69
69
|
output.write(`${line}\n`);
|
|
@@ -97,4 +97,4 @@ function createPreviewPromoteProgress(output, enabled) {
|
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
99
|
//#endregion
|
|
100
|
-
export {
|
|
100
|
+
export { createDeployProgress, createDeployProgressState, createPromoteProgress };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/lib/app/read-branch.ts
|
|
2
|
+
/**
|
|
3
|
+
* Resolves the branch an app management command should read from, without ever
|
|
4
|
+
* creating one. Returns the branch whose `gitName` matches `branchName`, else
|
|
5
|
+
* the project's default branch, else null when the project has no branches.
|
|
6
|
+
*/
|
|
7
|
+
async function resolveReadBranch(client, options) {
|
|
8
|
+
const branches = [];
|
|
9
|
+
let cursor;
|
|
10
|
+
do {
|
|
11
|
+
const result = await client.GET("/v1/projects/{projectId}/branches", {
|
|
12
|
+
params: {
|
|
13
|
+
path: { projectId: options.projectId },
|
|
14
|
+
query: { cursor }
|
|
15
|
+
},
|
|
16
|
+
signal: options.signal
|
|
17
|
+
});
|
|
18
|
+
if (result.error || !result.data) throw new Error(`Failed to list branches for project ${options.projectId}: ${JSON.stringify(result.error)}`);
|
|
19
|
+
branches.push(...result.data.data);
|
|
20
|
+
cursor = result.data.pagination.hasMore ? result.data.pagination.nextCursor ?? void 0 : void 0;
|
|
21
|
+
} while (cursor);
|
|
22
|
+
const chosen = branches.find((branch) => branch.gitName === options.branchName) ?? branches.find((branch) => branch.isDefault) ?? null;
|
|
23
|
+
return chosen ? {
|
|
24
|
+
id: chosen.id,
|
|
25
|
+
name: chosen.gitName,
|
|
26
|
+
kind: chosen.role
|
|
27
|
+
} : null;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { resolveReadBranch };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/cli",
|
|
3
|
-
"version": "3.0.0-dev.
|
|
3
|
+
"version": "3.0.0-dev.91.1",
|
|
4
4
|
"description": "Command-line interface for the Prisma Developer Platform.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@clack/prompts": "^1.5.0",
|
|
47
|
-
"@prisma/compute-sdk": "^0.
|
|
47
|
+
"@prisma/compute-sdk": "^0.28.0",
|
|
48
48
|
"@prisma/credentials-store": "^7.8.0",
|
|
49
49
|
"@prisma/management-api-sdk": "^1.37.0",
|
|
50
50
|
"better-result": "^2.9.2",
|