@prisma/cli 3.0.0-dev.99.1 → 8.0.0-rc.10-dev.80
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 +26 -28
- package/dist/cli.js +14551 -16
- package/dist/payload-B88Qvzxk-CrtTXSOe.js +34 -0
- package/dist/sender.js +192 -0
- package/package.json +26 -19
- package/dist/adapters/git.js +0 -54
- package/dist/adapters/local-state.js +0 -144
- package/dist/adapters/mock-api.js +0 -136
- package/dist/adapters/token-storage.js +0 -418
- package/dist/cli2.js +0 -119
- package/dist/commands/app/index.js +0 -345
- package/dist/commands/auth/index.js +0 -96
- package/dist/commands/branch/index.js +0 -27
- package/dist/commands/database/index.js +0 -159
- package/dist/commands/env.js +0 -99
- package/dist/commands/git/index.js +0 -36
- package/dist/commands/project/index.js +0 -69
- package/dist/commands/version/index.js +0 -18
- package/dist/controllers/app-env-api.js +0 -54
- package/dist/controllers/app-env-file.js +0 -181
- package/dist/controllers/app-env.js +0 -502
- package/dist/controllers/app.js +0 -2443
- package/dist/controllers/auth.js +0 -316
- package/dist/controllers/branch.js +0 -103
- package/dist/controllers/database.js +0 -318
- package/dist/controllers/project.js +0 -731
- package/dist/controllers/select-prompt-port.js +0 -12
- package/dist/controllers/version.js +0 -12
- package/dist/lib/app/app-interaction.js +0 -5
- package/dist/lib/app/app-provider.js +0 -544
- package/dist/lib/app/branch-database-api.js +0 -102
- package/dist/lib/app/branch-database-deploy.js +0 -325
- package/dist/lib/app/branch-database.js +0 -215
- package/dist/lib/app/build-settings.js +0 -93
- package/dist/lib/app/build.js +0 -80
- package/dist/lib/app/bun-project.js +0 -45
- package/dist/lib/app/compute-config.js +0 -147
- package/dist/lib/app/deploy-output.js +0 -24
- package/dist/lib/app/deploy-plan.js +0 -58
- package/dist/lib/app/deploy-progress.js +0 -100
- package/dist/lib/app/domain-guidance.js +0 -14
- package/dist/lib/app/env-config.js +0 -67
- package/dist/lib/app/env-file.js +0 -82
- package/dist/lib/app/env-vars.js +0 -50
- package/dist/lib/app/local-dev.js +0 -109
- package/dist/lib/app/production-deploy-gate.js +0 -161
- package/dist/lib/app/read-branch.js +0 -30
- package/dist/lib/auth/auth-ops.js +0 -158
- package/dist/lib/auth/client.js +0 -22
- package/dist/lib/auth/guard.js +0 -38
- package/dist/lib/auth/login.js +0 -330
- package/dist/lib/database/provider.js +0 -167
- package/dist/lib/diagnostics.js +0 -15
- package/dist/lib/fs/home-path.js +0 -24
- package/dist/lib/git/local-branch.js +0 -53
- package/dist/lib/git/local-status.js +0 -57
- package/dist/lib/project/interactive-setup.js +0 -56
- package/dist/lib/project/local-pin.js +0 -200
- package/dist/lib/project/resolution.js +0 -386
- package/dist/lib/project/setup.js +0 -135
- package/dist/lib/version.js +0 -55
- package/dist/output/patterns.js +0 -90
- package/dist/presenters/app-env.js +0 -265
- package/dist/presenters/app.js +0 -646
- package/dist/presenters/auth.js +0 -183
- package/dist/presenters/branch.js +0 -46
- package/dist/presenters/database.js +0 -274
- package/dist/presenters/project.js +0 -174
- package/dist/presenters/verbose-context.js +0 -64
- package/dist/presenters/version.js +0 -29
- package/dist/shell/command-arguments.js +0 -6
- package/dist/shell/command-meta.js +0 -622
- package/dist/shell/command-runner.js +0 -112
- package/dist/shell/diagnostics-output.js +0 -57
- package/dist/shell/errors.js +0 -134
- package/dist/shell/global-flags.js +0 -37
- package/dist/shell/help.js +0 -89
- package/dist/shell/output.js +0 -82
- package/dist/shell/prompt.js +0 -41
- package/dist/shell/runtime.js +0 -55
- package/dist/shell/ui.js +0 -116
- package/dist/shell/update-check.js +0 -247
- 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/lib/app/build.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
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 };
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { access, readFile } from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
//#region src/lib/app/bun-project.ts
|
|
4
|
-
async function readBunPackageJson(appPath, signal) {
|
|
5
|
-
const packageJsonPath = path.join(appPath, "package.json");
|
|
6
|
-
let content;
|
|
7
|
-
signal?.throwIfAborted();
|
|
8
|
-
try {
|
|
9
|
-
content = await readFile(packageJsonPath, {
|
|
10
|
-
encoding: "utf8",
|
|
11
|
-
signal
|
|
12
|
-
});
|
|
13
|
-
} catch (error) {
|
|
14
|
-
if (error.code === "ENOENT") return null;
|
|
15
|
-
throw new Error(`Failed to read ${packageJsonPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
16
|
-
}
|
|
17
|
-
try {
|
|
18
|
-
return JSON.parse(content);
|
|
19
|
-
} catch (error) {
|
|
20
|
-
throw new Error(`Failed to parse ${packageJsonPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
function readBunPackageEntrypoint(packageJson) {
|
|
24
|
-
return typeof packageJson?.main === "string" ? packageJson.main : void 0;
|
|
25
|
-
}
|
|
26
|
-
async function resolveBunEntrypoint(appPath, explicitEntrypoint, signal) {
|
|
27
|
-
const packageJson = await readBunPackageJson(appPath, signal);
|
|
28
|
-
const candidate = explicitEntrypoint ?? readBunPackageEntrypoint(packageJson);
|
|
29
|
-
if (!candidate) throw new Error("Entrypoint is required. Pass --entry or define package.json main.");
|
|
30
|
-
if (path.isAbsolute(candidate)) throw new Error("Entrypoint must be a relative path.");
|
|
31
|
-
const normalized = path.normalize(candidate);
|
|
32
|
-
if (normalized.startsWith("..") || path.isAbsolute(normalized) || normalized.includes(`${path.sep}..${path.sep}`)) throw new Error("Entrypoint must not escape the app directory.");
|
|
33
|
-
const entrypointPath = path.join(appPath, normalized);
|
|
34
|
-
signal?.throwIfAborted();
|
|
35
|
-
try {
|
|
36
|
-
await access(entrypointPath);
|
|
37
|
-
signal?.throwIfAborted();
|
|
38
|
-
} catch (error) {
|
|
39
|
-
if (signal?.aborted) throw error;
|
|
40
|
-
throw new Error(`Entrypoint file does not exist: ${entrypointPath}`);
|
|
41
|
-
}
|
|
42
|
-
return normalized.split(path.sep).join("/");
|
|
43
|
-
}
|
|
44
|
-
//#endregion
|
|
45
|
-
export { readBunPackageEntrypoint, readBunPackageJson, resolveBunEntrypoint };
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { CliError } from "../../shell/errors.js";
|
|
2
|
-
import { COMPUTE_CONFIG_FILENAME, COMPUTE_CONFIG_FILENAME as COMPUTE_CONFIG_FILENAME$1, ComputeConfigTargetRequiredError, computeTargetAppDir, frameworkByKey, inferComputeTargetFromCwd, loadComputeConfig, selectComputeDeployTarget } from "@prisma/compute-sdk/config";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { matchError } from "better-result";
|
|
5
|
-
//#region src/lib/app/compute-config.ts
|
|
6
|
-
/**
|
|
7
|
-
* Loads the nearest compute config, searching from `cwd` up to the source
|
|
8
|
-
* root (repository or workspace boundary). Thin adapter over the SDK loader
|
|
9
|
-
* keeping the CLI's positional-signal call shape.
|
|
10
|
-
*/
|
|
11
|
-
async function loadComputeConfig$1(cwd, signal) {
|
|
12
|
-
return loadComputeConfig(cwd, { signal });
|
|
13
|
-
}
|
|
14
|
-
/** Local build/run strategy implied by a configured framework. */
|
|
15
|
-
function computeFrameworkToBuildType(framework) {
|
|
16
|
-
return frameworkByKey(framework).buildType;
|
|
17
|
-
}
|
|
18
|
-
function mergeComputeDeployInputs(options) {
|
|
19
|
-
const { cli, target, configFilename } = options;
|
|
20
|
-
const configAnnotation = `set by ${configFilename}`;
|
|
21
|
-
const framework = cli.framework ? {
|
|
22
|
-
value: cli.framework,
|
|
23
|
-
annotation: "set by --framework"
|
|
24
|
-
} : target?.framework ? {
|
|
25
|
-
value: target.framework,
|
|
26
|
-
annotation: configAnnotation
|
|
27
|
-
} : void 0;
|
|
28
|
-
const entrypoint = cli.entrypoint ? {
|
|
29
|
-
value: cli.entrypoint,
|
|
30
|
-
annotation: "set by --entry"
|
|
31
|
-
} : target?.entry ? {
|
|
32
|
-
value: target.entry,
|
|
33
|
-
annotation: configAnnotation
|
|
34
|
-
} : void 0;
|
|
35
|
-
const httpPort = cli.httpPort ? {
|
|
36
|
-
value: cli.httpPort,
|
|
37
|
-
annotation: "set by --http-port"
|
|
38
|
-
} : target?.httpPort ? {
|
|
39
|
-
value: String(target.httpPort),
|
|
40
|
-
annotation: configAnnotation
|
|
41
|
-
} : void 0;
|
|
42
|
-
const cliEnvInputs = cli.envInputs && cli.envInputs.length > 0 ? cli.envInputs : void 0;
|
|
43
|
-
const configEnvInputs = target && target.envInputs.length > 0 ? target.envInputs : void 0;
|
|
44
|
-
const envInputs = cliEnvInputs ?? configEnvInputs;
|
|
45
|
-
const configAppName = target?.name ? {
|
|
46
|
-
value: target.name,
|
|
47
|
-
annotation: configAnnotation
|
|
48
|
-
} : target?.key ? {
|
|
49
|
-
value: target.key,
|
|
50
|
-
annotation: configAnnotation
|
|
51
|
-
} : void 0;
|
|
52
|
-
return {
|
|
53
|
-
framework,
|
|
54
|
-
entrypoint,
|
|
55
|
-
httpPort,
|
|
56
|
-
envInputs,
|
|
57
|
-
envInputsFromConfig: !cliEnvInputs && configEnvInputs !== void 0,
|
|
58
|
-
configAppName,
|
|
59
|
-
appRoot: target?.root ?? void 0
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Merges CLI inputs for the local `app build` and `app run` commands with a
|
|
64
|
-
* selected config target. Explicit flags win; `--build-type auto` is the
|
|
65
|
-
* flag default and defers to the configured framework.
|
|
66
|
-
*/
|
|
67
|
-
function mergeComputeLocalInputs(options) {
|
|
68
|
-
const { cli, target } = options;
|
|
69
|
-
const cliBuildType = cli.buildType && cli.buildType !== "auto" ? cli.buildType : void 0;
|
|
70
|
-
const configBuildType = target?.framework ? computeFrameworkToBuildType(target.framework) : void 0;
|
|
71
|
-
return {
|
|
72
|
-
entrypoint: cli.entrypoint ?? target?.entry ?? void 0,
|
|
73
|
-
buildType: cliBuildType ?? configBuildType,
|
|
74
|
-
buildTypeFromConfig: !cliBuildType && configBuildType !== void 0,
|
|
75
|
-
port: cli.port ?? (target?.httpPort ? String(target.httpPort) : void 0),
|
|
76
|
-
appRoot: target?.root ?? void 0
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
function computeConfigErrorToCliError(error, commandName = "deploy") {
|
|
80
|
-
const command = `prisma-cli app ${commandName}`;
|
|
81
|
-
return matchError(error, {
|
|
82
|
-
ComputeConfigAmbiguousError: (ambiguous) => new CliError({
|
|
83
|
-
code: "COMPUTE_CONFIG_INVALID",
|
|
84
|
-
domain: "app",
|
|
85
|
-
summary: "Multiple compute config files found",
|
|
86
|
-
why: ambiguous.message,
|
|
87
|
-
fix: `Keep exactly one compute config file, preferably ${COMPUTE_CONFIG_FILENAME}.`,
|
|
88
|
-
meta: { configPaths: ambiguous.configPaths },
|
|
89
|
-
exitCode: 2,
|
|
90
|
-
nextSteps: [command]
|
|
91
|
-
}),
|
|
92
|
-
ComputeConfigLoadError: (load) => new CliError({
|
|
93
|
-
code: "COMPUTE_CONFIG_INVALID",
|
|
94
|
-
domain: "app",
|
|
95
|
-
summary: `Could not load ${path.basename(load.configPath)}`,
|
|
96
|
-
why: load.message,
|
|
97
|
-
fix: `Fix the error in ${path.basename(load.configPath)} and rerun the command.`,
|
|
98
|
-
where: load.configPath,
|
|
99
|
-
meta: { configPath: load.configPath },
|
|
100
|
-
exitCode: 2,
|
|
101
|
-
nextSteps: [command]
|
|
102
|
-
}),
|
|
103
|
-
ComputeConfigInvalidError: (invalid) => new CliError({
|
|
104
|
-
code: "COMPUTE_CONFIG_INVALID",
|
|
105
|
-
domain: "app",
|
|
106
|
-
summary: `Invalid ${path.basename(invalid.configPath)}`,
|
|
107
|
-
why: invalid.issues.join(" "),
|
|
108
|
-
fix: `Edit ${path.basename(invalid.configPath)} so it default-exports defineComputeConfig({ app }) or defineComputeConfig({ apps }).`,
|
|
109
|
-
where: invalid.configPath,
|
|
110
|
-
meta: {
|
|
111
|
-
configPath: invalid.configPath,
|
|
112
|
-
issues: invalid.issues
|
|
113
|
-
},
|
|
114
|
-
exitCode: 2,
|
|
115
|
-
nextSteps: [command]
|
|
116
|
-
}),
|
|
117
|
-
ComputeConfigTargetRequiredError: (required) => new CliError({
|
|
118
|
-
code: "COMPUTE_CONFIG_TARGET_REQUIRED",
|
|
119
|
-
domain: "app",
|
|
120
|
-
summary: "App target required",
|
|
121
|
-
why: required.message,
|
|
122
|
-
fix: `Pass the app target, for example ${command} <target>.`,
|
|
123
|
-
meta: {
|
|
124
|
-
configPath: required.configPath,
|
|
125
|
-
availableTargets: required.availableTargets
|
|
126
|
-
},
|
|
127
|
-
exitCode: 2,
|
|
128
|
-
nextSteps: required.availableTargets.map((target) => `${command} ${target}`)
|
|
129
|
-
}),
|
|
130
|
-
ComputeConfigTargetUnknownError: (unknown) => new CliError({
|
|
131
|
-
code: "COMPUTE_CONFIG_TARGET_UNKNOWN",
|
|
132
|
-
domain: "app",
|
|
133
|
-
summary: `Unknown app target "${unknown.requestedTarget}"`,
|
|
134
|
-
why: unknown.message,
|
|
135
|
-
fix: unknown.availableTargets.length > 0 ? `Pass one of the configured targets: ${unknown.availableTargets.join(", ")}.` : "Remove the target argument; this config defines a single app.",
|
|
136
|
-
meta: {
|
|
137
|
-
configPath: unknown.configPath,
|
|
138
|
-
requestedTarget: unknown.requestedTarget,
|
|
139
|
-
availableTargets: unknown.availableTargets
|
|
140
|
-
},
|
|
141
|
-
exitCode: 2,
|
|
142
|
-
nextSteps: unknown.availableTargets.length > 0 ? unknown.availableTargets.map((target) => `${command} ${target}`) : [command]
|
|
143
|
-
})
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
//#endregion
|
|
147
|
-
export { COMPUTE_CONFIG_FILENAME$1 as COMPUTE_CONFIG_FILENAME, ComputeConfigTargetRequiredError, computeConfigErrorToCliError, computeFrameworkToBuildType, computeTargetAppDir, inferComputeTargetFromCwd, loadComputeConfig$1 as loadComputeConfig, mergeComputeDeployInputs, mergeComputeLocalInputs, selectComputeDeployTarget };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { padDisplay } from "../../shell/ui.js";
|
|
2
|
-
//#region src/lib/app/deploy-output.ts
|
|
3
|
-
const DEPLOY_OUTPUT_MIN_LABEL_WIDTH = 9;
|
|
4
|
-
const DEPLOY_OUTPUT_MIN_VALUE_WIDTH = 9;
|
|
5
|
-
const DEPLOY_SETTINGS_MIN_KEY_WIDTH = 10;
|
|
6
|
-
function renderDeployOutputRows(ui, rows) {
|
|
7
|
-
if (rows.length === 0) return [];
|
|
8
|
-
const labelWidth = Math.max(DEPLOY_OUTPUT_MIN_LABEL_WIDTH, ...rows.map((row) => row.label.length));
|
|
9
|
-
const valueWidth = Math.max(DEPLOY_OUTPUT_MIN_VALUE_WIDTH, ...rows.map((row) => row.value?.length ?? 0));
|
|
10
|
-
return rows.map((row) => {
|
|
11
|
-
if (!row.value) return ` ${row.label}`;
|
|
12
|
-
return ` ${padDisplay(row.label, labelWidth)} ${padDisplay(ui.strong(row.value), valueWidth)}${row.origin ? ` ${ui.dim(`· ${row.origin}`)}` : ""}`.trimEnd();
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
function renderDeploySettingsPreview(ui, rows) {
|
|
16
|
-
if (rows.length === 0) return [];
|
|
17
|
-
const keyWidth = Math.max(DEPLOY_SETTINGS_MIN_KEY_WIDTH, ...rows.map((row) => `${row.key}:`.length));
|
|
18
|
-
const rail = ui.dim("│");
|
|
19
|
-
return rows.map((row) => {
|
|
20
|
-
return `${rail} ${ui.accent(padDisplay(`${row.key}:`, keyWidth))} ${ui.strong(row.value)}`;
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
//#endregion
|
|
24
|
-
export { renderDeployOutputRows, renderDeploySettingsPreview };
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
//#region src/lib/app/deploy-plan.ts
|
|
2
|
-
/**
|
|
3
|
-
* Decides whether a deploy covers one app or the whole system. A multi-app
|
|
4
|
-
* config with no target named or inferred deploys every target in declaration
|
|
5
|
-
* order; everything else (single-app config, an explicit/inferred target, or
|
|
6
|
-
* no config at all) is a single deploy.
|
|
7
|
-
*/
|
|
8
|
-
function planAppDeploy(options) {
|
|
9
|
-
const { config, requestedTarget, hasCreateProject } = options;
|
|
10
|
-
if (!(config !== null && config.kind === "multi" && !requestedTarget && config.targets.length > 1)) return { mode: "single" };
|
|
11
|
-
const total = config.targets.length;
|
|
12
|
-
return {
|
|
13
|
-
mode: "all",
|
|
14
|
-
targets: config.targets.map((target, index) => ({
|
|
15
|
-
targetKey: target.key,
|
|
16
|
-
index,
|
|
17
|
-
total,
|
|
18
|
-
bindsCreateProject: index === 0 && hasCreateProject
|
|
19
|
-
}))
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Names the per-app inputs present in a deploy-all invocation, in the order
|
|
24
|
-
* they should be reported. An empty list means the run is unambiguous; the
|
|
25
|
-
* caller renders the usage error when it is not.
|
|
26
|
-
*/
|
|
27
|
-
function perAppInputsForDeployAll(inputs) {
|
|
28
|
-
return [
|
|
29
|
-
["--app", inputs.appName],
|
|
30
|
-
["--framework", inputs.framework],
|
|
31
|
-
["--entry", inputs.entrypoint],
|
|
32
|
-
["--http-port", inputs.httpPort],
|
|
33
|
-
["--env", inputs.envAssignments?.length ? inputs.envAssignments : void 0],
|
|
34
|
-
[inputs.appIdEnvVar.name, inputs.appIdEnvVar.value]
|
|
35
|
-
].filter(([, value]) => value !== void 0).map(([flag]) => flag);
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Describes a deploy-all run that stopped at the first failing target: which
|
|
39
|
-
* targets already went live and which were never attempted, so the caller can
|
|
40
|
-
* surface a converge path. Pure; the caller folds this into the CliError.
|
|
41
|
-
*/
|
|
42
|
-
function describeDeployAllFailure(options) {
|
|
43
|
-
const { targetKeys, failedIndex, completed } = options;
|
|
44
|
-
const failedTarget = targetKeys[failedIndex];
|
|
45
|
-
const notAttempted = targetKeys.slice(failedIndex + 1);
|
|
46
|
-
return {
|
|
47
|
-
failedTarget,
|
|
48
|
-
completed,
|
|
49
|
-
notAttempted,
|
|
50
|
-
contextLines: [
|
|
51
|
-
`Deploying all apps stopped at "${failedTarget}" (${failedIndex + 1}/${targetKeys.length}).`,
|
|
52
|
-
...completed.length > 0 ? [`Already live: ${completed.map((entry) => entry.target).join(", ")}.`] : [],
|
|
53
|
-
...notAttempted.length > 0 ? [`Not attempted: ${notAttempted.join(", ")}.`] : []
|
|
54
|
-
]
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
//#endregion
|
|
58
|
-
export { describeDeployAllFailure, perAppInputsForDeployAll, planAppDeploy };
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { renderDeployOutputRows } from "./deploy-output.js";
|
|
2
|
-
//#region src/lib/app/deploy-progress.ts
|
|
3
|
-
function createDeployProgressState() {
|
|
4
|
-
return {
|
|
5
|
-
buildStarted: false,
|
|
6
|
-
buildCompleted: false,
|
|
7
|
-
archiveReady: false,
|
|
8
|
-
uploadCompleted: false,
|
|
9
|
-
versionId: null,
|
|
10
|
-
startRequested: false,
|
|
11
|
-
containerLive: false,
|
|
12
|
-
deploymentUrl: null,
|
|
13
|
-
promotedUrl: null
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
function createDeployProgress(output, ui, enabled, state = createDeployProgressState()) {
|
|
17
|
-
const write = (line) => {
|
|
18
|
-
if (!enabled) return;
|
|
19
|
-
output.write(`${line}\n`);
|
|
20
|
-
};
|
|
21
|
-
const writeRows = (rows) => {
|
|
22
|
-
for (const line of renderDeployOutputRows(ui, rows)) write(line);
|
|
23
|
-
};
|
|
24
|
-
return {
|
|
25
|
-
onBuildStart() {
|
|
26
|
-
state.buildStarted = true;
|
|
27
|
-
write("Building locally...");
|
|
28
|
-
},
|
|
29
|
-
onBuildComplete() {
|
|
30
|
-
state.buildCompleted = true;
|
|
31
|
-
},
|
|
32
|
-
onArchiveReady(byteLength) {
|
|
33
|
-
state.archiveReady = true;
|
|
34
|
-
writeRows([{
|
|
35
|
-
label: "Built",
|
|
36
|
-
value: formatArtifactSize(byteLength)
|
|
37
|
-
}]);
|
|
38
|
-
},
|
|
39
|
-
onUploadStart() {
|
|
40
|
-
write("Uploading...");
|
|
41
|
-
},
|
|
42
|
-
onVersionCreated(versionId) {
|
|
43
|
-
state.versionId = versionId;
|
|
44
|
-
},
|
|
45
|
-
onUploadComplete() {
|
|
46
|
-
state.uploadCompleted = true;
|
|
47
|
-
writeRows([{ label: "Uploaded" }]);
|
|
48
|
-
},
|
|
49
|
-
onStartRequested() {
|
|
50
|
-
state.startRequested = true;
|
|
51
|
-
write("Deploying...");
|
|
52
|
-
},
|
|
53
|
-
onRunning(url) {
|
|
54
|
-
state.containerLive = true;
|
|
55
|
-
state.deploymentUrl = url;
|
|
56
|
-
writeRows([{ label: "Deployed" }]);
|
|
57
|
-
},
|
|
58
|
-
onPromoted(url) {
|
|
59
|
-
state.promotedUrl = url;
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
function formatArtifactSize(byteLength) {
|
|
64
|
-
return `${(byteLength / 1024 / 1024).toFixed(1)} MB`;
|
|
65
|
-
}
|
|
66
|
-
function createPromoteProgress(output, enabled) {
|
|
67
|
-
if (!enabled) return;
|
|
68
|
-
const write = (line) => {
|
|
69
|
-
output.write(`${line}\n`);
|
|
70
|
-
};
|
|
71
|
-
return {
|
|
72
|
-
onVersionStarting(versionId) {
|
|
73
|
-
write(`Starting deployment ${versionId}...`);
|
|
74
|
-
},
|
|
75
|
-
onVersionStartRequested() {
|
|
76
|
-
write("Requesting deployment start...");
|
|
77
|
-
},
|
|
78
|
-
onStatusChange(status) {
|
|
79
|
-
write(`Status: ${status}`);
|
|
80
|
-
},
|
|
81
|
-
onVersionRunning() {
|
|
82
|
-
write("Deployment is running.");
|
|
83
|
-
},
|
|
84
|
-
onPromoteStart() {
|
|
85
|
-
write("Promoting deployment...");
|
|
86
|
-
},
|
|
87
|
-
onPromoted(url) {
|
|
88
|
-
if (url) {
|
|
89
|
-
write(`Promoted to ${url}.`);
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
write("Promotion complete.");
|
|
93
|
-
},
|
|
94
|
-
onPromoteFailed(error) {
|
|
95
|
-
write(`Promotion failed${error?.message ? `: ${error.message}` : "."}`);
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
//#endregion
|
|
100
|
-
export { createDeployProgress, createDeployProgressState, createPromoteProgress };
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
//#region src/lib/app/domain-guidance.ts
|
|
2
|
-
function formatDomainFailureFix(domain) {
|
|
3
|
-
if (domain.status !== "failed") return null;
|
|
4
|
-
const dnsRecord = domain.dnsRecords[0];
|
|
5
|
-
if (domain.failureCategory === "dns") {
|
|
6
|
-
if (dnsRecord) return `Add ${dnsRecord.type} ${dnsRecord.name} -> ${dnsRecord.value}, then run prisma-cli app domain retry ${domain.hostname}.`;
|
|
7
|
-
return `DNS verification failed, but the platform did not return a DNS record. Run prisma-cli app domain show ${domain.hostname} later, then retry when the DNS target is available.`;
|
|
8
|
-
}
|
|
9
|
-
if (domain.failureCategory === "acme") return `Retry TLS issuance with prisma-cli app domain retry ${domain.hostname}. Contact support if it fails again.`;
|
|
10
|
-
if (domain.failureCategory === "storage") return `Retry provisioning with prisma-cli app domain retry ${domain.hostname}. Contact support if it fails again.`;
|
|
11
|
-
return `Run prisma-cli app domain retry ${domain.hostname}. Contact support if it fails again.`;
|
|
12
|
-
}
|
|
13
|
-
//#endregion
|
|
14
|
-
export { formatDomainFailureFix };
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { usageError } from "../../shell/errors.js";
|
|
2
|
-
//#region src/lib/app/env-config.ts
|
|
3
|
-
const VALID_ROLES = new Set(["production", "preview"]);
|
|
4
|
-
function positionalHint(command) {
|
|
5
|
-
if (command === "add" || command === "update") return "KEY=value ";
|
|
6
|
-
if (command === "remove") return "KEY ";
|
|
7
|
-
return "";
|
|
8
|
-
}
|
|
9
|
-
function resolveEnvScope(flags, options) {
|
|
10
|
-
if (flags.roleName && flags.branchName) throw usageError(`prisma-cli project env ${options.command} accepts either --role or --branch`, "--role targets a project-level config map; --branch targets a preview branch override.", "Pass exactly one scope flag.", [`prisma-cli project env ${options.command} ${positionalHint(options.command)}--role preview`, `prisma-cli project env ${options.command} ${positionalHint(options.command)}--branch feature/foo`], "app");
|
|
11
|
-
if (flags.roleName) {
|
|
12
|
-
if (!VALID_ROLES.has(flags.roleName)) throw usageError(`Unknown role "${flags.roleName}"`, "--role accepts production or preview.", "Pass --role production or --role preview.", [`prisma-cli project env ${options.command} --role production`, `prisma-cli project env ${options.command} --role preview`], "app");
|
|
13
|
-
return {
|
|
14
|
-
kind: "role",
|
|
15
|
-
role: flags.roleName
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
if (flags.branchName) return {
|
|
19
|
-
kind: "branch",
|
|
20
|
-
branchName: flags.branchName
|
|
21
|
-
};
|
|
22
|
-
if (options.requireExplicit) {
|
|
23
|
-
const positional = positionalHint(options.command);
|
|
24
|
-
throw usageError(`prisma-cli project env ${options.command} requires --role or --branch`, "Writing without an explicit scope is rejected so the command never silently targets production.", "Pass --role production, --role preview, or --branch <git-name>.", [
|
|
25
|
-
`prisma-cli project env ${options.command} ${positional}--role production`,
|
|
26
|
-
`prisma-cli project env ${options.command} ${positional}--role preview`,
|
|
27
|
-
`prisma-cli project env ${options.command} ${positional}--branch feature/foo`
|
|
28
|
-
], "app");
|
|
29
|
-
}
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
function parseKeyValuePositional(raw, command, env = process.env) {
|
|
33
|
-
if (!raw) throw usageError(`prisma-cli project env ${command} requires KEY=VALUE`, "No KEY=VALUE positional argument was supplied.", "Pass the variable as KEY=VALUE, e.g. STRIPE_KEY=sk_test_xxx.", [`prisma-cli project env ${command} STRIPE_KEY=sk_test_xxx --role production`], "app");
|
|
34
|
-
const separatorIndex = raw.indexOf("=");
|
|
35
|
-
if (separatorIndex === -1) {
|
|
36
|
-
if (KEY_SHAPE.test(raw)) {
|
|
37
|
-
validateKey(raw, command);
|
|
38
|
-
const value = env[raw];
|
|
39
|
-
if (typeof value === "string" && value.length > 0) return {
|
|
40
|
-
key: raw,
|
|
41
|
-
value
|
|
42
|
-
};
|
|
43
|
-
throw usageError(`Value for "${raw}" was not provided`, `No KEY=VALUE assignment was supplied, and ${raw} is not set in the current environment.`, "Pass KEY=VALUE or export the variable before running the command.", [`prisma-cli project env ${command} ${raw}=value --role production`, `${raw}=value prisma-cli project env ${command} ${raw} --role production`], "app");
|
|
44
|
-
}
|
|
45
|
-
throw usageError(`KEY=VALUE argument is missing the = separator`, `"${raw}" does not contain an = character.`, "Pass the variable as KEY=VALUE, e.g. STRIPE_KEY=sk_test_xxx.", [`prisma-cli project env ${command} STRIPE_KEY=sk_test_xxx --role production`], "app");
|
|
46
|
-
}
|
|
47
|
-
const key = raw.slice(0, separatorIndex);
|
|
48
|
-
const value = raw.slice(separatorIndex + 1);
|
|
49
|
-
validateKey(key, command);
|
|
50
|
-
if (value.length === 0) throw usageError(`KEY=VALUE argument has an empty value`, `"${raw}" has an empty value after the = separator.`, `Pass a non-empty value, or use prisma-cli project env remove to remove a variable.`, [`prisma-cli project env ${command} ${key}=value --role production`], "app");
|
|
51
|
-
return {
|
|
52
|
-
key,
|
|
53
|
-
value
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
const KEY_SHAPE = /^[A-Z_][A-Z0-9_]*$/;
|
|
57
|
-
function validateKey(key, command) {
|
|
58
|
-
if (key.length === 0) throw usageError(`Variable key cannot be empty`, "An empty key was passed.", "Pass an env-var key, e.g. STRIPE_KEY.", [`prisma-cli project env ${command} STRIPE_KEY${command === "remove" ? "" : "=value"} --role production`], "app");
|
|
59
|
-
if (key.length > 256) throw usageError(`Variable key "${key}" exceeds the 256-character limit`, "Env-var keys are capped at 256 characters by the platform.", "Use a shorter key.", [], "app");
|
|
60
|
-
if (!KEY_SHAPE.test(key)) throw usageError(`Variable key "${key}" must match the POSIX env-var shape`, "Keys must start with an uppercase letter or underscore and contain only uppercase letters, digits, and underscores.", "Rename the key to match [A-Z_][A-Z0-9_]*.", [`prisma-cli project env ${command} STRIPE_KEY${command === "remove" ? "" : "=value"} --role production`], "app");
|
|
61
|
-
}
|
|
62
|
-
function formatScopeLabel(scope) {
|
|
63
|
-
if (scope.kind === "role") return scope.role;
|
|
64
|
-
return `branch:${scope.branchName}`;
|
|
65
|
-
}
|
|
66
|
-
//#endregion
|
|
67
|
-
export { formatScopeLabel, parseKeyValuePositional, resolveEnvScope, validateKey };
|
package/dist/lib/app/env-file.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { usageError } from "../../shell/errors.js";
|
|
2
|
-
import { validateKey } from "./env-config.js";
|
|
3
|
-
import { readFile } from "node:fs/promises";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { parse } from "dotenv";
|
|
6
|
-
//#region src/lib/app/env-file.ts
|
|
7
|
-
const ASSIGNMENT_KEY_PATTERN = /^\s*(?:export\s+)?([^#=\s]+)\s*=/;
|
|
8
|
-
async function readEnvFileAssignments(cwd, filePath, command) {
|
|
9
|
-
const resolvedPath = path.resolve(cwd, filePath);
|
|
10
|
-
let contents;
|
|
11
|
-
try {
|
|
12
|
-
contents = await readFile(resolvedPath, "utf8");
|
|
13
|
-
} catch (error) {
|
|
14
|
-
throw usageError(`Failed to read env file "${filePath}"`, error instanceof Error ? error.message : "The file could not be read.", "Pass a readable dotenv file path.", [command === "deploy" ? "prisma-cli app deploy --env .env" : `prisma-cli project env ${command} --file .env --role preview`], "app");
|
|
15
|
-
}
|
|
16
|
-
return parseEnvFileContents(contents, filePath, command);
|
|
17
|
-
}
|
|
18
|
-
function parseEnvFileContents(contents, filePath, command) {
|
|
19
|
-
const parsedKeys = extractParsedKeys(contents);
|
|
20
|
-
if (parsedKeys.length === 0) throw usageError(`No environment variables found in "${filePath}"`, "The file does not contain any KEY=VALUE assignments.", "Pass a dotenv file with at least one non-empty variable.", [], "app");
|
|
21
|
-
const seen = /* @__PURE__ */ new Map();
|
|
22
|
-
for (const entry of parsedKeys) {
|
|
23
|
-
validateEnvFileKey(entry.key, entry.line, filePath, command);
|
|
24
|
-
const firstLine = seen.get(entry.key);
|
|
25
|
-
if (firstLine !== void 0) throw usageError(`Duplicate environment variable "${entry.key}" in "${filePath}"`, `Lines ${firstLine} and ${entry.line} both define ${entry.key}.`, "Keep one assignment for each key before importing the file.", [], "app");
|
|
26
|
-
seen.set(entry.key, entry.line);
|
|
27
|
-
}
|
|
28
|
-
const parsedValues = parse(contents);
|
|
29
|
-
return parsedKeys.map(({ key }) => {
|
|
30
|
-
const value = parsedValues[key];
|
|
31
|
-
if (typeof value !== "string" || value.length === 0) {
|
|
32
|
-
const line = seen.get(key);
|
|
33
|
-
throw usageError(`Environment variable "${key}" in "${filePath}" has an empty value`, line === void 0 ? `${key} has an empty value.` : `Line ${line} defines ${key} with an empty value.`, "Pass a non-empty value, or omit the key from the file.", [], "app");
|
|
34
|
-
}
|
|
35
|
-
return {
|
|
36
|
-
key,
|
|
37
|
-
value
|
|
38
|
-
};
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
function extractParsedKeys(contents) {
|
|
42
|
-
const keys = [];
|
|
43
|
-
let multilineQuote = null;
|
|
44
|
-
const lines = contents.split(/\n/);
|
|
45
|
-
for (const [index, line] of lines.entries()) {
|
|
46
|
-
const lineNumber = index + 1;
|
|
47
|
-
if (multilineQuote !== null) {
|
|
48
|
-
if (hasClosingQuote(line, multilineQuote, 0)) multilineQuote = null;
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
const match = ASSIGNMENT_KEY_PATTERN.exec(line);
|
|
52
|
-
if (!match) continue;
|
|
53
|
-
const key = match[1];
|
|
54
|
-
keys.push({
|
|
55
|
-
key,
|
|
56
|
-
line: lineNumber
|
|
57
|
-
});
|
|
58
|
-
const valueStart = line.slice(match[0].length).trimStart();
|
|
59
|
-
const openingQuote = valueStart[0];
|
|
60
|
-
if ((openingQuote === "\"" || openingQuote === "'" || openingQuote === "`") && !hasClosingQuote(valueStart, openingQuote, 1)) multilineQuote = openingQuote;
|
|
61
|
-
}
|
|
62
|
-
return keys;
|
|
63
|
-
}
|
|
64
|
-
function validateEnvFileKey(key, line, filePath, command) {
|
|
65
|
-
try {
|
|
66
|
-
validateKey(key, command === "deploy" ? "add" : command);
|
|
67
|
-
} catch (error) {
|
|
68
|
-
const reason = error instanceof Error && error.message.length > 0 ? error.message : "Invalid environment variable key.";
|
|
69
|
-
throw usageError(`Invalid environment variable "${key}" in "${filePath}"`, `Line ${line}: ${reason}`, "Use a valid env-var key and retry the import.", [], "app");
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function hasClosingQuote(value, quote, startIndex) {
|
|
73
|
-
for (let index = startIndex; index < value.length; index += 1) if (value[index] === quote && !isEscaped(value, index)) return true;
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
function isEscaped(value, index) {
|
|
77
|
-
let backslashes = 0;
|
|
78
|
-
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) backslashes += 1;
|
|
79
|
-
return backslashes % 2 === 1;
|
|
80
|
-
}
|
|
81
|
-
//#endregion
|
|
82
|
-
export { readEnvFileAssignments };
|
package/dist/lib/app/env-vars.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { usageError } from "../../shell/errors.js";
|
|
2
|
-
import { validateKey } from "./env-config.js";
|
|
3
|
-
import { readEnvFileAssignments } from "./env-file.js";
|
|
4
|
-
//#region src/lib/app/env-vars.ts
|
|
5
|
-
function parseEnvAssignments(assignments, options) {
|
|
6
|
-
const values = assignments ?? [];
|
|
7
|
-
if (options.requireAtLeastOne && values.length === 0) throw usageError("At least one environment variable is required", `prisma-cli app ${options.commandName} needs at least one --env NAME=VALUE flag in the current mode.`, `Pass one or more --env NAME=VALUE flags, for example prisma-cli app ${options.commandName} --env DATABASE_URL=postgresql://example.`, [`prisma-cli app ${options.commandName} --env DATABASE_URL=postgresql://example`], "app");
|
|
8
|
-
const parsed = {};
|
|
9
|
-
const seen = /* @__PURE__ */ new Set();
|
|
10
|
-
for (const assignment of values) {
|
|
11
|
-
const separatorIndex = assignment.indexOf("=");
|
|
12
|
-
if (separatorIndex === -1) throw usageError("Environment variable assignment must use NAME=VALUE", "A provided --env flag is missing the = separator.", `Pass repeated --env NAME=VALUE flags, for example prisma-cli app ${options.commandName} --env DATABASE_URL=postgresql://example.`, [`prisma-cli app ${options.commandName} --env DATABASE_URL=postgresql://example`], "app");
|
|
13
|
-
const name = assignment.slice(0, separatorIndex);
|
|
14
|
-
if (name.length === 0) throw usageError("Environment variable name is required", "A provided --env flag has an empty variable name.", `Pass repeated --env NAME=VALUE flags, for example prisma-cli app ${options.commandName} --env DATABASE_URL=postgresql://example.`, [`prisma-cli app ${options.commandName} --env DATABASE_URL=postgresql://example`], "app");
|
|
15
|
-
validateEnvAssignmentName(name, options.commandName);
|
|
16
|
-
if (seen.has(name)) throw usageError(`Environment variable "${name}" was provided more than once`, "Each environment variable name may be set only once per command invocation.", `Remove the duplicate "${name}" assignment and rerun prisma-cli app ${options.commandName}.`, [`prisma-cli app ${options.commandName} --env ${name}=value`], "app");
|
|
17
|
-
const value = assignment.slice(separatorIndex + 1);
|
|
18
|
-
if (value.length === 0) throw usageError(`Environment variable "${name}" has an empty value`, `A provided --env flag defines ${name} with no value.`, "Pass a non-empty value, or omit the key from the deploy command.", [`prisma-cli app ${options.commandName} --env ${name}=value`], "app");
|
|
19
|
-
seen.add(name);
|
|
20
|
-
parsed[name] = value;
|
|
21
|
-
}
|
|
22
|
-
return parsed;
|
|
23
|
-
}
|
|
24
|
-
async function parseEnvInputs(cwd, inputs, options) {
|
|
25
|
-
const values = inputs ?? [];
|
|
26
|
-
const expandedAssignments = [];
|
|
27
|
-
for (const value of values) {
|
|
28
|
-
if (value.includes("=")) {
|
|
29
|
-
expandedAssignments.push(value);
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
const fileAssignments = await readEnvFileAssignments(cwd, value, options.commandName);
|
|
33
|
-
expandedAssignments.push(...fileAssignments.map((assignment) => `${assignment.key}=${assignment.value}`));
|
|
34
|
-
}
|
|
35
|
-
return parseEnvAssignments(expandedAssignments, options);
|
|
36
|
-
}
|
|
37
|
-
function validateEnvAssignmentName(name, commandName) {
|
|
38
|
-
try {
|
|
39
|
-
validateKey(name, "add");
|
|
40
|
-
} catch (error) {
|
|
41
|
-
const reason = error instanceof Error && error.message.length > 0 ? error.message : "Invalid environment variable name.";
|
|
42
|
-
throw usageError(`Invalid environment variable "${name}"`, reason, "Use a valid env-var name and retry the deploy.", [`prisma-cli app ${commandName} --env DATABASE_URL=postgresql://example`], "app");
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function envVarNames(envVars) {
|
|
46
|
-
if (!envVars) return [];
|
|
47
|
-
return Object.entries(envVars).filter(([, value]) => value !== null).map(([name]) => name).sort((left, right) => left.localeCompare(right));
|
|
48
|
-
}
|
|
49
|
-
//#endregion
|
|
50
|
-
export { envVarNames, parseEnvInputs };
|