@prisma/cli 3.0.0-alpha.0 → 3.0.0-alpha.10

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 (55) hide show
  1. package/README.md +1 -16
  2. package/dist/adapters/git.js +49 -0
  3. package/dist/adapters/local-state.js +39 -1
  4. package/dist/cli2.js +60 -4
  5. package/dist/commands/app/index.js +43 -30
  6. package/dist/commands/auth/index.js +3 -2
  7. package/dist/commands/branch/index.js +2 -1
  8. package/dist/commands/env.js +87 -0
  9. package/dist/commands/git/index.js +36 -0
  10. package/dist/commands/project/index.js +12 -14
  11. package/dist/commands/version/index.js +18 -0
  12. package/dist/controllers/app-env.js +223 -0
  13. package/dist/controllers/app.js +1051 -173
  14. package/dist/controllers/auth.js +9 -9
  15. package/dist/controllers/branch.js +6 -6
  16. package/dist/controllers/project.js +451 -161
  17. package/dist/controllers/version.js +12 -0
  18. package/dist/lib/app/bun-project.js +1 -1
  19. package/dist/lib/app/deploy-output.js +15 -0
  20. package/dist/lib/app/env-config.js +57 -0
  21. package/dist/lib/app/env-vars.js +4 -4
  22. package/dist/lib/app/local-dev.js +2 -1
  23. package/dist/lib/app/preview-build.js +130 -144
  24. package/dist/lib/app/preview-interaction.js +2 -35
  25. package/dist/lib/app/preview-progress.js +43 -58
  26. package/dist/lib/app/preview-provider.js +125 -24
  27. package/dist/lib/auth/auth-ops.js +58 -13
  28. package/dist/lib/auth/client.js +1 -1
  29. package/dist/lib/auth/guard.js +1 -1
  30. package/dist/lib/auth/login.js +115 -4
  31. package/dist/lib/project/local-pin.js +51 -0
  32. package/dist/lib/project/resolution.js +201 -0
  33. package/dist/lib/version.js +55 -0
  34. package/dist/output/patterns.js +15 -18
  35. package/dist/presenters/app-env.js +129 -0
  36. package/dist/presenters/app.js +16 -29
  37. package/dist/presenters/auth.js +2 -2
  38. package/dist/presenters/branch.js +6 -6
  39. package/dist/presenters/project.js +87 -44
  40. package/dist/presenters/version.js +29 -0
  41. package/dist/shell/command-meta.js +150 -84
  42. package/dist/shell/command-runner.js +32 -2
  43. package/dist/shell/errors.js +8 -3
  44. package/dist/shell/global-flags.js +13 -1
  45. package/dist/shell/help.js +8 -7
  46. package/dist/shell/output.js +29 -12
  47. package/dist/shell/prompt.js +12 -2
  48. package/dist/shell/runtime.js +1 -1
  49. package/dist/shell/ui.js +19 -1
  50. package/dist/use-cases/auth.js +9 -12
  51. package/dist/use-cases/branch.js +20 -20
  52. package/dist/use-cases/create-cli-gateways.js +3 -13
  53. package/dist/use-cases/project.js +2 -48
  54. package/package.json +3 -3
  55. package/dist/adapters/config.js +0 -74
@@ -12,6 +12,7 @@ var CliError = class extends Error {
12
12
  docsUrl;
13
13
  exitCode;
14
14
  nextSteps;
15
+ humanLines;
15
16
  constructor(options) {
16
17
  super(options.summary);
17
18
  this.name = "CliError";
@@ -27,6 +28,7 @@ var CliError = class extends Error {
27
28
  this.docsUrl = options.docsUrl ?? null;
28
29
  this.exitCode = options.exitCode ?? 1;
29
30
  this.nextSteps = options.nextSteps ?? [];
31
+ this.humanLines = options.humanLines && options.humanLines.length > 0 ? [...options.humanLines] : null;
30
32
  }
31
33
  };
32
34
  function usageError(summary, why, fix, nextSteps = [], domain = "cli") {
@@ -40,17 +42,20 @@ function usageError(summary, why, fix, nextSteps = [], domain = "cli") {
40
42
  nextSteps
41
43
  });
42
44
  }
