@prisma/cli 3.0.0-beta.8 → 3.0.0-dev.101.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 +0 -13
- package/dist/adapters/mock-api.js +75 -0
- package/dist/adapters/token-storage.js +311 -33
- package/dist/cli.js +7 -7
- package/dist/cli2.js +5 -3
- package/dist/commands/app/index.js +65 -52
- package/dist/commands/auth/index.js +55 -2
- package/dist/commands/database/index.js +159 -0
- package/dist/controllers/app-env.js +10 -7
- package/dist/controllers/app.js +550 -208
- package/dist/controllers/auth.js +211 -2
- package/dist/controllers/branch.js +5 -6
- package/dist/controllers/database.js +318 -0
- package/dist/controllers/project.js +49 -20
- package/dist/lib/app/app-interaction.js +5 -0
- package/dist/lib/app/{preview-provider.js → app-provider.js} +32 -28
- package/dist/lib/app/{preview-branch-database.js → branch-database-api.js} +1 -1
- package/dist/lib/app/branch-database-deploy.js +13 -60
- package/dist/lib/app/branch-database.js +1 -102
- package/dist/lib/app/build-settings.js +93 -0
- package/dist/lib/app/build.js +82 -0
- package/dist/lib/app/bun-project.js +2 -3
- package/dist/lib/app/compute-config.js +147 -0
- package/dist/lib/app/deploy-plan.js +58 -0
- package/dist/lib/app/{preview-progress.js → deploy-progress.js} +5 -5
- package/dist/lib/app/local-dev.js +3 -60
- package/dist/lib/app/production-deploy-gate.js +3 -3
- package/dist/lib/app/read-branch.js +30 -0
- package/dist/lib/auth/auth-ops.js +10 -4
- package/dist/lib/auth/guard.js +4 -1
- package/dist/lib/auth/login.js +32 -25
- package/dist/lib/database/provider.js +167 -0
- package/dist/lib/diagnostics.js +1 -1
- package/dist/lib/fs/home-path.js +24 -0
- package/dist/lib/git/local-branch.js +15 -3
- package/dist/lib/project/local-pin.js +170 -40
- package/dist/lib/project/resolution.js +166 -61
- package/dist/lib/project/setup.js +65 -19
- package/dist/output/patterns.js +1 -1
- package/dist/presenters/app.js +44 -39
- package/dist/presenters/auth.js +98 -1
- package/dist/presenters/branch.js +1 -1
- package/dist/presenters/database.js +274 -0
- package/dist/presenters/project.js +3 -9
- package/dist/shell/command-meta.js +153 -2
- package/dist/shell/command-runner.js +39 -21
- package/dist/shell/diagnostics-output.js +2 -8
- package/dist/shell/errors.js +50 -1
- package/dist/shell/help.js +30 -20
- package/dist/shell/runtime.js +8 -4
- package/dist/shell/ui.js +19 -2
- package/dist/use-cases/auth.js +68 -1
- package/package.json +18 -3
- package/dist/lib/app/preview-build-settings.js +0 -385
- package/dist/lib/app/preview-build.js +0 -475
- package/dist/lib/app/preview-interaction.js +0 -5
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { CliError, authRequiredError, commandCanceledError } from "./errors.js";
|
|
2
|
-
import { cliErrorToJson, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess } from "./output.js";
|
|
1
|
+
import { CliError, authConfigInvalidError, authRequiredError, commandCanceledError } from "./errors.js";
|
|
3
2
|
import { getCommandDescriptor } from "./command-meta.js";
|
|
4
3
|
import { resolveGlobalFlags } from "./global-flags.js";
|
|
5
4
|
import { createCommandContext } from "./runtime.js";
|
|
5
|
+
import { cliErrorToJson, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess } from "./output.js";
|
|
6
6
|
import { collectCommandDiagnostics } from "../lib/diagnostics.js";
|
|
7
7
|
import { renderCommandDiagnostics } from "./diagnostics-output.js";
|
|
8
8
|
import { AuthError } from "@prisma/management-api-sdk";
|
|
@@ -11,6 +11,7 @@ function toCliError(error, runtime) {
|
|
|
11
11
|
if (isCancellationError(error) || runtime.signal.aborted) return commandCanceledError();
|
|
12
12
|
if (error instanceof CliError) return error;
|
|
13
13
|
if (error instanceof AuthError) return authRequiredError(["prisma-cli auth login"], { debug: error.message });
|
|
14
|
+
if (error instanceof Error && error.message.startsWith("PRISMA_SERVICE_TOKEN is set but empty")) return authConfigInvalidError(error.message);
|
|
14
15
|
return null;
|
|
15
16
|
}
|
|
16
17
|
function isCancellationError(error) {
|
|
@@ -18,37 +19,54 @@ function isCancellationError(error) {
|
|
|
18
19
|
return error.name === "AbortError" || error.name === "CancelledError";
|
|
19
20
|
}
|
|
20
21
|
async function runCommand(runtime, commandName, options, handler, presenter) {
|
|
21
|
-
const
|
|
22
|
-
const context = await createCommandContext(runtime, flags);
|
|
22
|
+
const context = await createCommandContext(runtime, resolveGlobalFlags(runtime.argv, options));
|
|
23
23
|
const descriptor = getCommandDescriptor(commandName);
|
|
24
24
|
const startedAt = Date.now();
|
|
25
25
|
try {
|
|
26
|
-
|
|
27
|
-
if (flags.json) {
|
|
28
|
-
writeJsonSuccess(context.output, {
|
|
29
|
-
...success,
|
|
30
|
-
result: presenter.renderJson ? presenter.renderJson(success.result) : success.result
|
|
31
|
-
});
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
if (flags.quiet) return;
|
|
35
|
-
const rendered = presenter.renderHuman(context, descriptor, success.result);
|
|
36
|
-
const diagnostics = await renderBestEffortCommandDiagnostics(context, {
|
|
37
|
-
enabled: flags.verbose && rendered.length > 0,
|
|
38
|
-
durationMs: Date.now() - startedAt
|
|
39
|
-
});
|
|
40
|
-
writeHumanLines(context.output, [...rendered, ...diagnostics]);
|
|
26
|
+
await writeCommandSuccess(context, descriptor, await handler(context), presenter, Date.now() - startedAt);
|
|
41
27
|
} catch (error) {
|
|
42
28
|
const cliError = toCliError(error, runtime);
|
|
43
29
|
if (cliError) {
|
|
44
|
-
|
|
45
|
-
else writeHumanError(context.output, context.ui, cliError, { trace: flags.trace });
|
|
30
|
+
writeCommandError(context, commandName, cliError);
|
|
46
31
|
process.exitCode = cliError.exitCode;
|
|
47
32
|
return;
|
|
48
33
|
}
|
|
49
34
|
throw error;
|
|
50
35
|
}
|
|
51
36
|
}
|
|
37
|
+
async function writeCommandSuccess(context, descriptor, success, presenter, durationMs) {
|
|
38
|
+
if (context.flags.json) {
|
|
39
|
+
writeJsonSuccess(context.output, {
|
|
40
|
+
...success,
|
|
41
|
+
result: presenter.renderJson ? presenter.renderJson(success.result) : success.result
|
|
42
|
+
});
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const stdout = presenter.renderStdout?.(context, descriptor, success.result) ?? [];
|
|
46
|
+
if (context.flags.quiet) {
|
|
47
|
+
writeStdoutLines(context, stdout);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const rendered = presenter.renderHuman(context, descriptor, success.result);
|
|
51
|
+
const diagnostics = await renderBestEffortCommandDiagnostics(context, {
|
|
52
|
+
enabled: context.flags.verbose && rendered.length > 0,
|
|
53
|
+
durationMs
|
|
54
|
+
});
|
|
55
|
+
const humanLines = [...rendered, ...diagnostics];
|
|
56
|
+
if (stdout.length > 0 && humanLines.length > 0) humanLines.push("");
|
|
57
|
+
writeHumanLines(context.output, humanLines);
|
|
58
|
+
writeStdoutLines(context, stdout);
|
|
59
|
+
}
|
|
60
|
+
function writeCommandError(context, commandName, cliError) {
|
|
61
|
+
if (context.flags.json) {
|
|
62
|
+
writeJsonError(context.output, commandName, cliError);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
writeHumanError(context.output, context.ui, cliError, { trace: context.flags.trace });
|
|
66
|
+
}
|
|
67
|
+
function writeStdoutLines(context, lines) {
|
|
68
|
+
if (lines.length > 0) context.output.stdout.write(`${lines.join("\n")}\n`);
|
|
69
|
+
}
|
|
52
70
|
async function renderBestEffortCommandDiagnostics(context, options) {
|
|
53
71
|
if (!options.enabled) return [];
|
|
54
72
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { renderVerboseBlock } from "./ui.js";
|
|
2
|
-
import
|
|
2
|
+
import { shortenHomePath } from "../lib/fs/home-path.js";
|
|
3
3
|
//#region src/shell/diagnostics-output.ts
|
|
4
4
|
function renderCommandDiagnostics(context, diagnostics, rows = [], options = {}) {
|
|
5
5
|
if (!diagnostics) return [];
|
|
@@ -43,13 +43,7 @@ function renderCommandDiagnostics(context, diagnostics, rows = [], options = {})
|
|
|
43
43
|
], { title: options.title ?? "Local context" });
|
|
44
44
|
}
|
|
45
45
|
function formatLocalPath(value, env) {
|
|
46
|
-
|
|
47
|
-
const home = env.HOME ? path.resolve(env.HOME) : null;
|
|
48
|
-
if (home && (resolved === home || resolved.startsWith(`${home}${path.sep}`))) {
|
|
49
|
-
const relative = path.relative(home, resolved);
|
|
50
|
-
return relative ? `~/${relative}` : "~";
|
|
51
|
-
}
|
|
52
|
-
return resolved;
|
|
46
|
+
return shortenHomePath(value, env);
|
|
53
47
|
}
|
|
54
48
|
function formatDirtyState(dirty) {
|
|
55
49
|
if (dirty === null) return "unknown";
|
package/dist/shell/errors.js
CHANGED
|
@@ -56,6 +56,17 @@ function authRequiredError(nextSteps = ["prisma-cli auth login"], options = {})
|
|
|
56
56
|
nextSteps
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
|
+
function authConfigInvalidError(message) {
|
|
60
|
+
return new CliError({
|
|
61
|
+
code: "AUTH_CONFIG_INVALID",
|
|
62
|
+
domain: "auth",
|
|
63
|
+
summary: "Authentication configuration is invalid",
|
|
64
|
+
why: message,
|
|
65
|
+
fix: "Provide a valid PRISMA_SERVICE_TOKEN value, or unset the variable to use local OAuth login.",
|
|
66
|
+
exitCode: 1,
|
|
67
|
+
nextSteps: ["prisma-cli auth login"]
|
|
68
|
+
});
|
|
69
|
+
}
|
|
59
70
|
function commandCanceledError() {
|
|
60
71
|
return new CliError({
|
|
61
72
|
code: "COMMAND_CANCELED",
|
|
@@ -70,6 +81,44 @@ function commandCanceledError() {
|
|
|
70
81
|
function workspaceRequiredError() {
|
|
71
82
|
return usageError("Workspace required", "This command needs an active workspace, but the authenticated session does not have one.", "Run prisma-cli auth login and choose a workspace.", ["prisma-cli auth login"], "auth");
|
|
72
83
|
}
|
|
84
|
+
function workspaceSwitchUnavailableError() {
|
|
85
|
+
return new CliError({
|
|
86
|
+
code: "WORKSPACE_SWITCH_UNAVAILABLE",
|
|
87
|
+
domain: "auth",
|
|
88
|
+
summary: "Workspace switching is unavailable",
|
|
89
|
+
why: "PRISMA_SERVICE_TOKEN is set, so authenticated commands use that token instead of local OAuth workspaces.",
|
|
90
|
+
fix: "Unset PRISMA_SERVICE_TOKEN to switch between local OAuth workspaces, or use a token for the workspace you want.",
|
|
91
|
+
exitCode: 1,
|
|
92
|
+
nextSteps: ["unset PRISMA_SERVICE_TOKEN", "prisma-cli auth workspace list"]
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function workspaceNotAuthenticatedError(workspaceRef) {
|
|
96
|
+
return new CliError({
|
|
97
|
+
code: "WORKSPACE_NOT_AUTHENTICATED",
|
|
98
|
+
domain: "auth",
|
|
99
|
+
summary: "Workspace is not authenticated",
|
|
100
|
+
why: `No stored OAuth session matched "${workspaceRef}".`,
|
|
101
|
+
fix: "Run prisma-cli auth login and authorize that workspace, then switch to it.",
|
|
102
|
+
meta: { workspaceRef },
|
|
103
|
+
exitCode: 1,
|
|
104
|
+
nextSteps: ["prisma-cli auth workspace list", "prisma-cli auth login"]
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function workspaceAmbiguousError(workspaceRef, matches) {
|
|
108
|
+
return new CliError({
|
|
109
|
+
code: "WORKSPACE_AMBIGUOUS",
|
|
110
|
+
domain: "auth",
|
|
111
|
+
summary: "Workspace name is ambiguous",
|
|
112
|
+
why: `Multiple authenticated workspaces matched "${workspaceRef}".`,
|
|
113
|
+
fix: "Run prisma-cli auth workspace list and switch by workspace id.",
|
|
114
|
+
meta: {
|
|
115
|
+
workspaceRef,
|
|
116
|
+
matches
|
|
117
|
+
},
|
|
118
|
+
exitCode: 2,
|
|
119
|
+
nextSteps: ["prisma-cli auth workspace list"]
|
|
120
|
+
});
|
|
121
|
+
}
|
|
73
122
|
function featureUnavailableError(summary, why, fix, nextSteps = [], domain = "cli") {
|
|
74
123
|
return new CliError({
|
|
75
124
|
code: "FEATURE_UNAVAILABLE",
|
|
@@ -82,4 +131,4 @@ function featureUnavailableError(summary, why, fix, nextSteps = [], domain = "cl
|
|
|
82
131
|
});
|
|
83
132
|
}
|
|
84
133
|
//#endregion
|
|
85
|
-
export { CliError, authRequiredError, commandCanceledError, featureUnavailableError, usageError, workspaceRequiredError };
|
|
134
|
+
export { CliError, authConfigInvalidError, authRequiredError, commandCanceledError, featureUnavailableError, usageError, workspaceAmbiguousError, workspaceNotAuthenticatedError, workspaceRequiredError, workspaceSwitchUnavailableError };
|
package/dist/shell/help.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createShellUi, padDisplay, wrapText } from "./ui.js";
|
|
2
1
|
import { formatDescriptorLabel, getDescriptorForCommand } from "./command-meta.js";
|
|
3
2
|
import { COMPACT_GLOBAL_OPTION_FLAGS, resolveGlobalFlags } from "./global-flags.js";
|
|
3
|
+
import { createShellUi, padDisplay, wrapText } from "./ui.js";
|
|
4
4
|
//#region src/shell/help.ts
|
|
5
5
|
function renderHelp(command, runtime) {
|
|
6
6
|
const descriptor = getDescriptorForCommand(command);
|
|
@@ -10,28 +10,38 @@ function renderHelp(command, runtime) {
|
|
|
10
10
|
const visibleCommands = command.commands.filter((candidate) => candidate.name() !== "help" && !candidate.hidden);
|
|
11
11
|
const visibleOptions = command.options.filter((candidate) => !candidate.hidden);
|
|
12
12
|
if (visibleCommands.length > 0) lines.push(...renderCommandRows(rail, ui, visibleCommands));
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
if (visibleOptions.length > 0) {
|
|
19
|
-
if (visibleCommands.length > 0) lines.push(`${rail}`);
|
|
20
|
-
if (visibleCommands.length > 0 && visibleOptions.every((option) => COMPACT_GLOBAL_OPTION_FLAGS.includes(option.flags))) lines.push(`${rail} Global options:`);
|
|
21
|
-
lines.push(...renderOptionRows(rail, ui, visibleOptions));
|
|
22
|
-
}
|
|
23
|
-
if (descriptor.examples && descriptor.examples.length > 0) {
|
|
24
|
-
lines.push(`${rail}`);
|
|
25
|
-
lines.push(`${rail} Examples:`);
|
|
26
|
-
for (const example of descriptor.examples) lines.push(`${rail} $ ${example}`);
|
|
27
|
-
}
|
|
28
|
-
if (descriptor.docsPath) {
|
|
29
|
-
lines.push(`${rail}`);
|
|
30
|
-
lines.push(`${rail} ${ui.accent(padDisplay("Read more", 16))} ${ui.link(descriptor.docsPath)}`);
|
|
31
|
-
}
|
|
13
|
+
lines.push(...renderLongDescription(rail, ui, descriptor.longDescription));
|
|
14
|
+
lines.push(...renderVisibleOptions(rail, ui, visibleCommands, visibleOptions));
|
|
15
|
+
lines.push(...renderExamples(rail, descriptor.examples));
|
|
16
|
+
lines.push(...renderDocsPath(rail, ui, descriptor.docsPath));
|
|
32
17
|
lines.push("");
|
|
33
18
|
return `${lines.join("\n")}`;
|
|
34
19
|
}
|
|
20
|
+
function renderLongDescription(rail, ui, longDescription) {
|
|
21
|
+
if (!longDescription) return [];
|
|
22
|
+
return [`${rail}`, ...wrapText(longDescription, Math.max(ui.width - 3, 40)).map((line) => `${rail} ${line}`)];
|
|
23
|
+
}
|
|
24
|
+
function renderVisibleOptions(rail, ui, visibleCommands, visibleOptions) {
|
|
25
|
+
if (visibleOptions.length === 0) return [];
|
|
26
|
+
const lines = visibleCommands.length > 0 ? [`${rail}`] : [];
|
|
27
|
+
if (shouldLabelGlobalOptions(visibleCommands, visibleOptions)) lines.push(`${rail} Global options:`);
|
|
28
|
+
return [...lines, ...renderOptionRows(rail, ui, visibleOptions)];
|
|
29
|
+
}
|
|
30
|
+
function shouldLabelGlobalOptions(visibleCommands, visibleOptions) {
|
|
31
|
+
return visibleCommands.length > 0 && visibleOptions.every((option) => COMPACT_GLOBAL_OPTION_FLAGS.includes(option.flags));
|
|
32
|
+
}
|
|
33
|
+
function renderExamples(rail, examples) {
|
|
34
|
+
if (!examples || examples.length === 0) return [];
|
|
35
|
+
return [
|
|
36
|
+
`${rail}`,
|
|
37
|
+
`${rail} Examples:`,
|
|
38
|
+
...examples.map((example) => `${rail} $ ${example}`)
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
function renderDocsPath(rail, ui, docsPath) {
|
|
42
|
+
if (!docsPath) return [];
|
|
43
|
+
return [`${rail}`, `${rail} ${ui.accent(padDisplay("Read more", 16))} ${ui.link(docsPath)}`];
|
|
44
|
+
}
|
|
35
45
|
function renderCommandRows(rail, ui, commands) {
|
|
36
46
|
return renderAlignedRows(rail, ui, commands.map((command) => {
|
|
37
47
|
const descriptor = getDescriptorForCommand(command);
|
package/dist/shell/runtime.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { createShellUi } from "./ui.js";
|
|
2
1
|
import { LocalStateStore } from "../adapters/local-state.js";
|
|
3
2
|
import { MockApi } from "../adapters/mock-api.js";
|
|
3
|
+
import { createShellUi } from "./ui.js";
|
|
4
4
|
import { renderHelp } from "./help.js";
|
|
5
|
+
import { findComputeConfigDir } from "@prisma/compute-sdk/config";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
//#region src/shell/runtime.ts
|
|
7
8
|
const DEFAULT_STATE_DIR_NAME = path.join(".prisma", "cli");
|
|
@@ -20,7 +21,7 @@ function configureRuntimeCommand(command, runtime) {
|
|
|
20
21
|
}
|
|
21
22
|
async function createCommandContext(runtime, flags) {
|
|
22
23
|
const fixturePath = runtime.fixturePath ?? runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
|
|
23
|
-
const stateDir = resolveStateDir(runtime);
|
|
24
|
+
const stateDir = await resolveStateDir(runtime);
|
|
24
25
|
let loadedApi;
|
|
25
26
|
if (fixturePath) loadedApi = await MockApi.load(fixturePath, runtime.signal);
|
|
26
27
|
return {
|
|
@@ -38,8 +39,11 @@ async function createCommandContext(runtime, flags) {
|
|
|
38
39
|
ui: createShellUi(runtime, flags)
|
|
39
40
|
};
|
|
40
41
|
}
|
|
41
|
-
function resolveStateDir(runtime) {
|
|
42
|
-
|
|
42
|
+
async function resolveStateDir(runtime) {
|
|
43
|
+
const explicitStateDir = runtime.stateDir ?? runtime.env.PRISMA_CLI_STATE_DIR;
|
|
44
|
+
if (explicitStateDir) return explicitStateDir;
|
|
45
|
+
const projectDir = await findComputeConfigDir(runtime.cwd, runtime.signal);
|
|
46
|
+
return path.join(projectDir ?? runtime.cwd, DEFAULT_STATE_DIR_NAME);
|
|
43
47
|
}
|
|
44
48
|
function canPrompt(context) {
|
|
45
49
|
if (context.flags.json) return false;
|
package/dist/shell/ui.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { createColors } from "colorette";
|
|
1
2
|
import stringWidth from "string-width";
|
|
2
3
|
import stripAnsi from "strip-ansi";
|
|
3
4
|
import wrapAnsi from "wrap-ansi";
|
|
4
|
-
import { createColors } from "colorette";
|
|
5
5
|
//#region src/shell/ui.ts
|
|
6
|
+
const URL_CREDENTIALS_PATTERN = /:\/\/[^:@/\s]+:[^@/\s]+@/g;
|
|
6
7
|
const DEFAULT_WIDTH = 80;
|
|
7
8
|
function createShellUi(runtime, flags) {
|
|
8
9
|
const isTTY = Boolean(runtime.stderr.isTTY);
|
|
@@ -73,7 +74,23 @@ function padDisplay(text, width) {
|
|
|
73
74
|
return `${text}${" ".repeat(padding)}`;
|
|
74
75
|
}
|
|
75
76
|
function maskValue(value) {
|
|
76
|
-
return value
|
|
77
|
+
return maskEmailLocalParts(value).replace(URL_CREDENTIALS_PATTERN, "://****:****@");
|
|
78
|
+
}
|
|
79
|
+
function maskEmailLocalParts(value) {
|
|
80
|
+
let masked = "";
|
|
81
|
+
let segmentStart = 0;
|
|
82
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
83
|
+
if (value[index] !== "@") continue;
|
|
84
|
+
let localStart = index;
|
|
85
|
+
while (localStart > segmentStart && isEmailLocalPartChar(value[localStart - 1])) localStart -= 1;
|
|
86
|
+
if (localStart === index) continue;
|
|
87
|
+
masked += `${value.slice(segmentStart, localStart)}****@`;
|
|
88
|
+
segmentStart = index + 1;
|
|
89
|
+
}
|
|
90
|
+
return masked + value.slice(segmentStart);
|
|
91
|
+
}
|
|
92
|
+
function isEmailLocalPartChar(char) {
|
|
93
|
+
return char >= "A" && char <= "Z" || char >= "a" && char <= "z" || char >= "0" && char <= "9" || char === "!" || char === "#" || char === "$" || char === "." || char === "&" || char === "'" || char === "*" || char === "%" || char === "+" || char === "-" || char === "/" || char === "=" || char === "?" || char === "^" || char === "_" || char === "`" || char === "{" || char === "|" || char === "}" || char === "~";
|
|
77
94
|
}
|
|
78
95
|
function resolveColorEnabled(runtime, flags, isTTY) {
|
|
79
96
|
if (flags.color === true) return true;
|
package/dist/use-cases/auth.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { usageError } from "../shell/errors.js";
|
|
1
|
+
import { authRequiredError, usageError, workspaceAmbiguousError, workspaceNotAuthenticatedError } from "../shell/errors.js";
|
|
2
2
|
//#region src/use-cases/auth.ts
|
|
3
3
|
function createAuthUseCases(dependencies) {
|
|
4
4
|
return {
|
|
@@ -15,6 +15,70 @@ function createAuthUseCases(dependencies) {
|
|
|
15
15
|
await dependencies.sessionGateway.clearAuthSession();
|
|
16
16
|
return resolveCurrentAuthState(dependencies);
|
|
17
17
|
},
|
|
18
|
+
listWorkspaces: async () => {
|
|
19
|
+
const session = await dependencies.sessionGateway.readAuthSession();
|
|
20
|
+
if (!session) return {
|
|
21
|
+
authSource: "none",
|
|
22
|
+
activeWorkspace: null,
|
|
23
|
+
workspaces: []
|
|
24
|
+
};
|
|
25
|
+
const workspaces = dependencies.identityGateway.listUserWorkspaces(session.userId);
|
|
26
|
+
return {
|
|
27
|
+
authSource: "oauth",
|
|
28
|
+
activeWorkspace: workspaces.find((workspace) => workspace.id === session.workspaceId) ?? null,
|
|
29
|
+
workspaces: workspaces.map((workspace) => ({
|
|
30
|
+
...workspace,
|
|
31
|
+
credentialWorkspaceId: workspace.id,
|
|
32
|
+
active: workspace.id === session.workspaceId,
|
|
33
|
+
source: "oauth",
|
|
34
|
+
switchable: true,
|
|
35
|
+
lastSeenAt: null
|
|
36
|
+
}))
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
useWorkspace: async (workspaceRef) => {
|
|
40
|
+
const session = await dependencies.sessionGateway.readAuthSession();
|
|
41
|
+
if (!session) throw authRequiredError(["prisma-cli auth login"]);
|
|
42
|
+
const ref = workspaceRef.trim();
|
|
43
|
+
const matches = dependencies.identityGateway.listUserWorkspaces(session.userId).filter((workspace) => workspaceMatchesRef(workspace, ref));
|
|
44
|
+
if (matches.length === 0) throw workspaceNotAuthenticatedError(workspaceRef);
|
|
45
|
+
if (matches.length > 1) throw workspaceAmbiguousError(workspaceRef, matches.map((workspace) => ({
|
|
46
|
+
id: workspace.id,
|
|
47
|
+
name: workspace.name,
|
|
48
|
+
credentialWorkspaceId: workspace.id
|
|
49
|
+
})));
|
|
50
|
+
const selected = matches[0];
|
|
51
|
+
const previousWorkspace = dependencies.identityGateway.getWorkspace(session.workspaceId) ?? null;
|
|
52
|
+
await dependencies.sessionGateway.writeAuthSession({
|
|
53
|
+
...session,
|
|
54
|
+
workspaceId: selected.id
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
previousWorkspace,
|
|
58
|
+
workspace: selected
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
logoutWorkspace: async (workspaceRef) => {
|
|
62
|
+
const session = await dependencies.sessionGateway.readAuthSession();
|
|
63
|
+
if (!session) throw workspaceNotAuthenticatedError(workspaceRef);
|
|
64
|
+
const ref = workspaceRef.trim();
|
|
65
|
+
const matches = dependencies.identityGateway.listUserWorkspaces(session.userId).filter((workspace) => workspaceMatchesRef(workspace, ref));
|
|
66
|
+
if (matches.length === 0) throw workspaceNotAuthenticatedError(workspaceRef);
|
|
67
|
+
if (matches.length > 1) throw workspaceAmbiguousError(workspaceRef, matches.map((workspace) => ({
|
|
68
|
+
id: workspace.id,
|
|
69
|
+
name: workspace.name,
|
|
70
|
+
credentialWorkspaceId: workspace.id
|
|
71
|
+
})));
|
|
72
|
+
const workspace = matches[0];
|
|
73
|
+
const wasActive = workspace.id === session.workspaceId;
|
|
74
|
+
const activeWorkspace = wasActive ? null : dependencies.identityGateway.getWorkspace(session.workspaceId) ?? null;
|
|
75
|
+
if (wasActive) await dependencies.sessionGateway.clearAuthSession();
|
|
76
|
+
return {
|
|
77
|
+
workspace,
|
|
78
|
+
wasActive,
|
|
79
|
+
activeWorkspace
|
|
80
|
+
};
|
|
81
|
+
},
|
|
18
82
|
listProviders: async () => dependencies.identityGateway.listProviders(),
|
|
19
83
|
resolveProvider: async (providerId) => {
|
|
20
84
|
const provider = dependencies.identityGateway.getProvider(providerId);
|
|
@@ -39,6 +103,9 @@ function createAuthUseCases(dependencies) {
|
|
|
39
103
|
}
|
|
40
104
|
};
|
|
41
105
|
}
|
|
106
|
+
function workspaceMatchesRef(workspace, ref) {
|
|
107
|
+
return workspace.id === ref || workspace.name.toLowerCase() === ref.toLowerCase();
|
|
108
|
+
}
|
|
42
109
|
async function resolveCurrentAuthState(dependencies) {
|
|
43
110
|
const session = await dependencies.sessionGateway.readAuthSession();
|
|
44
111
|
if (!session) return {
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/cli",
|
|
3
|
-
"version": "3.0.0-
|
|
3
|
+
"version": "3.0.0-dev.101.1",
|
|
4
4
|
"description": "Command-line interface for the Prisma Developer Platform.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"prisma-cli": "./dist/cli.js"
|
|
8
8
|
},
|
|
9
|
+
"exports": {
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
9
12
|
"files": [
|
|
10
13
|
"dist",
|
|
11
14
|
"README.md",
|
|
@@ -34,12 +37,17 @@
|
|
|
34
37
|
"url": "https://github.com/prisma/prisma-cli/issues"
|
|
35
38
|
},
|
|
36
39
|
"license": "Apache-2.0",
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsdown",
|
|
42
|
+
"prepack": "pnpm run build",
|
|
43
|
+
"test": "vitest run"
|
|
44
|
+
},
|
|
37
45
|
"dependencies": {
|
|
38
46
|
"@clack/prompts": "^1.5.0",
|
|
39
|
-
"@prisma/compute-sdk": "^0.
|
|
47
|
+
"@prisma/compute-sdk": "^0.29.0",
|
|
40
48
|
"@prisma/credentials-store": "^7.8.0",
|
|
41
49
|
"@prisma/management-api-sdk": "^1.37.0",
|
|
42
|
-
"
|
|
50
|
+
"better-result": "^2.9.2",
|
|
43
51
|
"colorette": "^2.0.20",
|
|
44
52
|
"commander": "^14.0.3",
|
|
45
53
|
"dotenv": "^17.4.2",
|
|
@@ -48,5 +56,12 @@
|
|
|
48
56
|
"string-width": "^8.2.1",
|
|
49
57
|
"strip-ansi": "^7.2.0",
|
|
50
58
|
"wrap-ansi": "^10.0.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/node": "^22.19.19",
|
|
62
|
+
"tsdown": "^0.21.10",
|
|
63
|
+
"tsx": "^4.22.4",
|
|
64
|
+
"typescript": "^6.0.3",
|
|
65
|
+
"vitest": "^4.1.8"
|
|
51
66
|
}
|
|
52
67
|
}
|