@prisma/cli 3.0.0-dev.97.1 → 8.0.0-rc.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 +3 -14
- package/dist/adapters/local-state.js +14 -3
- package/dist/{lib/auth → auth}/client.js +11 -3
- package/dist/auth/errors.js +50 -0
- package/dist/{lib/auth → auth}/guard.js +7 -6
- package/dist/{lib/auth → auth}/login.js +147 -6
- package/dist/{lib/auth/auth-ops.js → auth/operations.js} +63 -13
- package/dist/auth/recipient.js +42 -0
- package/dist/{adapters → auth}/token-storage.js +28 -7
- package/dist/auth/workspaces.js +171 -0
- package/dist/cli-command.js +14 -0
- package/dist/cli-name.js +12 -0
- package/dist/cli.js +1 -1
- package/dist/cli2.js +25 -8
- package/dist/command-arguments.js +12 -0
- package/dist/commands/agent/index.js +60 -0
- package/dist/commands/app/index.js +11 -6
- package/dist/commands/auth/index.js +2 -3
- package/dist/commands/bucket/index.js +123 -0
- package/dist/commands/build/index.js +29 -0
- package/dist/commands/database/index.js +92 -2
- package/dist/commands/feedback/index.js +20 -0
- package/dist/commands/git/index.js +1 -1
- package/dist/commands/init/index.js +33 -0
- package/dist/commands/project/index.js +54 -5
- package/dist/controllers/agent-setup.js +52 -0
- package/dist/controllers/agent.js +228 -0
- package/dist/controllers/app-env-api.js +3 -2
- package/dist/controllers/app-env-file.js +1 -1
- package/dist/controllers/app-env.js +5 -5
- package/dist/controllers/app.js +423 -358
- package/dist/controllers/auth.js +62 -254
- package/dist/controllers/branch.js +5 -16
- package/dist/controllers/bucket.js +184 -0
- package/dist/controllers/build.js +88 -0
- package/dist/controllers/database.js +230 -85
- package/dist/controllers/feedback.js +90 -0
- package/dist/controllers/init.js +814 -0
- package/dist/controllers/project.js +345 -184
- package/dist/controllers/select-prompt-port.js +1 -0
- package/dist/{shell/errors.js → errors.js} +8 -40
- package/dist/lib/agent/cli-command.js +20 -0
- package/dist/lib/agent/constants.js +12 -0
- package/dist/lib/agent/package-manager.js +99 -0
- package/dist/lib/agent/setup-status.js +83 -0
- package/dist/lib/app/app-provider.js +168 -95
- package/dist/lib/app/branch-database-deploy.js +70 -42
- package/dist/lib/app/branch-database.js +39 -20
- package/dist/lib/app/build-settings.js +8 -3
- package/dist/lib/app/build.js +16 -14
- package/dist/lib/app/bun-project.js +1 -1
- package/dist/lib/app/compute-config.js +29 -31
- package/dist/lib/app/deploy-plan.js +1 -0
- package/dist/lib/app/deploy-progress.js +7 -7
- package/dist/lib/app/env-config.js +1 -1
- package/dist/lib/app/env-file.js +2 -2
- package/dist/lib/app/env-vars.js +1 -1
- package/dist/lib/app/local-dev.js +1 -1
- package/dist/lib/app/production-deploy-gate.js +3 -2
- package/dist/lib/bucket/provider.js +139 -0
- package/dist/lib/database/provider.js +235 -17
- package/dist/lib/diagnostics.js +2 -1
- package/dist/lib/feedback.js +15 -0
- package/dist/lib/git/local-branch.js +1 -1
- package/dist/lib/project/interactive-setup.js +6 -5
- package/dist/lib/project/local-pin.js +1 -1
- package/dist/lib/project/provider.js +93 -0
- package/dist/lib/project/resolution.js +11 -8
- package/dist/lib/project/setup.js +9 -6
- package/dist/lib/version.js +3 -2
- package/dist/lib/workspace-id.js +18 -0
- package/dist/payload-B88Qvzxk-CrtTXSOe.js +34 -0
- package/dist/presenters/agent.js +74 -0
- package/dist/presenters/app.js +33 -7
- package/dist/presenters/auth.js +3 -2
- package/dist/presenters/bucket.js +174 -0
- package/dist/presenters/database.js +193 -5
- package/dist/presenters/feedback.js +26 -0
- package/dist/presenters/init.js +30 -0
- package/dist/presenters/project.js +98 -4
- package/dist/shell/cli-command.js +2 -0
- package/dist/shell/command-meta.js +303 -4
- package/dist/shell/command-runner.js +13 -6
- package/dist/shell/help.js +6 -5
- package/dist/shell/output.js +65 -3
- package/dist/shell/prompt.js +12 -5
- package/dist/shell/runtime.js +4 -21
- package/dist/state-dir.js +12 -0
- package/dist/{shell/update-check.js → update-check.js} +6 -5
- package/dist/v8/cli.js +14699 -0
- package/dist/v8/sender.js +192 -0
- package/package.json +21 -13
- package/dist/adapters/mock-api.js +0 -136
- package/dist/lib/app/app-interaction.js +0 -5
- package/dist/shell/command-arguments.js +0 -6
- 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
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { t as isParentToSenderPayload } from "../payload-B88Qvzxk-CrtTXSOe.js";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { determineAgent } from "@vercel/detect-agent";
|
|
5
|
+
//#region ../cli-telemetry/dist/sender.js
|
|
6
|
+
/**
|
|
7
|
+
* Identify the runtime the sender is running in. Same-runtime as the
|
|
8
|
+
* parent is a correctness requirement: the parent forked us via
|
|
9
|
+
* `child_process.fork`, which inherits the parent's runtime. Detection
|
|
10
|
+
* keys on the runtime-specific version field rather than env vars so a
|
|
11
|
+
* spoofed env can't lie about the actual interpreter.
|
|
12
|
+
*/
|
|
13
|
+
function resolveRuntime(versions) {
|
|
14
|
+
if (versions.bun !== void 0) return {
|
|
15
|
+
name: "bun",
|
|
16
|
+
version: versions.bun
|
|
17
|
+
};
|
|
18
|
+
if (versions.deno !== void 0) return {
|
|
19
|
+
name: "deno",
|
|
20
|
+
version: versions.deno
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
name: "node",
|
|
24
|
+
version: versions.node
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const WHITESPACE = /\s+/;
|
|
28
|
+
const SEMVER_RANGE_PREFIX = /^[\^~]/;
|
|
29
|
+
/**
|
|
30
|
+
* Parse `npm_config_user_agent` into a `<pm>/<version>` token. The
|
|
31
|
+
* value, when present, looks like
|
|
32
|
+
* `"pnpm/10.27.0 npm/? node/v24.13.0 darwin arm64"` — we take the first
|
|
33
|
+
* whitespace-separated token. Any failure → `null`.
|
|
34
|
+
*/
|
|
35
|
+
function parsePackageManager(userAgent) {
|
|
36
|
+
if (userAgent === void 0) return null;
|
|
37
|
+
const first = userAgent.split(WHITESPACE)[0];
|
|
38
|
+
if (first === void 0 || first.length === 0) return null;
|
|
39
|
+
if (!first.includes("/")) return null;
|
|
40
|
+
return first;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Read the user's project `package.json` and resolve a TypeScript
|
|
44
|
+
* version from `devDependencies.typescript` (preferred) or
|
|
45
|
+
* `dependencies.typescript`. Strips a leading `^` or `~` semver
|
|
46
|
+
* prefix. Returns `null` on any failure mode — file missing,
|
|
47
|
+
* unreadable, malformed JSON, key absent, not a string.
|
|
48
|
+
*/
|
|
49
|
+
function readTsVersionFromPackageJson(raw) {
|
|
50
|
+
if (raw === null) return null;
|
|
51
|
+
let parsed;
|
|
52
|
+
try {
|
|
53
|
+
parsed = JSON.parse(raw);
|
|
54
|
+
} catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const candidate = pickStringDep(parsed.devDependencies) ?? pickStringDep(parsed.dependencies);
|
|
58
|
+
if (candidate === null) return null;
|
|
59
|
+
return candidate.replace(SEMVER_RANGE_PREFIX, "");
|
|
60
|
+
}
|
|
61
|
+
function pickStringDep(deps) {
|
|
62
|
+
if (deps === null || typeof deps !== "object" || Array.isArray(deps)) return null;
|
|
63
|
+
const value = deps.typescript;
|
|
64
|
+
return typeof value === "string" ? value : null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Build the full backend event from the parent's payload, the
|
|
68
|
+
* project-config slice, and the child's per-process snapshot. Pure
|
|
69
|
+
* given a `projectConfig` + `EnrichEnvironment`.
|
|
70
|
+
*/
|
|
71
|
+
function buildTelemetryEvent(payload, projectConfig, env) {
|
|
72
|
+
const runtime = resolveRuntime(env.versions);
|
|
73
|
+
return {
|
|
74
|
+
installationId: payload.installationId,
|
|
75
|
+
version: payload.version,
|
|
76
|
+
command: payload.command,
|
|
77
|
+
flags: payload.flags,
|
|
78
|
+
runtimeName: runtime.name,
|
|
79
|
+
runtimeVersion: runtime.version,
|
|
80
|
+
os: env.platform,
|
|
81
|
+
arch: env.arch,
|
|
82
|
+
packageManager: parsePackageManager(env.env.npm_config_user_agent),
|
|
83
|
+
databaseTarget: projectConfig.databaseTarget,
|
|
84
|
+
tsVersion: readTsVersionFromPackageJson(env.readProjectPackageJson()),
|
|
85
|
+
agent: env.agent,
|
|
86
|
+
extensions: projectConfig.extensions
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Resolve the agent label for the telemetry event via
|
|
91
|
+
* `@vercel/detect-agent`, collapsing its discriminated result to the
|
|
92
|
+
* event's `string | null` shape. Any detection failure counts as
|
|
93
|
+
* "no agent" — telemetry is best-effort and non-blocking.
|
|
94
|
+
*/
|
|
95
|
+
async function resolveAgentLabel() {
|
|
96
|
+
try {
|
|
97
|
+
const result = await determineAgent();
|
|
98
|
+
return result.isAgent ? result.agent.name : null;
|
|
99
|
+
} catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Convenience for the sender entry: build the event from the live
|
|
105
|
+
* `process` plus a real project-package.json reader, swallowing any
|
|
106
|
+
* I/O errors in the file read.
|
|
107
|
+
*
|
|
108
|
+
* The project-config slice is payload-only: `databaseTarget` is the
|
|
109
|
+
* parent's override when present (else `null`), and `extensions` is
|
|
110
|
+
* always empty — there is no `prisma-next.config.*` in this product to
|
|
111
|
+
* derive them from.
|
|
112
|
+
*/
|
|
113
|
+
async function buildTelemetryEventFromProcess(payload) {
|
|
114
|
+
return buildTelemetryEvent(payload, {
|
|
115
|
+
databaseTarget: payload.databaseTarget ?? null,
|
|
116
|
+
extensions: []
|
|
117
|
+
}, {
|
|
118
|
+
platform: process.platform,
|
|
119
|
+
arch: process.arch,
|
|
120
|
+
versions: process.versions,
|
|
121
|
+
env: process.env,
|
|
122
|
+
agent: await resolveAgentLabel(),
|
|
123
|
+
readProjectPackageJson: () => {
|
|
124
|
+
try {
|
|
125
|
+
return readFileSync(join(payload.projectRoot, "package.json"), "utf-8");
|
|
126
|
+
} catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Sender script entry — forked into a detached child by the parent CLI via
|
|
134
|
+
* `child_process.fork(senderPath, [], { detached: true, ... })`.
|
|
135
|
+
*
|
|
136
|
+
* Lifecycle:
|
|
137
|
+
* 1. Wait for the parent's IPC `message` event carrying a
|
|
138
|
+
* `ParentToSenderPayload`.
|
|
139
|
+
* 2. Enrich with the local-process probes (runtime, os, arch, agent,
|
|
140
|
+
* package manager, tsVersion).
|
|
141
|
+
* 3. POST the event to the endpoint URL with a hard 1.5 s timeout.
|
|
142
|
+
* 4. Exit 0 unconditionally — successful POST, network failure, server
|
|
143
|
+
* error, parse error of the response, anything else: same outcome.
|
|
144
|
+
*
|
|
145
|
+
* Every error is swallowed; the only escape valve for visibility is
|
|
146
|
+
* `PRISMA_DEBUG=1`, which routes diagnostics to stderr. In normal
|
|
147
|
+
* operation no telemetry-originating output ever reaches the user — the
|
|
148
|
+
* parent's stdio map ignores our streams anyway, but stderr writes are
|
|
149
|
+
* also held behind the debug flag so the same binary is safe to invoke
|
|
150
|
+
* directly outside the spawn flow.
|
|
151
|
+
*/
|
|
152
|
+
const REQUEST_TIMEOUT_MS = 1500;
|
|
153
|
+
function debugLog(message, error) {
|
|
154
|
+
if (process.env.PRISMA_DEBUG !== "1") return;
|
|
155
|
+
if (error !== void 0) process.stderr.write(`[cli-telemetry] ${message}: ${String(error)}\n`);
|
|
156
|
+
else process.stderr.write(`[cli-telemetry] ${message}\n`);
|
|
157
|
+
}
|
|
158
|
+
async function postEvent(payload) {
|
|
159
|
+
const event = await buildTelemetryEventFromProcess(payload);
|
|
160
|
+
const controller = new AbortController();
|
|
161
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
162
|
+
try {
|
|
163
|
+
debugLog(`sent event: status=${(await fetch(payload.endpoint, {
|
|
164
|
+
method: "POST",
|
|
165
|
+
headers: { "content-type": "application/json" },
|
|
166
|
+
body: JSON.stringify(event),
|
|
167
|
+
signal: controller.signal
|
|
168
|
+
})).status}`);
|
|
169
|
+
} catch (err) {
|
|
170
|
+
debugLog("send failed", err);
|
|
171
|
+
} finally {
|
|
172
|
+
clearTimeout(timer);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function exitClean() {
|
|
176
|
+
try {
|
|
177
|
+
process.disconnect?.();
|
|
178
|
+
} catch {}
|
|
179
|
+
process.exit(0);
|
|
180
|
+
}
|
|
181
|
+
process.once("message", (message) => {
|
|
182
|
+
if (!isParentToSenderPayload(message)) {
|
|
183
|
+
debugLog("received malformed payload; exiting");
|
|
184
|
+
exitClean();
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
postEvent(message).catch((err) => debugLog("post threw", err)).finally(exitClean);
|
|
188
|
+
});
|
|
189
|
+
const SENDER_IDLE_EXIT_MS = REQUEST_TIMEOUT_MS * 2;
|
|
190
|
+
setTimeout(exitClean, SENDER_IDLE_EXIT_MS).unref();
|
|
191
|
+
//#endregion
|
|
192
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0-rc.1",
|
|
4
4
|
"description": "Command-line interface for the Prisma Developer Platform.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"prisma-cli": "./dist/cli.js"
|
|
7
|
+
"prisma-cli": "./dist/v8/cli.js"
|
|
8
8
|
},
|
|
9
9
|
"exports": {
|
|
10
10
|
"./package.json": "./package.json"
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
20
|
"engines": {
|
|
21
|
-
"node": ">=22.
|
|
21
|
+
"node": ">=22.18.0"
|
|
22
22
|
},
|
|
23
23
|
"keywords": [
|
|
24
24
|
"prisma",
|
|
@@ -37,31 +37,39 @@
|
|
|
37
37
|
"url": "https://github.com/prisma/prisma-cli/issues"
|
|
38
38
|
},
|
|
39
39
|
"license": "Apache-2.0",
|
|
40
|
-
"scripts": {
|
|
41
|
-
"build": "tsdown",
|
|
42
|
-
"prepack": "pnpm run build",
|
|
43
|
-
"test": "vitest run"
|
|
44
|
-
},
|
|
45
40
|
"dependencies": {
|
|
46
|
-
"@clack/prompts": "
|
|
47
|
-
"@prisma/
|
|
41
|
+
"@clack/prompts": "1.5.0",
|
|
42
|
+
"@prisma/cli-engine": "8.0.0-rc.1",
|
|
43
|
+
"@prisma/composer": "0.6.0-dev.16",
|
|
44
|
+
"@prisma/compute-sdk": "0.39.0",
|
|
48
45
|
"@prisma/credentials-store": "^7.8.0",
|
|
49
|
-
"@prisma/management-api-sdk": "
|
|
46
|
+
"@prisma/management-api-sdk": "1.55.0",
|
|
47
|
+
"@prisma/orm-toolchain": "8.0.0-rc.1-dev.40",
|
|
48
|
+
"@vercel/detect-agent": "^1.2.3",
|
|
50
49
|
"better-result": "^2.9.2",
|
|
51
50
|
"colorette": "^2.0.20",
|
|
52
51
|
"commander": "^14.0.3",
|
|
53
52
|
"dotenv": "^17.4.2",
|
|
54
|
-
"
|
|
53
|
+
"execa": "^9.6.1",
|
|
55
54
|
"open": "^11.0.0",
|
|
56
55
|
"string-width": "^8.2.1",
|
|
57
56
|
"strip-ansi": "^7.2.0",
|
|
58
57
|
"wrap-ansi": "^10.0.0"
|
|
59
58
|
},
|
|
60
59
|
"devDependencies": {
|
|
60
|
+
"@repo/cli-telemetry": "8.0.0-rc.1",
|
|
61
|
+
"@repo/tsconfig": "8.0.0-rc.1",
|
|
61
62
|
"@types/node": "^22.19.19",
|
|
62
63
|
"tsdown": "^0.21.10",
|
|
63
64
|
"tsx": "^4.22.4",
|
|
64
65
|
"typescript": "^6.0.3",
|
|
65
66
|
"vitest": "^4.1.8"
|
|
67
|
+
},
|
|
68
|
+
"scripts": {
|
|
69
|
+
"build": "tsdown",
|
|
70
|
+
"check:grammar": "vitest run tests/v8-mount-coverage.test.ts",
|
|
71
|
+
"typecheck": "tsc --noEmit",
|
|
72
|
+
"test": "vitest run",
|
|
73
|
+
"test:e2e": "vitest run --config vitest.e2e.config.ts"
|
|
66
74
|
}
|
|
67
|
-
}
|
|
75
|
+
}
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
//#region src/adapters/mock-api.ts
|
|
3
|
-
var MockApi = class MockApi {
|
|
4
|
-
data;
|
|
5
|
-
constructor(data) {
|
|
6
|
-
this.data = data;
|
|
7
|
-
}
|
|
8
|
-
static async load(fixturePath, signal) {
|
|
9
|
-
signal?.throwIfAborted();
|
|
10
|
-
const raw = await readFile(fixturePath, {
|
|
11
|
-
encoding: "utf8",
|
|
12
|
-
signal
|
|
13
|
-
});
|
|
14
|
-
return new MockApi(JSON.parse(raw));
|
|
15
|
-
}
|
|
16
|
-
listProviders() {
|
|
17
|
-
return this.data.providers;
|
|
18
|
-
}
|
|
19
|
-
getProvider(providerId) {
|
|
20
|
-
return this.data.providers.find((provider) => provider.id === providerId);
|
|
21
|
-
}
|
|
22
|
-
listUsersForProvider(providerId) {
|
|
23
|
-
return this.data.users.filter((user) => user.providerIds.includes(providerId));
|
|
24
|
-
}
|
|
25
|
-
getUser(userId) {
|
|
26
|
-
return this.data.users.find((user) => user.id === userId);
|
|
27
|
-
}
|
|
28
|
-
getUserForProvider(providerId, userId) {
|
|
29
|
-
return this.listUsersForProvider(providerId).find((user) => user.id === userId);
|
|
30
|
-
}
|
|
31
|
-
listUserWorkspaces(userId) {
|
|
32
|
-
const workspaceIds = this.data.memberships.filter((membership) => membership.userId === userId).map((membership) => membership.workspaceId);
|
|
33
|
-
return this.data.workspaces.filter((workspace) => workspaceIds.includes(workspace.id));
|
|
34
|
-
}
|
|
35
|
-
getWorkspace(workspaceId) {
|
|
36
|
-
return this.data.workspaces.find((workspace) => workspace.id === workspaceId);
|
|
37
|
-
}
|
|
38
|
-
getUserWorkspace(userId, workspaceId) {
|
|
39
|
-
return this.listUserWorkspaces(userId).find((workspace) => workspace.id === workspaceId);
|
|
40
|
-
}
|
|
41
|
-
listProjectsForWorkspace(workspaceId) {
|
|
42
|
-
return this.data.projects.filter((project) => project.workspaceId === workspaceId);
|
|
43
|
-
}
|
|
44
|
-
getProject(projectId) {
|
|
45
|
-
return this.data.projects.find((project) => project.id === projectId);
|
|
46
|
-
}
|
|
47
|
-
getProjectForWorkspace(workspaceId, projectId) {
|
|
48
|
-
return this.listProjectsForWorkspace(workspaceId).find((project) => project.id === projectId);
|
|
49
|
-
}
|
|
50
|
-
listBranchesForProject(projectId) {
|
|
51
|
-
return this.data.branches.filter((branch) => branch.projectId === projectId);
|
|
52
|
-
}
|
|
53
|
-
getBranchForProject(projectId, name) {
|
|
54
|
-
return this.listBranchesForProject(projectId).find((branch) => branch.name === name);
|
|
55
|
-
}
|
|
56
|
-
getDeployment(deploymentId) {
|
|
57
|
-
return this.data.deployments.find((deployment) => deployment.id === deploymentId);
|
|
58
|
-
}
|
|
59
|
-
listDatabasesForProject(projectId, branchName) {
|
|
60
|
-
return (this.data.databases ?? []).filter((database) => database.projectId === projectId && (!branchName || database.branchName === branchName));
|
|
61
|
-
}
|
|
62
|
-
getDatabase(databaseId) {
|
|
63
|
-
return (this.data.databases ?? []).find((database) => database.id === databaseId);
|
|
64
|
-
}
|
|
65
|
-
createDatabase(input) {
|
|
66
|
-
this.data.databases ??= [];
|
|
67
|
-
this.data.databaseConnections ??= [];
|
|
68
|
-
const database = {
|
|
69
|
-
id: `db_${this.data.databases.length + 1e3}`,
|
|
70
|
-
projectId: input.projectId,
|
|
71
|
-
branchId: input.branchName ? this.getBranchForProject(input.projectId, input.branchName)?.id ?? null : null,
|
|
72
|
-
branchName: input.branchName ?? null,
|
|
73
|
-
name: input.name,
|
|
74
|
-
region: input.region ?? null,
|
|
75
|
-
status: "ready",
|
|
76
|
-
isDefault: false,
|
|
77
|
-
createdAt: "2026-06-09T00:00:00.000Z"
|
|
78
|
-
};
|
|
79
|
-
const connectionString = `postgresql://${database.id}.example.prisma.io/postgres`;
|
|
80
|
-
const connection = {
|
|
81
|
-
id: `conn_${this.data.databaseConnections.length + 1e3}`,
|
|
82
|
-
databaseId: database.id,
|
|
83
|
-
name: "primary",
|
|
84
|
-
createdAt: "2026-06-09T00:00:00.000Z",
|
|
85
|
-
connectionString
|
|
86
|
-
};
|
|
87
|
-
this.data.databases.push(database);
|
|
88
|
-
this.data.databaseConnections.push(connection);
|
|
89
|
-
return {
|
|
90
|
-
database,
|
|
91
|
-
connection,
|
|
92
|
-
connectionString
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
removeDatabase(databaseId) {
|
|
96
|
-
this.data.databases ??= [];
|
|
97
|
-
this.data.databaseConnections ??= [];
|
|
98
|
-
const database = this.getDatabase(databaseId);
|
|
99
|
-
if (!database) return;
|
|
100
|
-
this.data.databases = this.data.databases.filter((candidate) => candidate.id !== databaseId);
|
|
101
|
-
this.data.databaseConnections = this.data.databaseConnections.filter((connection) => connection.databaseId !== databaseId);
|
|
102
|
-
return database;
|
|
103
|
-
}
|
|
104
|
-
listDatabaseConnections(databaseId) {
|
|
105
|
-
return (this.data.databaseConnections ?? []).filter((connection) => connection.databaseId === databaseId);
|
|
106
|
-
}
|
|
107
|
-
getDatabaseConnection(connectionId) {
|
|
108
|
-
return (this.data.databaseConnections ?? []).find((connection) => connection.id === connectionId);
|
|
109
|
-
}
|
|
110
|
-
createDatabaseConnection(input) {
|
|
111
|
-
if (!this.getDatabase(input.databaseId)) return;
|
|
112
|
-
this.data.databaseConnections ??= [];
|
|
113
|
-
const connectionString = `postgresql://${input.databaseId}-${this.data.databaseConnections.length + 1}.example.prisma.io/postgres`;
|
|
114
|
-
const connection = {
|
|
115
|
-
id: `conn_${this.data.databaseConnections.length + 1e3}`,
|
|
116
|
-
databaseId: input.databaseId,
|
|
117
|
-
name: input.name,
|
|
118
|
-
createdAt: "2026-06-09T00:00:00.000Z",
|
|
119
|
-
connectionString
|
|
120
|
-
};
|
|
121
|
-
this.data.databaseConnections.push(connection);
|
|
122
|
-
return {
|
|
123
|
-
connection,
|
|
124
|
-
connectionString
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
removeDatabaseConnection(connectionId) {
|
|
128
|
-
this.data.databaseConnections ??= [];
|
|
129
|
-
const connection = this.getDatabaseConnection(connectionId);
|
|
130
|
-
if (!connection) return;
|
|
131
|
-
this.data.databaseConnections = this.data.databaseConnections.filter((candidate) => candidate.id !== connectionId);
|
|
132
|
-
return connection;
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
//#endregion
|
|
136
|
-
export { MockApi };
|
package/dist/use-cases/auth.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { authRequiredError, usageError, workspaceAmbiguousError, workspaceNotAuthenticatedError } from "../shell/errors.js";
|
|
2
|
-
//#region src/use-cases/auth.ts
|
|
3
|
-
function createAuthUseCases(dependencies) {
|
|
4
|
-
return {
|
|
5
|
-
whoami: () => resolveCurrentAuthState(dependencies),
|
|
6
|
-
login: async (selection) => {
|
|
7
|
-
await dependencies.sessionGateway.writeAuthSession({
|
|
8
|
-
provider: selection.provider,
|
|
9
|
-
userId: selection.userId,
|
|
10
|
-
workspaceId: selection.workspaceId
|
|
11
|
-
});
|
|
12
|
-
return resolveCurrentAuthState(dependencies);
|
|
13
|
-
},
|
|
14
|
-
logout: async () => {
|
|
15
|
-
await dependencies.sessionGateway.clearAuthSession();
|
|
16
|
-
return resolveCurrentAuthState(dependencies);
|
|
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
|
-
},
|
|
82
|
-
listProviders: async () => dependencies.identityGateway.listProviders(),
|
|
83
|
-
resolveProvider: async (providerId) => {
|
|
84
|
-
const provider = dependencies.identityGateway.getProvider(providerId);
|
|
85
|
-
if (!provider) throw usageError("Login requires a valid mock provider", `The mock provider "${providerId}" does not exist.`, "Use --provider github or --provider google.", ["prisma-cli auth login"], "auth");
|
|
86
|
-
return provider;
|
|
87
|
-
},
|
|
88
|
-
listUsersForProvider: async (providerId) => {
|
|
89
|
-
const users = dependencies.identityGateway.listUsersForProvider(providerId);
|
|
90
|
-
if (users.length === 0) throw usageError("Login requires a valid mock user", `No mock users support provider "${providerId}".`, "Update the fixture data or choose a different provider.", ["prisma-cli auth login"], "auth");
|
|
91
|
-
return users;
|
|
92
|
-
},
|
|
93
|
-
resolveUserForProvider: async (providerId, userId) => {
|
|
94
|
-
const user = dependencies.identityGateway.getUserForProvider(providerId, userId);
|
|
95
|
-
if (!user) throw usageError("Login requires a valid mock user", `The mock user "${userId}" is not available for provider "${providerId}".`, "Choose a user that supports the selected provider.", ["prisma-cli auth login"], "auth");
|
|
96
|
-
return user;
|
|
97
|
-
},
|
|
98
|
-
listWorkspacesForUser: async (userId) => dependencies.identityGateway.listUserWorkspaces(userId),
|
|
99
|
-
resolveWorkspaceForUser: async (userId, workspaceId) => {
|
|
100
|
-
const workspace = dependencies.identityGateway.getUserWorkspace(userId, workspaceId);
|
|
101
|
-
if (!workspace) throw usageError("Login requires a valid mock workspace", `The mock workspace "${workspaceId}" is not available for the selected user.`, "Choose a workspace that the selected user can access.", ["prisma-cli auth login"], "auth");
|
|
102
|
-
return workspace;
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
function workspaceMatchesRef(workspace, ref) {
|
|
107
|
-
return workspace.id === ref || workspace.name.toLowerCase() === ref.toLowerCase();
|
|
108
|
-
}
|
|
109
|
-
async function resolveCurrentAuthState(dependencies) {
|
|
110
|
-
const session = await dependencies.sessionGateway.readAuthSession();
|
|
111
|
-
if (!session) return {
|
|
112
|
-
authenticated: false,
|
|
113
|
-
provider: null,
|
|
114
|
-
user: null,
|
|
115
|
-
workspace: null,
|
|
116
|
-
credential: null
|
|
117
|
-
};
|
|
118
|
-
const provider = dependencies.identityGateway.getProvider(session.provider);
|
|
119
|
-
const user = dependencies.identityGateway.getUser(session.userId);
|
|
120
|
-
const workspace = dependencies.identityGateway.getWorkspace(session.workspaceId);
|
|
121
|
-
if (!provider || !user || !workspace) return {
|
|
122
|
-
authenticated: false,
|
|
123
|
-
provider: null,
|
|
124
|
-
user: null,
|
|
125
|
-
workspace: null,
|
|
126
|
-
credential: null
|
|
127
|
-
};
|
|
128
|
-
return {
|
|
129
|
-
authenticated: true,
|
|
130
|
-
provider: provider.id,
|
|
131
|
-
user: {
|
|
132
|
-
id: user.id,
|
|
133
|
-
email: user.email,
|
|
134
|
-
name: user.name
|
|
135
|
-
},
|
|
136
|
-
workspace,
|
|
137
|
-
credential: {
|
|
138
|
-
type: "oauth",
|
|
139
|
-
id: null,
|
|
140
|
-
name: null
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
//#endregion
|
|
145
|
-
export { createAuthUseCases };
|
package/dist/use-cases/branch.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
//#region src/use-cases/branch.ts
|
|
2
|
-
function createBranchUseCases(dependencies) {
|
|
3
|
-
return { list: async () => {
|
|
4
|
-
const projectId = await dependencies.projectStateGateway.readRememberedProjectId();
|
|
5
|
-
if (!projectId) return {
|
|
6
|
-
projectId: "",
|
|
7
|
-
projectName: "not resolved",
|
|
8
|
-
branches: []
|
|
9
|
-
};
|
|
10
|
-
const remoteBranches = await listRemoteBranches(dependencies.branchGateway, projectId);
|
|
11
|
-
return {
|
|
12
|
-
projectId,
|
|
13
|
-
projectName: resolveProjectName(dependencies.projectGateway, projectId) ?? "not resolved",
|
|
14
|
-
branches: buildBranchSummaries(remoteBranches)
|
|
15
|
-
};
|
|
16
|
-
} };
|
|
17
|
-
}
|
|
18
|
-
function resolveProjectName(projectGateway, projectId) {
|
|
19
|
-
if (!projectId) return null;
|
|
20
|
-
return projectGateway.getProject(projectId)?.name ?? null;
|
|
21
|
-
}
|
|
22
|
-
async function listRemoteBranches(branchGateway, projectId) {
|
|
23
|
-
if (!projectId) return [];
|
|
24
|
-
return branchGateway.listBranchesForProject(projectId);
|
|
25
|
-
}
|
|
26
|
-
function buildBranchSummaries(remoteBranches) {
|
|
27
|
-
return sortBranches(remoteBranches.map((branch) => ({
|
|
28
|
-
id: branch.id,
|
|
29
|
-
name: branch.name,
|
|
30
|
-
role: branch.role,
|
|
31
|
-
envMap: branch.role
|
|
32
|
-
})));
|
|
33
|
-
}
|
|
34
|
-
function sortBranches(branches) {
|
|
35
|
-
return branches.slice().sort((left, right) => {
|
|
36
|
-
const leftRank = branchOrder(left);
|
|
37
|
-
const rightRank = branchOrder(right);
|
|
38
|
-
if (leftRank !== rightRank) return leftRank - rightRank;
|
|
39
|
-
return left.name.localeCompare(right.name);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
function branchOrder(branch) {
|
|
43
|
-
if (branch.role === "production") return 0;
|
|
44
|
-
return 1;
|
|
45
|
-
}
|
|
46
|
-
//#endregion
|
|
47
|
-
export { createBranchUseCases };
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
//#region src/use-cases/create-cli-gateways.ts
|
|
2
|
-
function createCliUseCaseGateways(context) {
|
|
3
|
-
return {
|
|
4
|
-
identityGateway: {
|
|
5
|
-
listProviders: () => context.api.listProviders(),
|
|
6
|
-
getProvider: (providerId) => context.api.getProvider(providerId),
|
|
7
|
-
listUsersForProvider: (providerId) => context.api.listUsersForProvider(providerId).map(toAuthUser),
|
|
8
|
-
getUser: (userId) => {
|
|
9
|
-
const user = context.api.getUser(userId);
|
|
10
|
-
return user ? toAuthUser(user) : void 0;
|
|
11
|
-
},
|
|
12
|
-
getUserForProvider: (providerId, userId) => {
|
|
13
|
-
const user = context.api.getUserForProvider(providerId, userId);
|
|
14
|
-
return user ? toAuthUser(user) : void 0;
|
|
15
|
-
},
|
|
16
|
-
listUserWorkspaces: (userId) => context.api.listUserWorkspaces(userId).map(toAuthWorkspace),
|
|
17
|
-
getWorkspace: (workspaceId) => {
|
|
18
|
-
const workspace = context.api.getWorkspace(workspaceId);
|
|
19
|
-
return workspace ? toAuthWorkspace(workspace) : void 0;
|
|
20
|
-
},
|
|
21
|
-
getUserWorkspace: (userId, workspaceId) => {
|
|
22
|
-
const workspace = context.api.getUserWorkspace(userId, workspaceId);
|
|
23
|
-
return workspace ? toAuthWorkspace(workspace) : void 0;
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
projectGateway: {
|
|
27
|
-
listProjectsForWorkspace: (workspaceId) => context.api.listProjectsForWorkspace(workspaceId),
|
|
28
|
-
getProject: (projectId) => context.api.getProject(projectId),
|
|
29
|
-
getProjectForWorkspace: (workspaceId, projectId) => context.api.getProjectForWorkspace(workspaceId, projectId)
|
|
30
|
-
},
|
|
31
|
-
branchGateway: {
|
|
32
|
-
listBranchesForProject: (projectId) => context.api.listBranchesForProject(projectId),
|
|
33
|
-
getBranchForProject: (projectId, name) => {
|
|
34
|
-
return context.api.getBranchForProject(projectId, name);
|
|
35
|
-
},
|
|
36
|
-
getDeployment: (deploymentId) => context.api.getDeployment(deploymentId)
|
|
37
|
-
},
|
|
38
|
-
projectStateGateway: { readRememberedProjectId: async () => {
|
|
39
|
-
return (await context.stateStore.readLastResolvedProject())?.id ?? null;
|
|
40
|
-
} },
|
|
41
|
-
sessionGateway: {
|
|
42
|
-
readAuthSession: async () => {
|
|
43
|
-
return (await context.stateStore.read()).auth;
|
|
44
|
-
},
|
|
45
|
-
writeAuthSession: async (session) => {
|
|
46
|
-
await context.stateStore.setAuthSession(session);
|
|
47
|
-
},
|
|
48
|
-
clearAuthSession: async () => {
|
|
49
|
-
await context.stateStore.clearAuthSession();
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
function toAuthUser(user) {
|
|
55
|
-
return {
|
|
56
|
-
id: user.id,
|
|
57
|
-
name: user.name,
|
|
58
|
-
email: user.email
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
function toAuthWorkspace(workspace) {
|
|
62
|
-
return {
|
|
63
|
-
id: workspace.id,
|
|
64
|
-
name: workspace.name
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
//#endregion
|
|
68
|
-
export { createCliUseCaseGateways };
|