43
- function authRequiredError(nextSteps = ["prisma auth login"]) {
45
+ function authRequiredError(nextSteps = ["prisma-cli auth login"]) {
44
46
  return new CliError({
45
47
  code: "AUTH_REQUIRED",
46
48
  domain: "auth",
47
49
  summary: "Authentication required",
48
50
  why: "This command needs an authenticated session.",
49
- fix: "Run prisma auth login, or rerun the command in a TTY to sign in interactively.",
51
+ fix: "Run prisma-cli auth login, or rerun the command in a TTY to sign in interactively.",
50
52
  exitCode: 1,
51
53
  nextSteps
52
54
  });
53
55
  }
56
+ function workspaceRequiredError() {
57
+ 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");
58
+ }
54
59
  function featureUnavailableError(summary, why, fix, nextSteps = [], domain = "cli") {
55
60
  return new CliError({
56
61
  code: "FEATURE_UNAVAILABLE",
@@ -63,4 +68,4 @@ function featureUnavailableError(summary, why, fix, nextSteps = [], domain = "cl
63
68
  });
64
69
  }
65
70
  //#endregion
66
- export { CliError, authRequiredError, featureUnavailableError, usageError };
71
+ export { CliError, authRequiredError, featureUnavailableError, usageError, workspaceRequiredError };
@@ -1,8 +1,20 @@
1
1
  import { Option } from "commander";
2
2
  //#region src/shell/global-flags.ts
3
+ const COMPACT_GLOBAL_OPTION_FLAGS = [
4
+ "--json",
5
+ "-q, --quiet",
6
+ "-v, --verbose",
7
+ "--trace",
8
+ "--no-interactive",
9
+ "-y, --yes",
10
+ "--version"
11
+ ];
3
12
  function addGlobalFlags(command) {
4
13
  return command.option("--json", "Emit structured JSON output.").option("-q, --quiet", "Reduce human-oriented output.").option("-v, --verbose", "Increase human-oriented output detail.").option("--trace", "Show deeper diagnostics for failures.").option("-y, --yes", "Accept supported confirmation prompts.").addOption(new Option("--interactive", "Force interactive behavior when prompts are supported.")).addOption(new Option("--no-interactive", "Disable interactive behavior and prompts.")).addOption(new Option("--color", "Force color output in supported terminals.")).addOption(new Option("--no-color", "Disable color output."));
5
14
  }
15
+ function addCompactGlobalFlags(command) {
16
+ return command.option("--json", "Emit structured JSON output.").option("-q, --quiet", "Reduce human-oriented output.").option("-v, --verbose", "Increase human-oriented output detail.").option("--trace", "Show deeper diagnostics for failures.").addOption(new Option("--no-interactive", "Disable interactive behavior and prompts.")).option("-y, --yes", "Accept supported confirmation prompts.");
17
+ }
6
18
  function getExplicitBoolean(argv, positive, negative) {
7
19
  for (let index = argv.length - 1; index >= 0; index -= 1) {
8
20
  const value = argv[index];
@@ -22,4 +34,4 @@ function resolveGlobalFlags(argv, options) {
22
34
  };
23
35
  }
24
36
  //#endregion
25
- export { addGlobalFlags, resolveGlobalFlags };
37
+ export { COMPACT_GLOBAL_OPTION_FLAGS, addCompactGlobalFlags, addGlobalFlags, resolveGlobalFlags };
@@ -1,6 +1,6 @@
1
- import { formatDescriptorLabel, getDescriptorForCommand } from "./command-meta.js";
2
- import { resolveGlobalFlags } from "./global-flags.js";
3
1
  import { createShellUi, padDisplay, wrapText } from "./ui.js";
2
+ import { formatDescriptorLabel, getDescriptorForCommand } from "./command-meta.js";
3
+ import { COMPACT_GLOBAL_OPTION_FLAGS, resolveGlobalFlags } from "./global-flags.js";
4
4
  //#region src/shell/help.ts
5
5
  function renderHelp(command, runtime) {
6
6
  const descriptor = getDescriptorForCommand(command);
@@ -10,8 +10,14 @@ 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
+ if (descriptor.longDescription) {
14
+ lines.push(`${rail}`);
15
+ const wrapped = wrapText(descriptor.longDescription, Math.max(ui.width - 3, 40));
16
+ for (const line of wrapped) lines.push(`${rail} ${line}`);
17
+ }
13
18
  if (visibleOptions.length > 0) {
14
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:`);
15
21
  lines.push(...renderOptionRows(rail, ui, visibleOptions));
16
22
  }
17
23
  if (descriptor.examples && descriptor.examples.length > 0) {
@@ -19,11 +25,6 @@ function renderHelp(command, runtime) {
19
25
  lines.push(`${rail} Examples:`);
20
26
  for (const example of descriptor.examples) lines.push(`${rail} $ ${example}`);
21
27
  }
22
- if (descriptor.longDescription) {
23
- lines.push(`${rail}`);
24
- const wrapped = wrapText(descriptor.longDescription, Math.max(ui.width - 3, 40));
25
- for (const line of wrapped) lines.push(`${rail} ${line}`);
26
- }
27
28
  if (descriptor.docsPath) {
28
29
  lines.push(`${rail}`);
29
30
  lines.push(`${rail} ${ui.accent(padDisplay("Read more", 16))} ${ui.link(descriptor.docsPath)}`);
@@ -6,21 +6,27 @@ function writeJsonSuccess(output, success) {
6
6
  ...success
7
7
  }, null, 2)}\n`);
8
8
  }
9
+ function writeJsonEvent(output, event) {
10
+ output.stdout.write(`${JSON.stringify(event)}\n`);
11
+ }
12
+ function cliErrorToJson(error) {
13
+ return {
14
+ code: error.code,
15
+ domain: error.domain,
16
+ severity: error.severity,
17
+ summary: error.summary,
18
+ why: error.why,
19
+ fix: error.fix,
20
+ where: error.where,
21
+ meta: error.meta,
22
+ docsUrl: error.docsUrl
23
+ };
24
+ }
9
25
  function writeJsonError(output, command, error) {
10
26
  output.stdout.write(`${JSON.stringify({
11
27
  ok: false,
12
28
  command,
13
- error: {
14
- code: error.code,
15
- domain: error.domain,
16
- severity: error.severity,
17
- summary: error.summary,
18
- why: error.why,
19
- fix: error.fix,
20
- where: error.where,
21
- meta: error.meta,
22
- docsUrl: error.docsUrl
23
- },
29
+ error: cliErrorToJson(error),
24
30
  warnings: [],
25
31
  nextSteps: error.nextSteps
26
32
  }, null, 2)}\n`);
@@ -30,6 +36,17 @@ function writeHumanLines(output, lines) {
30
36
  output.stderr.write(`${lines.join("\n")}\n`);
31
37
  }
32
38
  function writeHumanError(output, ui, error, options) {
39
+ if (error.humanLines && error.humanLines.length > 0) {
40
+ const lines = [...error.humanLines];
41
+ if (options.trace && error.debug) {
42
+ lines.push("");
43
+ lines.push("Trace:");
44
+ lines.push(...error.debug.trimEnd().split("\n"));
45
+ }
46
+ lines.push(...renderNextSteps(error.nextSteps));
47
+ writeHumanLines(output, lines);
48
+ return;
49
+ }
33
50
  const lines = [renderSummaryLine(ui, "error", `${error.summary} [${error.code}]`)];
34
51
  if (error.where) lines.push(...["", `Where: ${error.where}`]);
35
52
  if (error.why) {
@@ -51,4 +68,4 @@ function writeHumanError(output, ui, error, options) {
51
68
  writeHumanLines(output, lines);
52
69
  }
53
70
  //#endregion
54
- export { writeHumanError, writeHumanLines, writeJsonError, writeJsonSuccess };
71
+ export { cliErrorToJson, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess };
@@ -1,5 +1,5 @@
1
1
  import { usageError } from "./errors.js";
2
- import { isCancel, select, text } from "@clack/prompts";
2
+ import { confirm, isCancel, select, text } from "@clack/prompts";
3
3
  //#region src/shell/prompt.ts
4
4
  async function selectPrompt(options) {
5
5
  const promptOptions = options.choices.map((choice) => ({
@@ -26,6 +26,16 @@ async function textPrompt(options) {
26
26
  if (isCancel(response)) throw usageError("Interactive prompt canceled", "The command was canceled before a value was entered.", "Re-run the command and provide a value to continue.");
27
27
  return response;
28
28
  }
29
+ async function confirmPrompt(options) {
30
+ const response = await confirm({
31
+ input: options.input,
32
+ output: options.output,
33
+ message: options.message,
34
+ initialValue: options.initialValue ?? false
35
+ });
36
+ if (isCancel(response)) throw usageError("Interactive prompt canceled", "The command was canceled before a confirmation was made.", "Re-run the command and choose an option to continue.");
37
+ return response;
38
+ }
29
39
  function disposePromptState(_input) {}
30
40
  //#endregion
31
- export { disposePromptState, selectPrompt, textPrompt };
41
+ export { confirmPrompt, disposePromptState, selectPrompt, textPrompt };
@@ -1,6 +1,6 @@
1
+ import { createShellUi } from "./ui.js";
1
2
  import { LocalStateStore } from "../adapters/local-state.js";
2
3
  import { MockApi } from "../adapters/mock-api.js";
3
- import { createShellUi } from "./ui.js";
4
4
  import { renderHelp } from "./help.js";
5
5
  import path from "node:path";
6
6
  //#region src/shell/runtime.ts
package/dist/shell/ui.js CHANGED
@@ -25,6 +25,18 @@ function createShellUi(runtime, flags) {
25
25
  strong: (text) => colors.bold(text)
26
26
  };
27
27
  }
28
+ function renderCommandHeader(ui, options) {
29
+ if (!ui.isTTY) return [];
30
+ const rows = options.rows ?? [];
31
+ const lines = [`${ui.strong(options.commandLabel)} ${ui.dim("→")} ${ui.dim(options.description)}`, ""];
32
+ const rail = ui.dim("│");
33
+ const keyWidth = rows.length > 0 ? Math.max(...rows.map((row) => stringWidth(`${row.key}:`)), stringWidth("Read more")) : stringWidth("Read more");
34
+ for (const row of rows) lines.push(`${rail} ${ui.accent(padDisplay(`${row.key}:`, keyWidth))} ${formatHeaderValue(ui, row)}`);
35
+ if (rows.length > 0 || options.docsPath) lines.push(rail);
36
+ if (options.docsPath) lines.push(`${rail} ${ui.accent(padDisplay("Read more", keyWidth))} ${ui.link(options.docsPath)}`);
37
+ lines.push("");
38
+ return lines;
39
+ }
28
40
  function renderSummaryLine(ui, status, text) {
29
41
  return `${status === "success" ? ui.success("✔") : status === "error" ? ui.error("✘") : status === "warning" ? ui.warning("⚠") : ui.info("ℹ")} ${text}`;
30
42
  }
@@ -55,5 +67,11 @@ function resolveColorEnabled(runtime, flags, isTTY) {
55
67
  if (runtime.env.NO_COLOR !== void 0) return false;
56
68
  return isTTY;
57
69
  }
70
+ function formatHeaderValue(ui, row) {
71
+ const value = row.sensitive ? maskValue(row.value) : row.value;
72
+ if (row.tone === "dim") return ui.dim(value);
73
+ if (row.tone === "link") return ui.link(value);
74
+ return value;
75
+ }
58
76
  //#endregion
59
- export { createShellUi, maskValue, padDisplay, renderNextSteps, renderSummaryLine, wrapText };
77
+ export { createShellUi, maskValue, padDisplay, renderCommandHeader, renderNextSteps, renderSummaryLine, wrapText };
@@ -18,35 +18,34 @@ function createAuthUseCases(dependencies) {
18
18
  listProviders: async () => dependencies.identityGateway.listProviders(),
19
19
  resolveProvider: async (providerId) => {
20
20
  const provider = dependencies.identityGateway.getProvider(providerId);
21
- if (!provider) throw usageError("Login requires a valid mock provider", `The mock provider "${providerId}" does not exist.`, "Use --provider github or --provider google.", ["prisma auth login"], "auth");
21
+ 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");
22
22
  return provider;
23
23
  },
24
24
  listUsersForProvider: async (providerId) => {
25
25
  const users = dependencies.identityGateway.listUsersForProvider(providerId);
26
- 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 auth login"], "auth");
26
+ 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");
27
27
  return users;
28
28
  },
29
29
  resolveUserForProvider: async (providerId, userId) => {
30
30
  const user = dependencies.identityGateway.getUserForProvider(providerId, userId);
31
- 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 auth login"], "auth");
31
+ 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");
32
32
  return user;
33
33
  },
34
34
  listWorkspacesForUser: async (userId) => dependencies.identityGateway.listUserWorkspaces(userId),
35
35
  resolveWorkspaceForUser: async (userId, workspaceId) => {
36
36
  const workspace = dependencies.identityGateway.getUserWorkspace(userId, workspaceId);
37
- 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 auth login"], "auth");
37
+ 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");
38
38
  return workspace;
39
39
  }
40
40
  };
41
41
  }
42
42
  async function resolveCurrentAuthState(dependencies) {
43
- const [session, linkedProjectId] = await Promise.all([dependencies.sessionGateway.readAuthSession(), dependencies.projectConfigGateway.readLinkedProjectId()]);
43
+ const session = await dependencies.sessionGateway.readAuthSession();
44
44
  if (!session) return {
45
45
  authenticated: false,
46
46
  provider: null,
47
47
  user: null,
48
- workspace: null,
49
- linkedProjectId
48
+ workspace: null
50
49
  };
51
50
  const provider = dependencies.identityGateway.getProvider(session.provider);
52
51
  const user = dependencies.identityGateway.getUser(session.userId);
@@ -55,15 +54,13 @@ async function resolveCurrentAuthState(dependencies) {
55
54
  authenticated: false,
56
55
  provider: null,
57
56
  user: null,
58
- workspace: null,
59
- linkedProjectId
57
+ workspace: null
60
58
  };
61
59
  return {
62
60
  authenticated: true,
63
61
  provider: provider.id,
64
- user,
65
- workspace,
66
- linkedProjectId
62
+ user: { email: user.email },
63
+ workspace
67
64
  };
68
65
  }
69
66
  //#endregion
@@ -2,41 +2,41 @@
2
2
  function createBranchUseCases(dependencies) {
3
3
  return {
4
4
  list: async () => {
5
- const [linkedProjectId, activeBranch] = await Promise.all([dependencies.projectConfigGateway.readLinkedProjectId(), dependencies.branchStateGateway.readActiveBranch()]);
6
- const remoteBranches = await listRemoteBranches(dependencies.branchGateway, linkedProjectId);
5
+ const [projectId, activeBranch] = await Promise.all([dependencies.projectStateGateway.readRememberedProjectId(), dependencies.branchStateGateway.readActiveBranch()]);
6
+ const remoteBranches = await listRemoteBranches(dependencies.branchGateway, projectId);
7
7
  return {
8
- linkedProjectId,
9
- projectName: resolveProjectName(dependencies.projectGateway, linkedProjectId),
8
+ projectId,
9
+ projectName: resolveProjectName(dependencies.projectGateway, projectId),
10
10
  activeBranch,
11
11
  branches: buildBranchSummaries(activeBranch, remoteBranches)
12
12
  };
13
13
  },
14
14
  show: async () => {
15
- const [linkedProjectId, activeBranch] = await Promise.all([dependencies.projectConfigGateway.readLinkedProjectId(), dependencies.branchStateGateway.readActiveBranch()]);
15
+ const [projectId, activeBranch] = await Promise.all([dependencies.projectStateGateway.readRememberedProjectId(), dependencies.branchStateGateway.readActiveBranch()]);
16
16
  return {
17
- linkedProjectId,
18
- projectName: resolveProjectName(dependencies.projectGateway, linkedProjectId),
19
- branch: buildBranchDetail(dependencies.branchGateway, linkedProjectId, activeBranch)
17
+ projectId,
18
+ projectName: resolveProjectName(dependencies.projectGateway, projectId),
19
+ branch: buildBranchDetail(dependencies.branchGateway, projectId, activeBranch)
20
20
  };
21
21
  },
22
22
  use: async (branchName) => {
23
23
  await dependencies.branchStateGateway.writeActiveBranch(branchName);
24
- const linkedProjectId = await dependencies.projectConfigGateway.readLinkedProjectId();
24
+ const projectId = await dependencies.projectStateGateway.readRememberedProjectId();
25
25
  return {
26
- linkedProjectId,
27
- projectName: resolveProjectName(dependencies.projectGateway, linkedProjectId),
28
- branch: buildBranchDetail(dependencies.branchGateway, linkedProjectId, branchName)
26
+ projectId,
27
+ projectName: resolveProjectName(dependencies.projectGateway, projectId),
28
+ branch: buildBranchDetail(dependencies.branchGateway, projectId, branchName)
29
29
  };
30
30
  }
31
31
  };
32
32
  }
33
- function resolveProjectName(projectGateway, linkedProjectId) {
34
- if (!linkedProjectId) return null;
35
- return projectGateway.getProject(linkedProjectId)?.name ?? null;
33
+ function resolveProjectName(projectGateway, projectId) {
34
+ if (!projectId) return null;
35
+ return projectGateway.getProject(projectId)?.name ?? null;
36
36
  }
37
- async function listRemoteBranches(branchGateway, linkedProjectId) {
38
- if (!linkedProjectId) return [];
39
- return branchGateway.listBranchesForProject(linkedProjectId);
37
+ async function listRemoteBranches(branchGateway, projectId) {
38
+ if (!projectId) return [];
39
+ return branchGateway.listBranchesForProject(projectId);
40
40
  }
41
41
  function buildBranchSummaries(activeBranch, remoteBranches) {
42
42
  const byName = /* @__PURE__ */ new Map();
@@ -56,9 +56,9 @@ function buildBranchSummaries(activeBranch, remoteBranches) {
56
56
  });
57
57
  return sortBranches([...byName.values()]);
58
58
  }
59
- function buildBranchDetail(branchGateway, linkedProjectId, branchName) {
59
+ function buildBranchDetail(branchGateway, projectId, branchName) {
60
60
  const kind = toBranchKind(branchName);
61
- const remoteBranch = linkedProjectId ? branchGateway.getBranchForProject(linkedProjectId, branchName) : void 0;
61
+ const remoteBranch = projectId ? branchGateway.getBranchForProject(projectId, branchName) : void 0;
62
62
  return {
63
63
  name: branchName,
64
64
  kind,
@@ -1,5 +1,3 @@
1
- import { UnsafeConfigWriteError, readLinkedProjectId, writeLinkedProjectId } from "../adapters/config.js";
2
- import { usageError } from "../shell/errors.js";
3
1
  //#region src/use-cases/create-cli-gateways.ts
4
2
  function createCliUseCaseGateways(context) {
5
3
  return {
@@ -44,17 +42,9 @@ function createCliUseCaseGateways(context) {
44
42
  },
45
43
  getDeployment: (deploymentId) => context.api.getDeployment(deploymentId)
46
44
  },
47
- projectConfigGateway: {
48
- readLinkedProjectId: () => readLinkedProjectId(context.runtime.cwd),
49
- writeLinkedProjectId: async (projectId) => {
50
- try {
51
- await writeLinkedProjectId(context.runtime.cwd, projectId);
52
- } catch (error) {
53
- if (error instanceof UnsafeConfigWriteError) throw usageError("Project link requires a writable Prisma config", error.message, "Update prisma.config.ts to use a recognizable project field, or remove it and rerun prisma project link.", ["prisma project link proj_123"], "project");
54
- throw error;
55
- }
56
- }
57
- },
45
+ projectStateGateway: { readRememberedProjectId: async () => {
46
+ return (await context.stateStore.readLastResolvedProject())?.id ?? null;
47
+ } },
58
48
  sessionGateway: {
59
49
  readAuthSession: async () => {
60
50
  return (await context.stateStore.read()).auth;
@@ -1,4 +1,4 @@
1
- import { CliError, authRequiredError } from "../shell/errors.js";
1
+ import { authRequiredError } from "../shell/errors.js";
2
2
  //#region src/use-cases/project.ts
3
3
  function createProjectUseCases(dependencies) {
4
4
  return {
@@ -6,44 +6,9 @@ function createProjectUseCases(dependencies) {
6
6
  const workspace = requireWorkspace(authState);
7
7
  return {
8
8
  workspace,
9
- linkedProjectId: authState.linkedProjectId,
10
9
  projects: listSortedWorkspaceProjects(dependencies.projectGateway, workspace.id).map(toProjectSummary)
11
10
  };
12
11
  },
13
- show: async (authState) => {
14
- if (!authState.linkedProjectId) return {
15
- linkedProjectId: null,
16
- workspace: null,
17
- project: null
18
- };
19
- if (!authState.authenticated || !authState.workspace) return {
20
- linkedProjectId: authState.linkedProjectId,
21
- workspace: null,
22
- project: null
23
- };
24
- const project = dependencies.projectGateway.getProjectForWorkspace(authState.workspace.id, authState.linkedProjectId);
25
- if (!project) return {
26
- linkedProjectId: authState.linkedProjectId,
27
- workspace: null,
28
- project: null
29
- };
30
- return {
31
- linkedProjectId: authState.linkedProjectId,
32
- workspace: authState.workspace,
33
- project: toProjectSummary(project)
34
- };
35
- },
36
- link: async (authState, projectId) => {
37
- const workspace = requireWorkspace(authState);
38
- const project = dependencies.projectGateway.getProjectForWorkspace(workspace.id, projectId);
39
- if (!project) throw projectNotFoundError(`The project "${projectId}" does not exist in workspace "${workspace.name}".`, "Run prisma project list and choose a project id from the active workspace.");
40
- await dependencies.projectConfigGateway.writeLinkedProjectId(project.id);
41
- return {
42
- linkedProjectId: project.id,
43
- workspace,
44
- project: toProjectSummary(project)
45
- };
46
- },
47
12
  listProjectsForWorkspace: async (workspaceId) => listSortedWorkspaceProjects(dependencies.projectGateway, workspaceId).map(toProjectSummary)
48
13
  };
49
14
  }
@@ -60,16 +25,5 @@ function toProjectSummary(project) {
60
25
  name: project.name
61
26
  };
62
27
  }
63
- function projectNotFoundError(why, fix, nextSteps = ["prisma project list"]) {
64
- return new CliError({
65
- code: "PROJECT_NOT_FOUND",
66
- domain: "project",
67
- summary: "Project not found",
68
- why,
69
- fix,
70
- exitCode: 1,
71
- nextSteps
72
- });
73
- }
74
28
  //#endregion
75
- export { createProjectUseCases, projectNotFoundError };
29
+ export { createProjectUseCases };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/cli",
3
- "version": "3.0.0-alpha.0",
3
+ "version": "3.0.0-alpha.10",
4
4
  "description": "Preview of the unified Prisma CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -36,10 +36,10 @@
36
36
  "license": "Apache-2.0",
37
37
  "dependencies": {
38
38
  "@clack/prompts": "^1.2.0",
39
- "@prisma/compute-sdk": "^0.14.0",
39
+ "@prisma/compute-sdk": "^0.18.0",
40
40
  "c12": "4.0.0-beta.4",
41
41
  "@prisma/credentials-store": "^7.7.0",
42
- "@prisma/management-api-sdk": "^1.24.0",
42
+ "@prisma/management-api-sdk": "^1.27.0",
43
43
  "colorette": "^2.0.20",
44
44
  "commander": "^12.1.0",
45
45
  "magicast": "^0.3.5",
@@ -1,74 +0,0 @@
1
- import path from "node:path";
2
- import { copyFile, mkdir, mkdtemp, readFile, rm } from "node:fs/promises";
3
- import os from "node:os";
4
- import { updateConfig } from "c12/update";
5
- //#region src/adapters/config.ts
6
- const PROJECT_FIELD_PATTERN = /project\s*:\s*["']([^"']+)["']/;
7
- async function readLinkedProjectId(cwd) {
8
- const configPath = path.join(cwd, "prisma.config.ts");
9
- try {
10
- return (await readFile(configPath, "utf8")).match(PROJECT_FIELD_PATTERN)?.[1] ?? null;
11
- } catch (error) {
12
- if (error.code === "ENOENT") return null;
13
- throw error;
14
- }
15
- }
16
- var UnsafeConfigWriteError = class extends Error {
17
- constructor(message) {
18
- super(message);
19
- this.name = "UnsafeConfigWriteError";
20
- }
21
- };
22
- async function assertLinkedProjectIdWritable(cwd) {
23
- const tempDir = await mkdtemp(path.join(os.tmpdir(), "prisma-cli-config-"));
24
- const sourceConfigPath = path.join(cwd, "prisma.config.ts");
25
- const tempConfigPath = path.join(tempDir, "prisma.config.ts");
26
- try {
27
- try {
28
- await copyFile(sourceConfigPath, tempConfigPath);
29
- } catch (error) {
30
- if (error.code !== "ENOENT") throw error;
31
- }
32
- await applyLinkedProjectIdUpdate(tempDir, "proj_preflight");
33
- } catch (error) {
34
- throw toUnsafeConfigWriteError(error);
35
- } finally {
36
- await rm(tempDir, {
37
- recursive: true,
38
- force: true
39
- });
40
- }
41
- }
42
- async function writeLinkedProjectId(cwd, projectId) {
43
- try {
44
- await applyLinkedProjectIdUpdate(cwd, projectId);
45
- } catch (error) {
46
- if (error.code === "ENOENT") {
47
- await mkdir(cwd, { recursive: true });
48
- await applyLinkedProjectIdUpdate(cwd, projectId);
49
- return;
50
- }
51
- throw toUnsafeConfigWriteError(error);
52
- }
53
- }
54
- async function applyLinkedProjectIdUpdate(cwd, projectId) {
55
- await updateConfig({
56
- cwd,
57
- configFile: "prisma.config",
58
- onUpdate(config) {
59
- config.project = projectId;
60
- },
61
- onCreate() {
62
- return renderProjectConfig(projectId);
63
- }
64
- });
65
- }
66
- function renderProjectConfig(projectId) {
67
- return `export default {\n project: "${projectId}",\n};\n`;
68
- }
69
- function toUnsafeConfigWriteError(error) {
70
- if (error instanceof UnsafeConfigWriteError) return error;
71
- return new UnsafeConfigWriteError("The existing prisma.config.ts file could not be updated safely.");
72
- }
73
- //#endregion
74
- export { UnsafeConfigWriteError, assertLinkedProjectIdWritable, readLinkedProjectId, writeLinkedProjectId };