@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.
Files changed (87) hide show
  1. package/README.md +3 -1
  2. package/dist/cli.js +15115 -16
  3. package/dist/deploy-framework-C7bQM00A.js +23 -0
  4. package/dist/payload-B88Qvzxk-CrtTXSOe.js +34 -0
  5. package/dist/sender.js +192 -0
  6. package/package.json +22 -18
  7. package/dist/adapters/git.js +0 -54
  8. package/dist/adapters/local-state.js +0 -144
  9. package/dist/adapters/mock-api.js +0 -136
  10. package/dist/adapters/token-storage.js +0 -418
  11. package/dist/cli2.js +0 -119
  12. package/dist/commands/app/index.js +0 -345
  13. package/dist/commands/auth/index.js +0 -96
  14. package/dist/commands/branch/index.js +0 -27
  15. package/dist/commands/database/index.js +0 -159
  16. package/dist/commands/env.js +0 -99
  17. package/dist/commands/git/index.js +0 -36
  18. package/dist/commands/project/index.js +0 -69
  19. package/dist/commands/version/index.js +0 -18
  20. package/dist/controllers/app-env-api.js +0 -54
  21. package/dist/controllers/app-env-file.js +0 -181
  22. package/dist/controllers/app-env.js +0 -502
  23. package/dist/controllers/app.js +0 -2443
  24. package/dist/controllers/auth.js +0 -316
  25. package/dist/controllers/branch.js +0 -103
  26. package/dist/controllers/database.js +0 -318
  27. package/dist/controllers/project.js +0 -731
  28. package/dist/controllers/select-prompt-port.js +0 -12
  29. package/dist/controllers/version.js +0 -12
  30. package/dist/lib/app/app-interaction.js +0 -5
  31. package/dist/lib/app/app-provider.js +0 -544
  32. package/dist/lib/app/branch-database-api.js +0 -102
  33. package/dist/lib/app/branch-database-deploy.js +0 -325
  34. package/dist/lib/app/branch-database.js +0 -215
  35. package/dist/lib/app/build-settings.js +0 -93
  36. package/dist/lib/app/build.js +0 -80
  37. package/dist/lib/app/bun-project.js +0 -45
  38. package/dist/lib/app/compute-config.js +0 -147
  39. package/dist/lib/app/deploy-output.js +0 -24
  40. package/dist/lib/app/deploy-plan.js +0 -58
  41. package/dist/lib/app/deploy-progress.js +0 -100
  42. package/dist/lib/app/domain-guidance.js +0 -14
  43. package/dist/lib/app/env-config.js +0 -67
  44. package/dist/lib/app/env-file.js +0 -82
  45. package/dist/lib/app/env-vars.js +0 -50
  46. package/dist/lib/app/local-dev.js +0 -109
  47. package/dist/lib/app/production-deploy-gate.js +0 -161
  48. package/dist/lib/app/read-branch.js +0 -30
  49. package/dist/lib/auth/auth-ops.js +0 -158
  50. package/dist/lib/auth/client.js +0 -22
  51. package/dist/lib/auth/guard.js +0 -38
  52. package/dist/lib/auth/login.js +0 -330
  53. package/dist/lib/database/provider.js +0 -167
  54. package/dist/lib/diagnostics.js +0 -15
  55. package/dist/lib/fs/home-path.js +0 -24
  56. package/dist/lib/git/local-branch.js +0 -53
  57. package/dist/lib/git/local-status.js +0 -57
  58. package/dist/lib/project/interactive-setup.js +0 -56
  59. package/dist/lib/project/local-pin.js +0 -200
  60. package/dist/lib/project/resolution.js +0 -386
  61. package/dist/lib/project/setup.js +0 -135
  62. package/dist/lib/version.js +0 -55
  63. package/dist/output/patterns.js +0 -90
  64. package/dist/presenters/app-env.js +0 -265
  65. package/dist/presenters/app.js +0 -646
  66. package/dist/presenters/auth.js +0 -183
  67. package/dist/presenters/branch.js +0 -46
  68. package/dist/presenters/database.js +0 -274
  69. package/dist/presenters/project.js +0 -174
  70. package/dist/presenters/verbose-context.js +0 -64
  71. package/dist/presenters/version.js +0 -29
  72. package/dist/shell/command-arguments.js +0 -6
  73. package/dist/shell/command-meta.js +0 -622
  74. package/dist/shell/command-runner.js +0 -112
  75. package/dist/shell/diagnostics-output.js +0 -57
  76. package/dist/shell/errors.js +0 -134
  77. package/dist/shell/global-flags.js +0 -37
  78. package/dist/shell/help.js +0 -89
  79. package/dist/shell/output.js +0 -82
  80. package/dist/shell/prompt.js +0 -41
  81. package/dist/shell/runtime.js +0 -55
  82. package/dist/shell/ui.js +0 -116
  83. package/dist/shell/update-check.js +0 -247
  84. package/dist/use-cases/auth.js +0 -145
  85. package/dist/use-cases/branch.js +0 -47
  86. package/dist/use-cases/create-cli-gateways.js +0 -68
  87. package/dist/use-cases/project.js +0 -30
