@prisma/cli 3.0.0-dev.95.1 → 3.0.0-dev.97.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.
@@ -11,6 +11,7 @@ const EMPTY_AUTH_CONTEXT = {
11
11
  activeWorkspaceId: null,
12
12
  workspaces: {}
13
13
  };
14
+ const UNKNOWN_WORKSPACE_NAME = "Unknown workspace";
14
15
  function getAuthContextFilePath(authFilePath) {
15
16
  const extension = path.extname(authFilePath);
16
17
  if (!extension) return `${authFilePath}.context.json`;
@@ -140,7 +141,7 @@ var FileTokenStorage = class {
140
141
  return credentials.map((credential) => storedCredentialToTokens(credential)).filter((tokens) => tokens !== null).map((tokens) => {
141
142
  const cached = context.state.workspaces[tokens.workspaceId];
142
143
  const id = typeof cached?.id === "string" && cached.id.trim().length > 0 ? cached.id.trim() : tokens.workspaceId;
143
- const name = typeof cached?.name === "string" && cached.name.trim().length > 0 ? cached.name.trim() : id;
144
+ const name = typeof cached?.name === "string" && cached.name.trim().length > 0 ? workspaceDisplayName(cached.name.trim(), tokens.workspaceId) : UNKNOWN_WORKSPACE_NAME;
144
145
  const lastSeenAt = typeof cached?.lastSeenAt === "string" && cached.lastSeenAt.trim().length > 0 ? cached.lastSeenAt.trim() : null;
145
146
  return {
146
147
  id,
@@ -151,6 +152,10 @@ var FileTokenStorage = class {
151
152
  };
152
153
  });
153
154
  }
155
+ async listWorkspaceTokens() {
156
+ this.signal?.throwIfAborted();
157
+ return (await this.readCredentialsFromDisk()).map((credential) => storedCredentialToTokens(credential)).filter((tokens) => tokens !== null);
158
+ }
154
159
  async useWorkspace(workspaceRef) {
155
160
  return this.withRefreshLock(() => this.useWorkspaceUnlocked(workspaceRef));
156
161
  }
@@ -406,5 +411,8 @@ function workspaceMatchesRef(workspace, ref) {
406
411
  function stripWorkspacePrefix(value) {
407
412
  return value.startsWith("wksp_") ? value.slice(5) : value;
408
413
  }
414
+ function workspaceDisplayName(name, credentialWorkspaceId) {
415
+ return name === credentialWorkspaceId ? UNKNOWN_WORKSPACE_NAME : name;
416
+ }
409
417
  //#endregion
410
418
  export { FileTokenStorage, WorkspaceSelectionError };
@@ -1,4 +1,4 @@
1
- import { SERVICE_TOKEN_ENV_VAR } from "../lib/auth/client.js";
1
+ import { CLIENT_ID, SERVICE_TOKEN_ENV_VAR, getApiBaseUrl } from "../lib/auth/client.js";
2
2
  import { FileTokenStorage, WorkspaceSelectionError } from "../adapters/token-storage.js";
3
3
  import { authRequiredError, usageError, workspaceAmbiguousError, workspaceNotAuthenticatedError, workspaceSwitchUnavailableError } from "../shell/errors.js";
4
4
  import { canPrompt } from "../shell/runtime.js";
@@ -6,6 +6,7 @@ import { performLogin, performLogout, readAuthState } from "../lib/auth/auth-ops
6
6
  import { createAuthUseCases } from "../use-cases/auth.js";
7
7
  import { createCliUseCaseGateways } from "../use-cases/create-cli-gateways.js";
8
8
  import { createSelectPromptPort } from "./select-prompt-port.js";
9
+ import { createManagementApiSdk } from "@prisma/management-api-sdk";
9
10
  //#region src/controllers/auth.ts
10
11
  function isRealMode(context) {
11
12
  return !context.runtime.fixturePath && !context.runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
@@ -77,7 +78,8 @@ async function requireAuthenticatedAuthState(context) {
77
78
  }
78
79
  async function listRealAuthWorkspaces(context) {
79
80
  const rawServiceToken = context.runtime.env[SERVICE_TOKEN_ENV_VAR];
80
- const localWorkspaces = await new FileTokenStorage(context.runtime.env, context.runtime.signal).listWorkspaces();
81
+ const storage = new FileTokenStorage(context.runtime.env, context.runtime.signal);
82
+ const localWorkspaces = await hydrateLocalAuthWorkspaces(context, storage, await storage.listWorkspaces());
81
83
  if (rawServiceToken !== void 0) {
82
84
  const authState = await readAuthState(context.runtime.env, context.runtime.signal);
83
85
  return {
@@ -117,6 +119,7 @@ async function listRealAuthWorkspaces(context) {
117
119
  async function useRealAuthWorkspace(context, workspaceRef) {
118
120
  if (context.runtime.env["PRISMA_SERVICE_TOKEN"] !== void 0) throw workspaceSwitchUnavailableError();
119
121
  const storage = new FileTokenStorage(context.runtime.env, context.runtime.signal);
122
+ await hydrateLocalAuthWorkspaces(context, storage, await storage.listWorkspaces());
120
123
  try {
121
124
  const result = await storage.useWorkspace(workspaceRef);
122
125
  return {
@@ -137,6 +140,7 @@ async function useRealAuthWorkspace(context, workspaceRef) {
137
140
  }
138
141
  async function logoutRealAuthWorkspace(context, workspaceRef) {
139
142
  const storage = new FileTokenStorage(context.runtime.env, context.runtime.signal);
143
+ await hydrateLocalAuthWorkspaces(context, storage, await storage.listWorkspaces());
140
144
  try {
141
145
  const result = await storage.logoutWorkspace(workspaceRef);
142
146
  return {
@@ -171,6 +175,78 @@ async function selectWorkspaceSession(context) {
171
175
  }))
172
176
  })).id;
173
177
  }
178
+ async function hydrateLocalAuthWorkspaces(context, storage, workspaces) {
179
+ const candidates = workspaces.filter(needsWorkspaceMetadataHydration);
180
+ if (candidates.length === 0) return workspaces;
181
+ const tokensByCredentialWorkspaceId = new Map((await storage.listWorkspaceTokens()).map((tokens) => [tokens.workspaceId, tokens]));
182
+ let nextWorkspaces = workspaces;
183
+ for (const workspace of candidates) {
184
+ const tokens = tokensByCredentialWorkspaceId.get(workspace.credentialWorkspaceId);
185
+ if (!tokens) continue;
186
+ const resolved = await resolveOAuthWorkspaceMetadata(context, tokens);
187
+ if (!resolved) continue;
188
+ await rememberResolvedWorkspaceMetadata(context, storage, tokens, resolved);
189
+ nextWorkspaces = nextWorkspaces.map((candidate) => candidate.credentialWorkspaceId === workspace.credentialWorkspaceId ? {
190
+ ...candidate,
191
+ id: resolved.id,
192
+ name: resolved.name,
193
+ lastSeenAt: (/* @__PURE__ */ new Date()).toISOString()
194
+ } : candidate);
195
+ }
196
+ return nextWorkspaces;
197
+ }
198
+ async function rememberResolvedWorkspaceMetadata(context, storage, tokens, resolved) {
199
+ try {
200
+ await storage.rememberWorkspace(tokens.workspaceId, resolved);
201
+ } catch {
202
+ context.runtime.signal?.throwIfAborted();
203
+ }
204
+ }
205
+ function needsWorkspaceMetadataHydration(workspace) {
206
+ return workspace.id === workspace.credentialWorkspaceId || workspace.name === "Unknown workspace" || workspace.name === workspace.credentialWorkspaceId;
207
+ }
208
+ async function resolveOAuthWorkspaceMetadata(context, tokens) {
209
+ const sdk = createManagementApiSdk({
210
+ clientId: CLIENT_ID,
211
+ redirectUri: "http://localhost:0/auth/callback",
212
+ tokenStorage: createSingleWorkspaceTokenStorage(new FileTokenStorage(context.runtime.env, context.runtime.signal, { activateOnSetTokens: false }), tokens),
213
+ apiBaseUrl: getApiBaseUrl(context.runtime.env)
214
+ });
215
+ try {
216
+ const { data } = await sdk.client.GET("/v1/workspaces/{id}", {
217
+ params: { path: { id: tokens.workspaceId } },
218
+ signal: context.runtime.signal
219
+ });
220
+ const id = stringOrNull(data?.data?.id) ?? tokens.workspaceId;
221
+ const name = stringOrNull(data?.data?.name) ?? id;
222
+ if (id === tokens.workspaceId && name === tokens.workspaceId) return null;
223
+ return {
224
+ id,
225
+ name
226
+ };
227
+ } catch {
228
+ context.runtime.signal?.throwIfAborted();
229
+ return null;
230
+ }
231
+ }
232
+ function createSingleWorkspaceTokenStorage(storage, initialTokens) {
233
+ let currentTokens = initialTokens;
234
+ return {
235
+ getTokens: async () => currentTokens,
236
+ setTokens: async (tokens) => {
237
+ currentTokens = tokens;
238
+ await storage.setTokens(tokens);
239
+ },
240
+ clearTokens: async () => {
241
+ const tokens = currentTokens;
242
+ currentTokens = null;
243
+ if (tokens) await storage.clearTokensIfCurrent(tokens);
244
+ }
245
+ };
246
+ }
247
+ function stringOrNull(value) {
248
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
249
+ }
174
250
  function toAuthWorkspace(workspace) {
175
251
  return {
176
252
  id: workspace.id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/cli",
3
- "version": "3.0.0-dev.95.1",
3
+ "version": "3.0.0-dev.97.1",
4
4
  "description": "Command-line interface for the Prisma Developer Platform.",
5
5
  "type": "module",
6
6
  "bin": {