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

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.
@@ -1,5 +1,8 @@
1
1
  import { getAuthFilePath } from "../lib/auth/client.js";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
2
4
  import { CredentialsStore } from "@prisma/credentials-store";
5
+ import { randomUUID } from "node:crypto";
3
6
  //#region src/adapters/token-storage.ts
4
7
  function findLatestValidTokens(allCredentials) {
5
8
  for (let i = allCredentials.length - 1; i >= 0; i -= 1) {
@@ -14,10 +17,19 @@ function findLatestValidTokens(allCredentials) {
14
17
  }
15
18
  return null;
16
19
  }
20
+ function tokensEqual(a, b) {
21
+ return a?.workspaceId === b?.workspaceId && a?.accessToken === b?.accessToken && a?.refreshToken === b?.refreshToken;
22
+ }
23
+ function sleep(ms) {
24
+ return new Promise((resolve) => setTimeout(resolve, ms));
25
+ }
17
26
  var FileTokenStorage = class {
18
27
  credentialsStore;
28
+ lockFilePath;
19
29
  constructor(env = process.env) {
20
- this.credentialsStore = new CredentialsStore(getAuthFilePath(env));
30
+ const authFilePath = getAuthFilePath(env);
31
+ this.credentialsStore = new CredentialsStore(authFilePath);
32
+ this.lockFilePath = `${authFilePath}.lock`;
21
33
  }
22
34
  async getTokens() {
23
35
  try {
@@ -38,6 +50,50 @@ var FileTokenStorage = class {
38
50
  if (!tokens) return;
39
51
  await this.credentialsStore.deleteCredentials(tokens.workspaceId);
40
52
  }
53
+ async clearTokensIfCurrent(tokens) {
54
+ if (!tokensEqual(await this.getTokens(), tokens)) return;
55
+ await this.clearTokens();
56
+ }
57
+ async withRefreshLock(fn) {
58
+ const lockId = await this.acquireRefreshLock();
59
+ try {
60
+ return await fn();
61
+ } finally {
62
+ await this.releaseRefreshLock(lockId);
63
+ }
64
+ }
65
+ async acquireRefreshLock() {
66
+ const lockId = randomUUID();
67
+ await fs.mkdir(path.dirname(this.lockFilePath), { recursive: true });
68
+ while (true) try {
69
+ const handle = await fs.open(this.lockFilePath, "wx");
70
+ try {
71
+ await handle.writeFile(lockId, "utf8");
72
+ } finally {
73
+ await handle.close();
74
+ }
75
+ return lockId;
76
+ } catch (error) {
77
+ if (error.code !== "EEXIST") throw error;
78
+ const staleLockId = await this.getStaleRefreshLockId();
79
+ if (staleLockId) {
80
+ await this.releaseRefreshLock(staleLockId);
81
+ continue;
82
+ }
83
+ await sleep(100);
84
+ }
85
+ }
86
+ async getStaleRefreshLockId() {
87
+ const lockId = await fs.readFile(this.lockFilePath, "utf8").catch(() => null);
88
+ if (lockId === null) return null;
89
+ const stats = await fs.stat(this.lockFilePath).catch(() => null);
90
+ if (!stats) return null;
91
+ return Date.now() - stats.mtimeMs > 3e4 ? lockId : null;
92
+ }
93
+ async releaseRefreshLock(lockId) {
94
+ if (await fs.readFile(this.lockFilePath, "utf8").catch(() => null) !== lockId) return;
95
+ await fs.unlink(this.lockFilePath).catch(() => {});
96
+ }
41
97
  };
42
98
  //#endregion
43
99
  export { FileTokenStorage };
@@ -46,7 +46,7 @@ async function executePreviewBuild(options) {
46
46
  });
47
47
  const artifact = await strategy.execute();
48
48
  try {
49
- if (buildType === "nextjs") await restageNextjsArtifact(artifact.directory, options.appPath);
49
+ if (buildType === "nextjs") await restageNextjsArtifact(artifact, options.appPath);
50
50
  await normalizeArtifactSymlinks(artifact.directory, options.appPath);
51
51
  return {
52
52
  artifact,
@@ -116,7 +116,8 @@ async function stageNextjsStandaloneArtifact(options) {
116
116
  });
117
117
  await hoistPnpmDependencies(path.join(artifactRoot, "node_modules"));
118
118
  }
119
- async function restageNextjsArtifact(artifactDir, appPath) {
119
+ async function restageNextjsArtifact(artifact, appPath) {
120
+ const artifactDir = artifact.directory;
120
121
  const standaloneDir = path.join(appPath, ".next", "standalone");
121
122
  await rm(artifactDir, {
122
123
  recursive: true,
@@ -127,17 +128,23 @@ async function restageNextjsArtifact(artifactDir, appPath) {
127
128
  artifactDir,
128
129
  appPath
129
130
  });
131
+ const serverSubpath = nextjsServerSubpath(artifact.entrypoint);
132
+ const serverDir = serverSubpath ? path.join(artifactDir, serverSubpath) : artifactDir;
130
133
  const publicDir = path.join(appPath, "public");
131
- if (await directoryExists(publicDir)) await cp(publicDir, path.join(artifactDir, "public"), {
134
+ if (await directoryExists(publicDir)) await cp(publicDir, path.join(serverDir, "public"), {
132
135
  recursive: true,
133
136
  verbatimSymlinks: true
134
137
  });
135
138
  const staticDir = path.join(appPath, ".next", "static");
136
- if (await directoryExists(staticDir)) await cp(staticDir, path.join(artifactDir, ".next", "static"), {
139
+ if (await directoryExists(staticDir)) await cp(staticDir, path.join(serverDir, ".next", "static"), {
137
140
  recursive: true,
138
141
  verbatimSymlinks: true
139
142
  });
140
143
  }
144
+ function nextjsServerSubpath(entrypoint) {
145
+ const dir = path.posix.dirname(entrypoint);
146
+ return dir === "." ? "" : dir;
147
+ }
141
148
  async function hoistPnpmDependencies(nodeModulesDir) {
142
149
  const pnpmNodeModulesDir = path.join(nodeModulesDir, ".pnpm", "node_modules");
143
150
  if (!await directoryExists(pnpmNodeModulesDir)) return;
@@ -1,9 +1,15 @@
1
- import { CliError } from "./errors.js";
1
+ import { CliError, authRequiredError } from "./errors.js";
2
2
  import { cliErrorToJson, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess } from "./output.js";
3
3
  import { getCommandDescriptor } from "./command-meta.js";
4
4
  import { resolveGlobalFlags } from "./global-flags.js";
5
5
  import { createCommandContext } from "./runtime.js";
6
+ import { AuthError } from "@prisma/management-api-sdk";
6
7
  //#region src/shell/command-runner.ts
8
+ function toCliError(error) {
9
+ if (error instanceof CliError) return error;
10
+ if (error instanceof AuthError) return authRequiredError(["prisma-cli auth login"], { debug: error.message });
11
+ return null;
12
+ }
7
13
  async function runCommand(runtime, commandName, options, handler, presenter) {
8
14
  const flags = resolveGlobalFlags(runtime.argv, options);
9
15
  const context = await createCommandContext(runtime, flags);
@@ -20,10 +26,11 @@ async function runCommand(runtime, commandName, options, handler, presenter) {
20
26
  if (flags.quiet) return;
21
27
  writeHumanLines(context.output, presenter.renderHuman(context, descriptor, success.result));
22
28
  } catch (error) {
23
- if (error instanceof CliError) {
24
- if (flags.json) writeJsonError(context.output, commandName, error);
25
- else writeHumanError(context.output, context.ui, error, { trace: flags.trace });
26
- process.exitCode = error.exitCode;
29
+ const cliError = toCliError(error);
30
+ if (cliError) {
31
+ if (flags.json) writeJsonError(context.output, commandName, cliError);
32
+ else writeHumanError(context.output, context.ui, cliError, { trace: flags.trace });
33
+ process.exitCode = cliError.exitCode;
27
34
  return;
28
35
  }
29
36
  throw error;
@@ -43,17 +50,18 @@ async function runStreamingCommand(runtime, commandName, options, handler) {
43
50
  nextSteps: []
44
51
  });
45
52
  } catch (error) {
46
- if (error instanceof CliError) {
53
+ const cliError = toCliError(error);
54
+ if (cliError) {
47
55
  if (flags.json) writeJsonEvent(context.output, {
48
56
  type: "error",
49
57
  command: commandName,
50
58
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
51
- error: cliErrorToJson(error),
59
+ error: cliErrorToJson(cliError),
52
60
  warnings: [],
53
- nextSteps: error.nextSteps
61
+ nextSteps: cliError.nextSteps
54
62
  });
55
- else writeHumanError(context.output, context.ui, error, { trace: flags.trace });
56
- process.exitCode = error.exitCode;
63
+ else writeHumanError(context.output, context.ui, cliError, { trace: flags.trace });
64
+ process.exitCode = cliError.exitCode;
57
65
  return;
58
66
  }
59
67
  throw error;
@@ -42,13 +42,14 @@ function usageError(summary, why, fix, nextSteps = [], domain = "cli") {
42
42
  nextSteps
43
43
  });
44
44
  }
45
- function authRequiredError(nextSteps = ["prisma-cli auth login"]) {
45
+ function authRequiredError(nextSteps = ["prisma-cli auth login"], options = {}) {
46
46
  return new CliError({
47
47
  code: "AUTH_REQUIRED",
48
48
  domain: "auth",
49
49
  summary: "Authentication required",
50
50
  why: "This command needs an authenticated session.",
51
51
  fix: "Run prisma-cli auth login, or rerun the command in a TTY to sign in interactively.",
52
+ debug: options.debug,
52
53
  exitCode: 1,
53
54
  nextSteps
54
55
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/cli",
3
- "version": "3.0.0-alpha.10",
3
+ "version": "3.0.0-alpha.12",
4
4
  "description": "Preview of the unified Prisma CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -39,7 +39,7 @@
39
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.27.0",
42
+ "@prisma/management-api-sdk": "^1.32.1",
43
43
  "colorette": "^2.0.20",
44
44
  "commander": "^12.1.0",
45
45
  "magicast": "^0.3.5",