@@ -0,0 +1,23 @@
1
+ import path from "node:path";
2
+ import { detectComputeAppFromDirectory } from "@prisma/compute-sdk/config/directory";
3
+ //#region src/lib/app/deploy-framework.ts
4
+ /** Reads the directory's package.json and framework config to name the
5
+ * framework a deploy would use, or null when none is recognised. */
6
+ async function detectDeployFramework(cwd, signal) {
7
+ const detected = await detectComputeAppFromDirectory({
8
+ appPath: cwd,
9
+ signal
10
+ });
11
+ if (!detected) return null;
12
+ let annotation = "detected from package.json";
13
+ if (detected.configFile?.standaloneOutput) annotation = "standalone output detected";
14
+ else if (detected.configFile) annotation = `detected from ${path.basename(detected.configFile.path)}`;
15
+ return {
16
+ key: detected.framework,
17
+ buildType: detected.buildType,
18
+ displayName: detected.frameworkName,
19
+ annotation
20
+ };
21
+ }
22
+ //#endregion
23
+ export { detectDeployFramework };
@@ -0,0 +1,34 @@
1
+ //#region ../cli-telemetry/dist/payload-B88Qvzxk.js
2
+ function isNonEmptyString(value) {
3
+ return typeof value === "string" && value.length > 0;
4
+ }
5
+ function isStringArray(value) {
6
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string");
7
+ }
8
+ /**
9
+ * Runtime validation for {@link ParentToSenderPayload}. The child sender
10
+ * uses this before `postEvent` so a payload missing a required field
11
+ * cannot silently produce a degraded telemetry event downstream.
12
+ *
13
+ * Same semantics as the ORM CLI's arktype schema (this repo carries no
14
+ * arktype dependency, so the checks are spelled out): required scalars
15
+ * must be non-empty strings; the optional `databaseTarget` override is
16
+ * a `string` when present (no `null` — see the type's doc-block); the
17
+ * string array is validated element-by-element. Size caps are enforced
18
+ * by the backend, not here — IPC is structured-cloned and the
19
+ * parent/child agree on the schema by version-coupling.
20
+ */
21
+ function isParentToSenderPayload(value) {
22
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
23
+ const record = value;
24
+ if (!isNonEmptyString(record.installationId)) return false;
25
+ if (!isNonEmptyString(record.version)) return false;
26
+ if (!isNonEmptyString(record.command)) return false;
27
+ if (!isStringArray(record.flags)) return false;
28
+ if (!isNonEmptyString(record.projectRoot)) return false;
29
+ if (!isNonEmptyString(record.endpoint)) return false;
30
+ if ("databaseTarget" in record && typeof record.databaseTarget !== "string") return false;
31
+ return true;
32
+ }
33
+ //#endregion
34
+ export { isParentToSenderPayload as t };
package/dist/sender.js ADDED
@@ -0,0 +1,192 @@
1
+ import { t as isParentToSenderPayload } from "./payload-B88Qvzxk-CrtTXSOe.js";
2
+ import { readFileSync } from "node:fs";
3
+ import { join } from "node:path";
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/cli",
3
- "version": "3.0.0-dev.99.1",
3
+ "version": "8.0.0-rc.2",
4
4
  "description": "Command-line interface for the Prisma Developer Platform.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,7 +18,7 @@
18
18
  "access": "public"
19
19
  },
20
20
  "engines": {
21
- "node": ">=22.12.0"
21
+ "node": ">=22.18.0"
22
22
  },
23
23
  "keywords": [
24
24
  "prisma",
@@ -37,31 +37,35 @@
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": "^1.5.0",
47
- "@prisma/compute-sdk": "^0.28.0",
41
+ "@prisma/cli-engine": "8.0.0-rc.2",
42
+ "@prisma/composer": "0.6.0-dev.16",
43
+ "@prisma/compute-sdk": "0.39.0",
48
44
  "@prisma/credentials-store": "^7.8.0",
49
- "@prisma/management-api-sdk": "^1.37.0",
45
+ "@prisma/management-api-sdk": "1.55.0",
46
+ "@prisma/orm-toolchain": "8.0.0-rc.1-dev.40",
47
+ "@vercel/detect-agent": "^1.2.3",
50
48
  "better-result": "^2.9.2",
51
- "colorette": "^2.0.20",
52
- "commander": "^14.0.3",
53
49
  "dotenv": "^17.4.2",
54
- "magicast": "^0.5.3",
55
- "open": "^11.0.0",
56
- "string-width": "^8.2.1",
57
- "strip-ansi": "^7.2.0",
58
- "wrap-ansi": "^10.0.0"
50
+ "execa": "^9.6.1",
51
+ "open": "^11.0.0"
59
52
  },
