@prisma/cli 3.0.0-dev.99.1 → 8.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/cli.js +15115 -16
- package/dist/deploy-framework-C7bQM00A.js +23 -0
- package/dist/payload-B88Qvzxk-CrtTXSOe.js +34 -0
- package/dist/sender.js +192 -0
- package/package.json +22 -18
- 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
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { resolveBunEntrypoint } from "./bun-project.js";
|
|
2
|
-
import "node:fs/promises";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { spawn } from "node:child_process";
|
|
5
|
-
//#region src/lib/app/local-dev.ts
|
|
6
|
-
const DEFAULT_LOCAL_DEV_PORT = 3e3;
|
|
7
|
-
async function runLocalApp(options) {
|
|
8
|
-
const spawnImpl = options.spawnImpl ?? spawn;
|
|
9
|
-
if (options.buildType === "nextjs") {
|
|
10
|
-
const command = await runWithFallback([
|
|
11
|
-
{
|
|
12
|
-
command: path.join(options.appPath, "node_modules", ".bin", process.platform === "win32" ? "next.cmd" : "next"),
|
|
13
|
-
args: [
|
|
14
|
-
"dev",
|
|
15
|
-
"--port",
|
|
16
|
-
String(options.port)
|
|
17
|
-
],
|
|
18
|
-
display: `next dev --port ${options.port}`
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
command: "npx",
|
|
22
|
-
args: [
|
|
23
|
-
"next",
|
|
24
|
-
"dev",
|
|
25
|
-
"--port",
|
|
26
|
-
String(options.port)
|
|
27
|
-
],
|
|
28
|
-
display: `next dev --port ${options.port}`
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
command: "bunx",
|
|
32
|
-
args: [
|
|
33
|
-
"next",
|
|
34
|
-
"dev",
|
|
35
|
-
"--port",
|
|
36
|
-
String(options.port)
|
|
37
|
-
],
|
|
38
|
-
display: `next dev --port ${options.port}`
|
|
39
|
-
}
|
|
40
|
-
], {
|
|
41
|
-
cwd: options.appPath,
|
|
42
|
-
env: {
|
|
43
|
-
...options.env,
|
|
44
|
-
PORT: String(options.port)
|
|
45
|
-
},
|
|
46
|
-
signal: options.signal
|
|
47
|
-
}, spawnImpl, "Could not find the Next.js CLI. Install it with `npm install next` or ensure npx/bunx is available.");
|
|
48
|
-
return {
|
|
49
|
-
framework: "nextjs",
|
|
50
|
-
entrypoint: null,
|
|
51
|
-
port: options.port,
|
|
52
|
-
command: command.display,
|
|
53
|
-
exitCode: command.exitCode,
|
|
54
|
-
signal: command.signal
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
const entrypoint = await resolveBunEntrypoint(options.appPath, options.entrypoint, options.signal);
|
|
58
|
-
const command = await runWithFallback([{
|
|
59
|
-
command: "bun",
|
|
60
|
-
args: ["--watch", entrypoint],
|
|
61
|
-
display: `bun --watch ${entrypoint}`
|
|
62
|
-
}], {
|
|
63
|
-
cwd: options.appPath,
|
|
64
|
-
env: {
|
|
65
|
-
...options.env,
|
|
66
|
-
PORT: String(options.port)
|
|
67
|
-
},
|
|
68
|
-
signal: options.signal
|
|
69
|
-
}, spawnImpl, "Bun is required to run this app locally. Install it from https://bun.sh.");
|
|
70
|
-
return {
|
|
71
|
-
framework: "bun",
|
|
72
|
-
entrypoint,
|
|
73
|
-
port: options.port,
|
|
74
|
-
command: command.display,
|
|
75
|
-
exitCode: command.exitCode,
|
|
76
|
-
signal: command.signal
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
async function runWithFallback(candidates, options, spawnImpl, missingCommandMessage) {
|
|
80
|
-
for (const candidate of candidates) try {
|
|
81
|
-
const result = await spawnCommand(candidate, options, spawnImpl);
|
|
82
|
-
return {
|
|
83
|
-
display: candidate.display,
|
|
84
|
-
exitCode: result.exitCode,
|
|
85
|
-
signal: result.signal
|
|
86
|
-
};
|
|
87
|
-
} catch (error) {
|
|
88
|
-
if (error.code === "ENOENT") continue;
|
|
89
|
-
throw error;
|
|
90
|
-
}
|
|
91
|
-
throw new Error(missingCommandMessage);
|
|
92
|
-
}
|
|
93
|
-
function spawnCommand(candidate, options, spawnImpl) {
|
|
94
|
-
return new Promise((resolve, reject) => {
|
|
95
|
-
const child = spawnImpl(candidate.command, candidate.args, {
|
|
96
|
-
...options,
|
|
97
|
-
stdio: "inherit"
|
|
98
|
-
});
|
|
99
|
-
child.once("error", reject);
|
|
100
|
-
child.once("exit", (code, signal) => {
|
|
101
|
-
resolve({
|
|
102
|
-
exitCode: code ?? 1,
|
|
103
|
-
signal
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
//#endregion
|
|
109
|
-
export { DEFAULT_LOCAL_DEV_PORT, runLocalApp };
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { CliError } from "../../shell/errors.js";
|
|
2
|
-
import { confirmPrompt } from "../../shell/prompt.js";
|
|
3
|
-
import { canPrompt } from "../../shell/runtime.js";
|
|
4
|
-
//#region src/lib/app/production-deploy-gate.ts
|
|
5
|
-
async function enforceProductionDeployGate(context, provider, options) {
|
|
6
|
-
if (options.branchKind !== "production") return { firstProductionDeploy: false };
|
|
7
|
-
if (!options.appId) {
|
|
8
|
-
renderFirstProductionDeployLine(context, options.appName);
|
|
9
|
-
return { firstProductionDeploy: true };
|
|
10
|
-
}
|
|
11
|
-
const currentLiveDeployment = resolveCurrentProductionDeployment(await provider.listDeployments(options.appId).catch((error) => {
|
|
12
|
-
throw productionDeployInspectionFailedError(error);
|
|
13
|
-
}));
|
|
14
|
-
if (!currentLiveDeployment) {
|
|
15
|
-
renderFirstProductionDeployLine(context, options.appName);
|
|
16
|
-
return { firstProductionDeploy: true };
|
|
17
|
-
}
|
|
18
|
-
if (!options.prod) throw productionDeployRequiresFlagError();
|
|
19
|
-
if (context.flags.yes) {
|
|
20
|
-
renderProductionDeployYesLine(context);
|
|
21
|
-
return { firstProductionDeploy: false };
|
|
22
|
-
}
|
|
23
|
-
if (!canPrompt(context)) throw productionDeployConfirmationRequiredError(options.appName);
|
|
24
|
-
renderProductionDeployConfirmation(context, currentLiveDeployment);
|
|
25
|
-
if (!await confirmPrompt({
|
|
26
|
-
input: context.runtime.stdin,
|
|
27
|
-
output: context.output.stderr,
|
|
28
|
-
message: "Deploy to production?",
|
|
29
|
-
initialValue: false
|
|
30
|
-
})) throw productionDeployCancelledError();
|
|
31
|
-
return { firstProductionDeploy: false };
|
|
32
|
-
}
|
|
33
|
-
function resolveCurrentProductionDeployment(result) {
|
|
34
|
-
if (result.deployments.length === 0) return null;
|
|
35
|
-
if (result.app.liveDeploymentId) {
|
|
36
|
-
const live = result.deployments.find((deployment) => deployment.id === result.app.liveDeploymentId);
|
|
37
|
-
if (live) return live;
|
|
38
|
-
}
|
|
39
|
-
return result.deployments.find((deployment) => deployment.live === true) ?? result.deployments[0] ?? null;
|
|
40
|
-
}
|
|
41
|
-
function renderFirstProductionDeployLine(context, appName) {
|
|
42
|
-
if (context.flags.json || context.flags.quiet) return;
|
|
43
|
-
context.output.stderr.write(`First deploy of "${appName}" -- promoting to production.\n\n`);
|
|
44
|
-
}
|
|
45
|
-
function renderProductionDeployYesLine(context) {
|
|
46
|
-
if (context.flags.json || context.flags.quiet) return;
|
|
47
|
-
context.output.stderr.write("Deploying to production (--prod --yes).\n\n");
|
|
48
|
-
}
|
|
49
|
-
function renderProductionDeployConfirmation(context, currentLiveDeployment) {
|
|
50
|
-
if (context.flags.json || context.flags.quiet) return;
|
|
51
|
-
const lines = [
|
|
52
|
-
"This will deploy to production and replace the live deployment.",
|
|
53
|
-
"",
|
|
54
|
-
` Current live: ${currentLiveDeployment.id} deployed ${formatDeploymentAge(currentLiveDeployment.createdAt)}`,
|
|
55
|
-
" New deploy: will be built from your local code",
|
|
56
|
-
""
|
|
57
|
-
];
|
|
58
|
-
context.output.stderr.write(`${lines.join("\n")}\n`);
|
|
59
|
-
}
|
|
60
|
-
function formatDeploymentAge(createdAt) {
|
|
61
|
-
const createdAtMs = Date.parse(createdAt);
|
|
62
|
-
if (!Number.isFinite(createdAtMs)) return createdAt;
|
|
63
|
-
const elapsedMs = Math.max(0, Date.now() - createdAtMs);
|
|
64
|
-
for (const unit of [
|
|
65
|
-
{
|
|
66
|
-
label: "day",
|
|
67
|
-
ms: 1440 * 60 * 1e3
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
label: "hour",
|
|
71
|
-
ms: 3600 * 1e3
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
label: "minute",
|
|
75
|
-
ms: 60 * 1e3
|
|
76
|
-
}
|
|
77
|
-
]) if (elapsedMs >= unit.ms) {
|
|
78
|
-
const value = Math.floor(elapsedMs / unit.ms);
|
|
79
|
-
return `${value} ${unit.label}${value === 1 ? "" : "s"} ago`;
|
|
80
|
-
}
|
|
81
|
-
return "less than a minute ago";
|
|
82
|
-
}
|
|
83
|
-
function productionDeployRequiresFlagError() {
|
|
84
|
-
return new CliError({
|
|
85
|
-
code: "PROD_DEPLOY_REQUIRES_FLAG",
|
|
86
|
-
domain: "app",
|
|
87
|
-
summary: "Production deploy requires --prod",
|
|
88
|
-
why: "The resolved Branch is production and this App already has a production deployment.",
|
|
89
|
-
fix: "Re-run with --prod, or deploy from a preview Branch.",
|
|
90
|
-
exitCode: 2,
|
|
91
|
-
nextActions: [{
|
|
92
|
-
kind: "run-command",
|
|
93
|
-
journey: "deploy-app",
|
|
94
|
-
label: "Deploy to production",
|
|
95
|
-
command: "prisma-cli app deploy --prod"
|
|
96
|
-
}, {
|
|
97
|
-
kind: "run-command",
|
|
98
|
-
journey: "deploy-app",
|
|
99
|
-
label: "Create a preview branch",
|
|
100
|
-
commands: ["git checkout -b <branch-name>", "prisma-cli app deploy"]
|
|
101
|
-
}],
|
|
102
|
-
humanLines: [
|
|
103
|
-
"This would deploy to production.",
|
|
104
|
-
"",
|
|
105
|
-
"Production deploys require explicit intent. Re-run with:",
|
|
106
|
-
"",
|
|
107
|
-
" prisma-cli app deploy --prod",
|
|
108
|
-
"",
|
|
109
|
-
"Or deploy a preview from a feature branch:",
|
|
110
|
-
"",
|
|
111
|
-
" git checkout -b <branch-name>",
|
|
112
|
-
" prisma-cli app deploy"
|
|
113
|
-
]
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
function productionDeployConfirmationRequiredError(appName) {
|
|
117
|
-
return new CliError({
|
|
118
|
-
code: "CONFIRMATION_REQUIRED",
|
|
119
|
-
domain: "app",
|
|
120
|
-
summary: "Production deploy requires confirmation in the current mode",
|
|
121
|
-
why: "This command cannot prompt for production deploy confirmation in the current mode.",
|
|
122
|
-
fix: `Pass --prod --yes to confirm deployment of "${appName}" to production.`,
|
|
123
|
-
exitCode: 1,
|
|
124
|
-
nextSteps: ["prisma-cli app deploy --prod --yes"],
|
|
125
|
-
nextActions: [{
|
|
126
|
-
kind: "run-command",
|
|
127
|
-
journey: "deploy-app",
|
|
128
|
-
label: "Deploy to production non-interactively",
|
|
129
|
-
command: "prisma-cli app deploy --prod --yes"
|
|
130
|
-
}]
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
function productionDeployCancelledError() {
|
|
134
|
-
return new CliError({
|
|
135
|
-
code: "CONFIRMATION_REQUIRED",
|
|
136
|
-
domain: "app",
|
|
137
|
-
summary: "Production deploy cancelled",
|
|
138
|
-
why: null,
|
|
139
|
-
fix: null,
|
|
140
|
-
exitCode: 0,
|
|
141
|
-
humanLines: ["Cancelled."]
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
function productionDeployInspectionFailedError(error) {
|
|
145
|
-
return new CliError({
|
|
146
|
-
code: "DEPLOY_FAILED",
|
|
147
|
-
domain: "app",
|
|
148
|
-
summary: "Failed to inspect production deployments",
|
|
149
|
-
why: error instanceof Error ? error.message : String(error),
|
|
150
|
-
fix: "Retry the command, or rerun with --trace for more detailed diagnostics.",
|
|
151
|
-
debug: formatDebugDetails(error),
|
|
152
|
-
exitCode: 1,
|
|
153
|
-
nextSteps: ["prisma-cli app list-deploys"]
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
function formatDebugDetails(error) {
|
|
157
|
-
if (error instanceof Error) return error.stack ?? error.message;
|
|
158
|
-
return typeof error === "string" ? error : null;
|
|
159
|
-
}
|
|
160
|
-
//#endregion
|
|
161
|
-
export { enforceProductionDeployGate };
|
|
@@ -1,30 +0,0 @@
|
|
|
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 };
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { SERVICE_TOKEN_ENV_VAR } from "./client.js";
|
|
2
|
-
import { FileTokenStorage } from "../../adapters/token-storage.js";
|
|
3
|
-
import { requireComputeAuth } from "./guard.js";
|
|
4
|
-
import { login } from "./login.js";
|
|
5
|
-
//#region src/lib/auth/auth-ops.ts
|
|
6
|
-
const WORKSPACE_SUB_PREFIX = "workspace:";
|
|
7
|
-
function decodeJwtPayload(token) {
|
|
8
|
-
try {
|
|
9
|
-
const payload = token.split(".")[1];
|
|
10
|
-
if (!payload) return {};
|
|
11
|
-
return JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
12
|
-
} catch {
|
|
13
|
-
return {};
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
function emailFromClaims(claims) {
|
|
17
|
-
const email = claims.email;
|
|
18
|
-
return typeof email === "string" && email.trim().length > 0 ? email.trim() : null;
|
|
19
|
-
}
|
|
20
|
-
function workspaceIdFromClaims(claims) {
|
|
21
|
-
const sub = claims.sub;
|
|
22
|
-
if (typeof sub !== "string") return null;
|
|
23
|
-
if (!sub.startsWith(WORKSPACE_SUB_PREFIX)) return null;
|
|
24
|
-
const id = sub.slice(10).trim();
|
|
25
|
-
return id.length > 0 ? id : null;
|
|
26
|
-
}
|
|
27
|
-
async function performLogin(env, signal) {
|
|
28
|
-
await login({
|
|
29
|
-
tokenStorage: new FileTokenStorage(env, signal, { activateOnSetTokens: true }),
|
|
30
|
-
env,
|
|
31
|
-
signal
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
async function readAuthState(env, signal) {
|
|
35
|
-
const rawServiceToken = env[SERVICE_TOKEN_ENV_VAR];
|
|
36
|
-
if (rawServiceToken !== void 0) {
|
|
37
|
-
const serviceToken = rawServiceToken.trim();
|
|
38
|
-
if (serviceToken.length === 0) throw new Error(`${SERVICE_TOKEN_ENV_VAR} is set but empty. Provide a valid token or unset the variable.`);
|
|
39
|
-
return readServiceTokenAuthState(serviceToken, env, signal);
|
|
40
|
-
}
|
|
41
|
-
const tokenStorage = new FileTokenStorage(env, signal);
|
|
42
|
-
const tokens = await tokenStorage.getTokens();
|
|
43
|
-
if (!tokens) return {
|
|
44
|
-
authenticated: false,
|
|
45
|
-
provider: null,
|
|
46
|
-
user: null,
|
|
47
|
-
workspace: null,
|
|
48
|
-
credential: null
|
|
49
|
-
};
|
|
50
|
-
const client = await requireComputeAuth(env, signal);
|
|
51
|
-
const currentPrincipal = await readCurrentPrincipalAuthState(client, signal);
|
|
52
|
-
if (currentPrincipal) {
|
|
53
|
-
if (currentPrincipal.authenticated && currentPrincipal.workspace) await tokenStorage.rememberWorkspace?.(tokens.workspaceId, currentPrincipal.workspace);
|
|
54
|
-
return currentPrincipal;
|
|
55
|
-
}
|
|
56
|
-
const claims = decodeJwtPayload(tokens.accessToken);
|
|
57
|
-
const authState = await buildAuthState({
|
|
58
|
-
workspaceIdFromCredential: tokens.workspaceId,
|
|
59
|
-
claims,
|
|
60
|
-
env,
|
|
61
|
-
client,
|
|
62
|
-
signal
|
|
63
|
-
});
|
|
64
|
-
if (authState.authenticated && authState.workspace) await tokenStorage.rememberWorkspace?.(tokens.workspaceId, authState.workspace);
|
|
65
|
-
return authState;
|
|
66
|
-
}
|
|
67
|
-
async function readServiceTokenAuthState(token, env, signal) {
|
|
68
|
-
const client = await requireComputeAuth(env, signal);
|
|
69
|
-
const currentPrincipal = await readCurrentPrincipalAuthState(client, signal);
|
|
70
|
-
if (currentPrincipal) return currentPrincipal;
|
|
71
|
-
const claims = decodeJwtPayload(token);
|
|
72
|
-
const workspaceId = workspaceIdFromClaims(claims);
|
|
73
|
-
if (!workspaceId) return {
|
|
74
|
-
authenticated: false,
|
|
75
|
-
provider: null,
|
|
76
|
-
user: null,
|
|
77
|
-
workspace: null,
|
|
78
|
-
credential: null
|
|
79
|
-
};
|
|
80
|
-
return buildAuthState({
|
|
81
|
-
workspaceIdFromCredential: workspaceId,
|
|
82
|
-
claims,
|
|
83
|
-
env,
|
|
84
|
-
client,
|
|
85
|
-
signal
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
async function buildAuthState({ workspaceIdFromCredential, claims, env, client, signal }) {
|
|
89
|
-
let workspaceId = workspaceIdFromCredential;
|
|
90
|
-
let workspaceName = workspaceIdFromCredential;
|
|
91
|
-
client ??= await requireComputeAuth(env, signal);
|
|
92
|
-
if (client) try {
|
|
93
|
-
const { data, response } = await client.GET("/v1/workspaces/{id}", {
|
|
94
|
-
params: { path: { id: workspaceIdFromCredential } },
|
|
95
|
-
signal
|
|
96
|
-
});
|
|
97
|
-
if (response?.status === 401) return {
|
|
98
|
-
authenticated: false,
|
|
99
|
-
provider: null,
|
|
100
|
-
user: null,
|
|
101
|
-
workspace: null,
|
|
102
|
-
credential: null
|
|
103
|
-
};
|
|
104
|
-
if (data?.data?.id) {
|
|
105
|
-
workspaceId = data.data.id;
|
|
106
|
-
workspaceName = data.data.id;
|
|
107
|
-
}
|
|
108
|
-
if (data?.data?.name) workspaceName = data.data.name;
|
|
109
|
-
} catch {
|
|
110
|
-
signal?.throwIfAborted();
|
|
111
|
-
}
|
|
112
|
-
const email = emailFromClaims(claims);
|
|
113
|
-
return {
|
|
114
|
-
authenticated: true,
|
|
115
|
-
provider: null,
|
|
116
|
-
user: email ? { email } : null,
|
|
117
|
-
workspace: {
|
|
118
|
-
id: workspaceId,
|
|
119
|
-
name: workspaceName
|
|
120
|
-
},
|
|
121
|
-
credential: null
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
async function readCurrentPrincipalAuthState(client, signal) {
|
|
125
|
-
if (!client) return null;
|
|
126
|
-
try {
|
|
127
|
-
const { data, response } = await client.GET("/v1/me", { signal });
|
|
128
|
-
if (response?.status === 401) return {
|
|
129
|
-
authenticated: false,
|
|
130
|
-
provider: null,
|
|
131
|
-
user: null,
|
|
132
|
-
workspace: null,
|
|
133
|
-
credential: null
|
|
134
|
-
};
|
|
135
|
-
const principal = data?.data;
|
|
136
|
-
if (!principal) return null;
|
|
137
|
-
if (!principal.credential) return null;
|
|
138
|
-
return {
|
|
139
|
-
authenticated: true,
|
|
140
|
-
provider: null,
|
|
141
|
-
user: principal.user ? {
|
|
142
|
-
id: principal.user.id,
|
|
143
|
-
email: principal.user.email,
|
|
144
|
-
name: principal.user.name
|
|
145
|
-
} : null,
|
|
146
|
-
workspace: principal.workspace,
|
|
147
|
-
credential: principal.credential
|
|
148
|
-
};
|
|
149
|
-
} catch {
|
|
150
|
-
signal?.throwIfAborted();
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
async function performLogout(env, signal) {
|
|
155
|
-
await new FileTokenStorage(env, signal).clearTokens();
|
|
156
|
-
}
|
|
157
|
-
//#endregion
|
|
158
|
-
export { performLogin, performLogout, readAuthState };
|
package/dist/lib/auth/client.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import os from "node:os";
|
|
3
|
-
//#region src/lib/auth/client.ts
|
|
4
|
-
const CLIENT_ID = "cmm3lndn701oo0uefvxzo0ivw";
|
|
5
|
-
const SERVICE_TOKEN_ENV_VAR = "PRISMA_SERVICE_TOKEN";
|
|
6
|
-
const AUTH_FILE_ENV_VAR = "PRISMA_COMPUTE_AUTH_FILE";
|
|
7
|
-
function getApiBaseUrl(env = process.env) {
|
|
8
|
-
return env.PRISMA_MANAGEMENT_API_URL?.trim() || "https://api.prisma.io";
|
|
9
|
-
}
|
|
10
|
-
function getAuthFilePath(env = process.env) {
|
|
11
|
-
const configured = env[AUTH_FILE_ENV_VAR];
|
|
12
|
-
if (configured?.trim()) return path.resolve(configured);
|
|
13
|
-
if (process.platform === "darwin") return path.join(os.homedir(), "Library", "Application Support", "prisma", "auth.json");
|
|
14
|
-
if (process.platform === "win32") {
|
|
15
|
-
const appData = env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming");
|
|
16
|
-
return path.join(appData, "prisma", "auth.json");
|
|
17
|
-
}
|
|
18
|
-
const xdgConfigHome = env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config");
|
|
19
|
-
return path.join(xdgConfigHome, "prisma", "auth.json");
|
|
20
|
-
}
|
|
21
|
-
//#endregion
|
|
22
|
-
export { CLIENT_ID, SERVICE_TOKEN_ENV_VAR, getApiBaseUrl, getAuthFilePath };
|
package/dist/lib/auth/guard.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { CLIENT_ID, SERVICE_TOKEN_ENV_VAR, getApiBaseUrl } from "./client.js";
|
|
2
|
-
import { FileTokenStorage } from "../../adapters/token-storage.js";
|
|
3
|
-
import { createManagementApiClient, createManagementApiSdk } from "@prisma/management-api-sdk";
|
|
4
|
-
//#region src/lib/auth/guard.ts
|
|
5
|
-
/**
|
|
6
|
-
* Resolve authentication and return a ManagementApiClient.
|
|
7
|
-
*
|
|
8
|
-
* Priority:
|
|
9
|
-
* 1. PRISMA_SERVICE_TOKEN env var → service token (CI / headless)
|
|
10
|
-
* 2. Stored OAuth tokens → SDK with auto-refresh
|
|
11
|
-
*
|
|
12
|
-
* Returns null if not authenticated.
|
|
13
|
-
*/
|
|
14
|
-
async function requireComputeAuth(env = process.env, signal) {
|
|
15
|
-
signal?.throwIfAborted();
|
|
16
|
-
const rawToken = env[SERVICE_TOKEN_ENV_VAR];
|
|
17
|
-
if (rawToken !== void 0) {
|
|
18
|
-
const token = rawToken.trim();
|
|
19
|
-
if (token.length === 0) throw new Error(`${SERVICE_TOKEN_ENV_VAR} is set but empty. Provide a valid token or unset the variable.`);
|
|
20
|
-
return createManagementApiClient({
|
|
21
|
-
baseUrl: getApiBaseUrl(env),
|
|
22
|
-
token
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
const tokenStorage = new FileTokenStorage(env, signal, {
|
|
26
|
-
activateOnSetTokens: false,
|
|
27
|
-
lockSetTokens: false
|
|
28
|
-
});
|
|
29
|
-
if (!await tokenStorage.getTokens()) return null;
|
|
30
|
-
return createManagementApiSdk({
|
|
31
|
-
clientId: CLIENT_ID,
|
|
32
|
-
redirectUri: "http://localhost:0/auth/callback",
|
|
33
|
-
tokenStorage,
|
|
34
|
-
apiBaseUrl: getApiBaseUrl(env)
|
|
35
|
-
}).client;
|
|
36
|
-
}
|
|
37
|
-
//#endregion
|
|
38
|
-
export { requireComputeAuth };
|