60
53
  "devDependencies": {
54
+ "@repo/cli-conformance": "8.0.0-rc.2",
55
+ "@repo/cli-telemetry": "8.0.0-rc.2",
56
+ "@repo/tsconfig": "8.0.0-rc.2",
61
57
  "@types/node": "^22.19.19",
62
58
  "tsdown": "^0.21.10",
63
59
  "tsx": "^4.22.4",
64
60
  "typescript": "^6.0.3",
65
61
  "vitest": "^4.1.8"
62
+ },
63
+ "scripts": {
64
+ "build": "tsdown",
65
+ "check:grammar": "vitest run tests/mount-coverage.test.ts",
66
+ "typecheck": "tsc --noEmit",
67
+ "test": "pnpm run build && vitest run",
68
+ "test:e2e": "vitest run --config vitest.e2e.config.ts",
69
+ "conformance": "tsx scripts/conformance.ts"
66
70
  }
67
- }
71
+ }
@@ -1,54 +0,0 @@
1
- import { execFile } from "node:child_process";
2
- import { promisify } from "node:util";
3
- //#region src/adapters/git.ts
4
- const execFileAsync = promisify(execFile);
5
- async function readGitOriginRemote(cwd, signal) {
6
- try {
7
- const { stdout } = await execFileAsync("git", [
8
- "config",
9
- "--get",
10
- "remote.origin.url"
11
- ], {
12
- cwd,
13
- timeout: 5e3,
14
- signal
15
- });
16
- const remote = stdout.trim();
17
- return remote.length > 0 ? remote : null;
18
- } catch (error) {
19
- if (signal?.aborted || isAbortError(error)) throw error;
20
- return null;
21
- }
22
- }
23
- function isAbortError(error) {
24
- return error instanceof Error && error.name === "AbortError";
25
- }
26
- function parseGitHubRepositoryUrl(value) {
27
- const input = value.trim();
28
- const shorthand = input.match(/^git@github\.com:([^/\s]+)\/([^/\s]+?)(?:\.git)?$/);
29
- if (shorthand) return toGitHubRepositoryReference(shorthand[1], shorthand[2]);
30
- let parsed;
31
- try {
32
- parsed = new URL(input);
33
- } catch {
34
- return null;
35
- }
36
- if (parsed.hostname !== "github.com") return null;
37
- if (parsed.protocol !== "https:" && parsed.protocol !== "http:" && parsed.protocol !== "ssh:") return null;
38
- const parts = parsed.pathname.split("/").filter(Boolean);
39
- if (parts.length !== 2) return null;
40
- const [owner, rawName] = parts;
41
- return toGitHubRepositoryReference(owner, rawName.endsWith(".git") ? rawName.slice(0, -4) : rawName);
42
- }
43
- function toGitHubRepositoryReference(owner, name) {
44
- if (!owner || !name || owner.includes("/") || name.includes("/")) return null;
45
- return {
46
- provider: "github",
47
- owner,
48
- name,
49
- fullName: `${owner}/${name}`,
50
- url: `https://github.com/${owner}/${name}`
51
- };
52
- }
53
- //#endregion
54
- export { parseGitHubRepositoryUrl, readGitOriginRemote };
@@ -1,144 +0,0 @@
1
- import { mkdir, readFile, writeFile } from "node:fs/promises";
2
- import path from "node:path";
3
- //#region src/adapters/local-state.ts
4
- const DEFAULT_STATE = {
5
- auth: null,
6
- project: {
7
- rememberedByWorkspace: {},
8
- lastResolved: null,
9
- repositoryConnectionsByProject: {}
10
- },
11
- branch: { active: "preview" },
12
- app: {
13
- selectedByProject: {},
14
- knownLiveDeploymentByProject: {}
15
- }
16
- };
17
- const DEFAULT_STATE_FILE_NAME = "state.json";
18
- function resolveLocalStateFilePath(stateDir) {
19
- return path.join(stateDir, DEFAULT_STATE_FILE_NAME);
20
- }
21
- var LocalStateStore = class {
22
- stateFilePath;
23
- constructor(stateDir, signal) {
24
- this.signal = signal;
25
- this.stateFilePath = resolveLocalStateFilePath(stateDir);
26
- }
27
- async read() {
28
- this.signal?.throwIfAborted();
29
- try {
30
- const raw = await readFile(this.stateFilePath, {
31
- encoding: "utf8",
32
- signal: this.signal
33
- });
34
- const parsed = JSON.parse(raw);
35
- return {
36
- auth: parsed.auth ?? structuredClone(DEFAULT_STATE.auth),
37
- project: {
38
- rememberedByWorkspace: parsed.project?.rememberedByWorkspace ?? {},
39
- lastResolved: parsed.project?.lastResolved ?? null,
40
- repositoryConnectionsByProject: parsed.project?.repositoryConnectionsByProject ?? {}
41
- },
42
- branch: { active: parsed.branch?.active ?? DEFAULT_STATE.branch.active },
43
- app: {
44
- selectedByProject: parsed.app?.selectedByProject ?? {},
45
- knownLiveDeploymentByProject: parsed.app?.knownLiveDeploymentByProject ?? {}
46
- }
47
- };
48
- } catch (error) {
49
- if (error.code === "ENOENT") return structuredClone(DEFAULT_STATE);
50
- throw error;
51
- }
52
- }
53
- async write(state) {
54
- this.signal?.throwIfAborted();
55
- await mkdir(path.dirname(this.stateFilePath), { recursive: true });
56
- this.signal?.throwIfAborted();
57
- await writeFile(this.stateFilePath, `${JSON.stringify(state, null, 2)}\n`, { encoding: "utf8" });
58
- this.signal?.throwIfAborted();
59
- }
60
- async setAuthSession(session) {
61
- const state = await this.read();
62
- state.auth = session;
63
- await this.write(state);
64
- return state;
65
- }
66
- async clearAuthSession() {
67
- const state = await this.read();
68
- state.auth = null;
69
- await this.write(state);
70
- return state;
71
- }
72
- async setActiveBranch(active) {
73
- const state = await this.read();
74
- state.branch.active = active;
75
- await this.write(state);
76
- return state;
77
- }
78
- async readRememberedProject(workspaceId) {
79
- return (await this.read()).project.rememberedByWorkspace[workspaceId] ?? null;
80
- }
81
- async readLastResolvedProject() {
82
- return (await this.read()).project.lastResolved;
83
- }
84
- async setRememberedProject(project) {
85
- const state = await this.read();
86
- state.project.rememberedByWorkspace[project.workspaceId] = project;
87
- state.project.lastResolved = project;
88
- await this.write(state);
89
- return state;
90
- }
91
- async readRepositoryConnection(projectId) {
92
- return (await this.read()).project.repositoryConnectionsByProject[projectId] ?? null;
93
- }
94
- async setRepositoryConnection(projectId, connection) {
95
- const state = await this.read();
96
- state.project.repositoryConnectionsByProject[projectId] = connection;
97
- await this.write(state);
98
- return state;
99
- }
100
- async clearRepositoryConnection(projectId) {
101
- const state = await this.read();
102
- delete state.project.repositoryConnectionsByProject[projectId];
103
- await this.write(state);
104
- return state;
105
- }
106
- async readSelectedApp(projectId) {
107
- return (await this.read()).app.selectedByProject[projectId] ?? null;
108
- }
109
- async setSelectedApp(projectId, app) {
110
- const state = await this.read();
111
- state.app.selectedByProject[projectId] = app;
112
- await this.write(state);
113
- return state;
114
- }
115
- async clearSelectedApp(projectId, appId) {
116
- const state = await this.read();
117
- const selectedApp = state.app.selectedByProject[projectId];
118
- if (!selectedApp || selectedApp.id !== appId) return state;
119
- delete state.app.selectedByProject[projectId];
120
- await this.write(state);
121
- return state;
122
- }
123
- async readKnownLiveDeployment(projectId, appId) {
124
- return (await this.read()).app.knownLiveDeploymentByProject[projectId]?.[appId] ?? null;
125
- }
126
- async setKnownLiveDeployment(projectId, appId, deploymentId) {
127
- const state = await this.read();
128
- state.app.knownLiveDeploymentByProject[projectId] ??= {};
129
- state.app.knownLiveDeploymentByProject[projectId][appId] = deploymentId;
130
- await this.write(state);
131
- return state;
132
- }
133
- async clearKnownLiveDeployment(projectId, appId) {
134
- const state = await this.read();
135
- const projectDeployments = state.app.knownLiveDeploymentByProject[projectId];
136
- if (!projectDeployments || !(appId in projectDeployments)) return state;
137
- delete projectDeployments[appId];
138
- if (Object.keys(projectDeployments).length === 0) delete state.app.knownLiveDeploymentByProject[projectId];
139
- await this.write(state);
140
- return state;
141
- }
142
- };
143
- //#endregion
144
- export { LocalStateStore, resolveLocalStateFilePath };
@@ -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 };