@vercel/oidc 3.1.0 → 3.2.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @vercel/oidc
2
2
 
3
+ ## 3.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - - Add optional `team` and `project` parameters to `getVercelOidcToken()` to allow explicit control over token refresh behavior instead of always reading from `.vercel/project.json` ([#14864](https://github.com/vercel/vercel/pull/14864))
8
+ - Add `expirationBufferMs` option to both `getVercelOidcToken()` and `getVercelToken()` to proactively refresh tokens before they expire (useful for avoiding auth errors mid-request)
9
+ - Export `getVercelToken()` function with `GetVercelTokenOptions` interface to allow refreshing CLI tokens with configurable expiration buffer
10
+
3
11
  ## 3.1.0
4
12
 
5
13
  ### Minor Changes
package/README.md CHANGED
@@ -1,3 +1,41 @@
1
1
  # `@vercel/oidc`
2
2
 
3
3
  Runtime OIDC helper methods intended to be used with your Vercel Functions
4
+
5
+ ## Usage
6
+
7
+ ### Getting an OIDC Token
8
+
9
+ ```typescript
10
+ import { getVercelOidcToken } from '@vercel/oidc';
11
+
12
+ // Get token using project.json configuration
13
+ const token = await getVercelOidcToken();
14
+
15
+ // Get token with explicit project and team (supports both IDs and slugs)
16
+ const token = await getVercelOidcToken({
17
+ project: 'my-project', // or 'prj_abc123'
18
+ team: 'my-team', // or 'team_xyz789'
19
+ });
20
+
21
+ // Get token with expiration buffer (refresh if expires within 5 minutes)
22
+ const token = await getVercelOidcToken({
23
+ expirationBufferMs: 5 * 60 * 1000,
24
+ });
25
+ ```
26
+
27
+ ## API
28
+
29
+ ### `getVercelOidcToken(options?)`
30
+
31
+ Gets the current OIDC token from the request context or environment variable. Will refresh the token if expired in development.
32
+
33
+ **Options:**
34
+
35
+ - `project?: string` - Project ID (prj\_\*) or slug
36
+ - `team?: string` - Team ID (team\_\*) or slug
37
+ - `expirationBufferMs?: number` - Buffer time in ms before expiry to trigger refresh (default: 0)
38
+
39
+ ### `getVercelOidcTokenSync()`
40
+
41
+ Synchronously gets the current OIDC token without refreshing. Use `getVercelOidcToken()` if you need automatic refresh in development.
@@ -27,4 +27,4 @@ export declare function writeAuthConfig(config: AuthConfig): void;
27
27
  * Check if an access token is valid (not expired)
28
28
  * Copied from packages/cli/src/util/client.ts:72-81
29
29
  */
30
- export declare function isValidAccessToken(authConfig: AuthConfig): boolean;
30
+ export declare function isValidAccessToken(authConfig: AuthConfig, expirationBufferMs?: number): boolean;
@@ -68,13 +68,14 @@ function writeAuthConfig(config) {
68
68
  }
69
69
  fs.writeFileSync(authPath, JSON.stringify(config, null, 2), { mode: 384 });
70
70
  }
71
- function isValidAccessToken(authConfig) {
71
+ function isValidAccessToken(authConfig, expirationBufferMs = 0) {
72
72
  if (!authConfig.token)
73
73
  return false;
74
74
  if (typeof authConfig.expiresAt !== "number")
75
75
  return true;
76
76
  const nowInSeconds = Math.floor(Date.now() / 1e3);
77
- return authConfig.expiresAt >= nowInSeconds;
77
+ const bufferInSeconds = expirationBufferMs / 1e3;
78
+ return authConfig.expiresAt >= nowInSeconds + bufferInSeconds;
78
79
  }
79
80
  // Annotate the CommonJS export names for ESM import in node:
80
81
  0 && (module.exports = {
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Error thrown when no authentication configuration is found.
3
+ * This typically means the user needs to log in.
4
+ */
5
+ export declare class AccessTokenMissingError extends Error {
6
+ name: string;
7
+ constructor();
8
+ }
9
+ /**
10
+ * Error thrown when attempting to refresh the authentication token fails.
11
+ * This includes cases where no refresh token is available.
12
+ */
13
+ export declare class RefreshAccessTokenFailedError extends Error {
14
+ name: string;
15
+ constructor(cause?: unknown);
16
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var auth_errors_exports = {};
20
+ __export(auth_errors_exports, {
21
+ AccessTokenMissingError: () => AccessTokenMissingError,
22
+ RefreshAccessTokenFailedError: () => RefreshAccessTokenFailedError
23
+ });
24
+ module.exports = __toCommonJS(auth_errors_exports);
25
+ class AccessTokenMissingError extends Error {
26
+ constructor() {
27
+ super(
28
+ "No authentication found. Please log in with the Vercel CLI (vercel login)."
29
+ );
30
+ this.name = "AccessTokenMissingError";
31
+ }
32
+ }
33
+ class RefreshAccessTokenFailedError extends Error {
34
+ constructor(cause) {
35
+ super("Failed to refresh authentication token.", { cause });
36
+ this.name = "RefreshAccessTokenFailedError";
37
+ }
38
+ }
39
+ // Annotate the CommonJS export names for ESM import in node:
40
+ 0 && (module.exports = {
41
+ AccessTokenMissingError,
42
+ RefreshAccessTokenFailedError
43
+ });
@@ -1,3 +1,24 @@
1
+ /**
2
+ * Options for getting the Vercel OIDC token.
3
+ */
4
+ export interface GetVercelOidcTokenOptions {
5
+ /**
6
+ * Optional team ID (team_*) or slug to use for token refresh.
7
+ * When provided, this team will be used instead of reading from `.vercel/project.json`.
8
+ */
9
+ team?: string;
10
+ /**
11
+ * Optional project ID (prj_*) or slug to use for token refresh.
12
+ * When provided, this project will be used instead of reading from `.vercel/project.json`.
13
+ */
14
+ project?: string;
15
+ /**
16
+ * Optional time buffer in milliseconds before token expiry to consider it expired.
17
+ * When provided, the token will be refreshed if it expires within this buffer time.
18
+ * @default 0
19
+ */
20
+ expirationBufferMs?: number;
21
+ }
1
22
  /**
2
23
  * Gets the current OIDC token from the request context or the environment variable.
3
24
  *
@@ -8,6 +29,7 @@
8
29
  *
9
30
  * Unlike the `getVercelOidcTokenSync` function, this function will refresh the token if it is expired in a development environment.
10
31
  *
32
+ * @param {GetVercelOidcTokenOptions} [options] - Optional configuration for token retrieval.
11
33
  * @returns {Promise<string>} A promise that resolves to the OIDC token.
12
34
  * @throws {Error} If the `x-vercel-oidc-token` header is missing from the request context and the environment variable `VERCEL_OIDC_TOKEN` is not set. If the token
13
35
  * is expired in a development environment, will also throw an error if the token cannot be refreshed: no CLI credentials are available, CLI credentials are expired, no project configuration is available
@@ -23,8 +45,19 @@
23
45
  * console.error('Error:', error.message);
24
46
  * });
25
47
  * ```
48
+ *
49
+ * @example
50
+ *
51
+ * ```js
52
+ * // Using the OIDC token with explicit team and project (supports IDs and slugs)
53
+ * getVercelOidcToken({ team: 'my-team', project: 'my-project' }).then((token) => {
54
+ * console.log('OIDC Token:', token);
55
+ * }).catch((error) => {
56
+ * console.error('Error:', error.message);
57
+ * });
58
+ * ```
26
59
  */
27
- export declare function getVercelOidcToken(): Promise<string>;
60
+ export declare function getVercelOidcToken(options?: GetVercelOidcTokenOptions): Promise<string>;
28
61
  /**
29
62
  * Gets the current OIDC token from the request context or the environment variable.
30
63
  *
@@ -34,7 +34,7 @@ __export(get_vercel_oidc_token_exports, {
34
34
  module.exports = __toCommonJS(get_vercel_oidc_token_exports);
35
35
  var import_get_context = require("./get-context");
36
36
  var import_token_error = require("./token-error");
37
- async function getVercelOidcToken() {
37
+ async function getVercelOidcToken(options) {
38
38
  let token = "";
39
39
  let err;
40
40
  try {
@@ -47,8 +47,8 @@ async function getVercelOidcToken() {
47
47
  await import("./token-util.js"),
48
48
  await import("./token.js")
49
49
  ]);
50
- if (!token || isExpired(getTokenPayload(token))) {
51
- await refreshToken();
50
+ if (!token || isExpired(getTokenPayload(token), options?.expirationBufferMs)) {
51
+ await refreshToken(options);
52
52
  token = getVercelOidcTokenSync();
53
53
  }
54
54
  } catch (error) {
@@ -38,8 +38,8 @@ import_vitest.vi.mock("./get-context", () => ({
38
38
  let userDataDir;
39
39
  let cliDataDir;
40
40
  let tokenDataDir;
41
- const projectId = "test-project-id";
42
- const teamId = "test-team-id";
41
+ const projectId = "prj_test123";
42
+ const teamId = "team_test456";
43
43
  (0, import_vitest.beforeEach)(() => {
44
44
  import_vitest.vi.clearAllMocks();
45
45
  import_vitest.vi.restoreAllMocks();
@@ -63,14 +63,14 @@ import_vitest.vi.mock("./get-context", () => ({
63
63
  fs.rmSync(rootDir, { recursive: true, force: true });
64
64
  }
65
65
  });
66
- (0, import_vitest.test)("should throw helpful error when CLI auth file is missing", async () => {
66
+ (0, import_vitest.test)("should throw AccessTokenMissingError when CLI auth file is missing", async () => {
67
67
  fs.writeFileSync(
68
68
  path.join(rootDir, ".vercel", "project.json"),
69
69
  JSON.stringify({ projectId, orgId: teamId })
70
70
  );
71
71
  process.env.VERCEL_OIDC_TOKEN = createExpiredToken();
72
72
  await (0, import_vitest.expect)((0, import_get_vercel_oidc_token.getVercelOidcToken)()).rejects.toThrow(
73
- /Failed to refresh OIDC token: Log in to Vercel CLI and link your project with `vc link`/
73
+ /No authentication found/
74
74
  );
75
75
  });
76
76
  (0, import_vitest.test)("should throw helpful error when project.json is missing", async () => {
@@ -216,6 +216,124 @@ import_vitest.vi.mock("./get-context", () => ({
216
216
  const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)();
217
217
  (0, import_vitest.expect)(token).toBe(newToken);
218
218
  });
219
+ (0, import_vitest.test)("should use provided team and project for refresh instead of reading project.json", async () => {
220
+ const customProjectId = "prj_custom123";
221
+ const customTeamId = "team_custom456";
222
+ fs.writeFileSync(
223
+ path.join(cliDataDir, "auth.json"),
224
+ JSON.stringify({ token: "test-auth-token" })
225
+ );
226
+ const newToken = createValidToken("custom-token");
227
+ const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
228
+ token: newToken
229
+ });
230
+ import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValueOnce({
231
+ sub: "test-sub",
232
+ name: "test-name",
233
+ exp: Date.now() / 1e3 - 1e3
234
+ }).mockReturnValue({
235
+ sub: "test-sub",
236
+ name: "test-name",
237
+ exp: Date.now() / 1e3 + 43200
238
+ });
239
+ process.env.VERCEL_OIDC_TOKEN = createExpiredToken();
240
+ const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)({
241
+ team: customTeamId,
242
+ project: customProjectId
243
+ });
244
+ (0, import_vitest.expect)(token).toBe(newToken);
245
+ (0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
246
+ "test-auth-token",
247
+ customProjectId,
248
+ customTeamId
249
+ );
250
+ });
251
+ (0, import_vitest.test)("should use provided project and read team from project.json", async () => {
252
+ const customProjectId = "prj_custom234";
253
+ fs.writeFileSync(
254
+ path.join(cliDataDir, "auth.json"),
255
+ JSON.stringify({ token: "test-auth-token" })
256
+ );
257
+ fs.writeFileSync(
258
+ path.join(rootDir, ".vercel", "project.json"),
259
+ JSON.stringify({ projectId: "original-project-id", orgId: teamId })
260
+ );
261
+ const newToken = createValidToken("partial-custom-token");
262
+ const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
263
+ token: newToken
264
+ });
265
+ import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValueOnce({
266
+ sub: "test-sub",
267
+ name: "test-name",
268
+ exp: Date.now() / 1e3 - 1e3
269
+ }).mockReturnValue({
270
+ sub: "test-sub",
271
+ name: "test-name",
272
+ exp: Date.now() / 1e3 + 43200
273
+ });
274
+ process.env.VERCEL_OIDC_TOKEN = createExpiredToken();
275
+ const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)({
276
+ project: customProjectId
277
+ });
278
+ (0, import_vitest.expect)(token).toBe(newToken);
279
+ (0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
280
+ "test-auth-token",
281
+ customProjectId,
282
+ teamId
283
+ );
284
+ });
285
+ (0, import_vitest.test)("should use provided team and read project from project.json", async () => {
286
+ const customTeamId = "team_custom789";
287
+ fs.writeFileSync(
288
+ path.join(cliDataDir, "auth.json"),
289
+ JSON.stringify({ token: "test-auth-token" })
290
+ );
291
+ fs.writeFileSync(
292
+ path.join(rootDir, ".vercel", "project.json"),
293
+ JSON.stringify({ projectId, orgId: "original-team-id" })
294
+ );
295
+ const newToken = createValidToken("partial-custom-token-2");
296
+ const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
297
+ token: newToken
298
+ });
299
+ import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValueOnce({
300
+ sub: "test-sub",
301
+ name: "test-name",
302
+ exp: Date.now() / 1e3 - 1e3
303
+ }).mockReturnValue({
304
+ sub: "test-sub",
305
+ name: "test-name",
306
+ exp: Date.now() / 1e3 + 43200
307
+ });
308
+ process.env.VERCEL_OIDC_TOKEN = createExpiredToken();
309
+ const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)({
310
+ team: customTeamId
311
+ });
312
+ (0, import_vitest.expect)(token).toBe(newToken);
313
+ (0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
314
+ "test-auth-token",
315
+ projectId,
316
+ customTeamId
317
+ );
318
+ });
319
+ (0, import_vitest.test)("should not refresh when token is valid even with options provided", async () => {
320
+ const validToken = createValidToken();
321
+ process.env.VERCEL_OIDC_TOKEN = validToken;
322
+ const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
323
+ token: "should-not-be-called"
324
+ });
325
+ import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValue({
326
+ sub: "test-sub",
327
+ name: "test-name",
328
+ exp: Date.now() / 1e3 + 43200
329
+ });
330
+ const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)({
331
+ team: "custom-team",
332
+ project: "custom-project"
333
+ });
334
+ (0, import_vitest.expect)(token).toBe(validToken);
335
+ (0, import_vitest.expect)(getVercelOidcTokenSpy).not.toHaveBeenCalled();
336
+ });
219
337
  });
220
338
  function createExpiredToken() {
221
339
  const header = Buffer.from(
@@ -1,3 +1,5 @@
1
1
  export { getContext } from './get-context';
2
+ export { AccessTokenMissingError, RefreshAccessTokenFailedError, } from './auth-errors';
2
3
  export declare function getVercelOidcToken(): Promise<string>;
3
4
  export declare function getVercelOidcTokenSync(): string;
5
+ export declare function getVercelToken(): Promise<string>;
@@ -18,21 +18,31 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var index_browser_exports = {};
20
20
  __export(index_browser_exports, {
21
+ AccessTokenMissingError: () => import_auth_errors.AccessTokenMissingError,
22
+ RefreshAccessTokenFailedError: () => import_auth_errors.RefreshAccessTokenFailedError,
21
23
  getContext: () => import_get_context.getContext,
22
24
  getVercelOidcToken: () => getVercelOidcToken,
23
- getVercelOidcTokenSync: () => getVercelOidcTokenSync
25
+ getVercelOidcTokenSync: () => getVercelOidcTokenSync,
26
+ getVercelToken: () => getVercelToken
24
27
  });
25
28
  module.exports = __toCommonJS(index_browser_exports);
26
29
  var import_get_context = require("./get-context");
30
+ var import_auth_errors = require("./auth-errors");
27
31
  async function getVercelOidcToken() {
28
32
  return "";
29
33
  }
30
34
  function getVercelOidcTokenSync() {
31
35
  return "";
32
36
  }
37
+ async function getVercelToken() {
38
+ throw new Error("getVercelToken is not supported in browser environments");
39
+ }
33
40
  // Annotate the CommonJS export names for ESM import in node:
34
41
  0 && (module.exports = {
42
+ AccessTokenMissingError,
43
+ RefreshAccessTokenFailedError,
35
44
  getContext,
36
45
  getVercelOidcToken,
37
- getVercelOidcTokenSync
46
+ getVercelOidcTokenSync,
47
+ getVercelToken
38
48
  });
package/dist/index.d.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  export { getVercelOidcToken, getVercelOidcTokenSync, } from './get-vercel-oidc-token';
2
2
  export { getContext } from './get-context';
3
+ export { AccessTokenMissingError, RefreshAccessTokenFailedError, } from './auth-errors';
4
+ export { getVercelToken } from './token-util';
package/dist/index.js CHANGED
@@ -18,16 +18,24 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var src_exports = {};
20
20
  __export(src_exports, {
21
+ AccessTokenMissingError: () => import_auth_errors.AccessTokenMissingError,
22
+ RefreshAccessTokenFailedError: () => import_auth_errors.RefreshAccessTokenFailedError,
21
23
  getContext: () => import_get_context.getContext,
22
24
  getVercelOidcToken: () => import_get_vercel_oidc_token.getVercelOidcToken,
23
- getVercelOidcTokenSync: () => import_get_vercel_oidc_token.getVercelOidcTokenSync
25
+ getVercelOidcTokenSync: () => import_get_vercel_oidc_token.getVercelOidcTokenSync,
26
+ getVercelToken: () => import_token_util.getVercelToken
24
27
  });
25
28
  module.exports = __toCommonJS(src_exports);
26
29
  var import_get_vercel_oidc_token = require("./get-vercel-oidc-token");
27
30
  var import_get_context = require("./get-context");
31
+ var import_auth_errors = require("./auth-errors");
32
+ var import_token_util = require("./token-util");
28
33
  // Annotate the CommonJS export names for ESM import in node:
29
34
  0 && (module.exports = {
35
+ AccessTokenMissingError,
36
+ RefreshAccessTokenFailedError,
30
37
  getContext,
31
38
  getVercelOidcToken,
32
- getVercelOidcTokenSync
39
+ getVercelOidcTokenSync,
40
+ getVercelToken
33
41
  });
@@ -1,5 +1,13 @@
1
1
  export declare function getVercelDataDir(): string | null;
2
- export declare function getVercelCliToken(): Promise<string | null>;
2
+ export interface GetVercelTokenOptions {
3
+ /**
4
+ * Optional time buffer in milliseconds before token expiry to consider it expired.
5
+ * When provided, the token will be refreshed if it expires within this buffer time.
6
+ * @default 0
7
+ */
8
+ expirationBufferMs?: number;
9
+ }
10
+ export declare function getVercelToken(options?: GetVercelTokenOptions): Promise<string>;
3
11
  interface VercelTokenResponse {
4
12
  token: string;
5
13
  }
@@ -17,5 +25,5 @@ interface TokenPayload {
17
25
  exp: number;
18
26
  }
19
27
  export declare function getTokenPayload(token: string): TokenPayload;
20
- export declare function isExpired(token: TokenPayload): boolean;
28
+ export declare function isExpired(token: TokenPayload, bufferMs?: number): boolean;
21
29
  export {};
@@ -31,9 +31,9 @@ __export(token_util_exports, {
31
31
  assertVercelOidcTokenResponse: () => assertVercelOidcTokenResponse,
32
32
  findProjectInfo: () => findProjectInfo,
33
33
  getTokenPayload: () => getTokenPayload,
34
- getVercelCliToken: () => getVercelCliToken,
35
34
  getVercelDataDir: () => getVercelDataDir,
36
35
  getVercelOidcToken: () => getVercelOidcToken,
36
+ getVercelToken: () => getVercelToken,
37
37
  isExpired: () => isExpired,
38
38
  loadToken: () => loadToken,
39
39
  saveToken: () => saveToken
@@ -45,6 +45,7 @@ var import_token_error = require("./token-error");
45
45
  var import_token_io = require("./token-io");
46
46
  var import_auth_config = require("./auth-config");
47
47
  var import_oauth = require("./oauth");
48
+ var import_auth_errors = require("./auth-errors");
48
49
  function getVercelDataDir() {
49
50
  const vercelFolder = "com.vercel.cli";
50
51
  const dataDir = (0, import_token_io.getUserDataDir)();
@@ -53,17 +54,17 @@ function getVercelDataDir() {
53
54
  }
54
55
  return path.join(dataDir, vercelFolder);
55
56
  }
56
- async function getVercelCliToken() {
57
+ async function getVercelToken(options) {
57
58
  const authConfig = (0, import_auth_config.readAuthConfig)();
58
- if (!authConfig) {
59
- return null;
59
+ if (!authConfig?.token) {
60
+ throw new import_auth_errors.AccessTokenMissingError();
60
61
  }
61
- if ((0, import_auth_config.isValidAccessToken)(authConfig)) {
62
- return authConfig.token || null;
62
+ if ((0, import_auth_config.isValidAccessToken)(authConfig, options?.expirationBufferMs)) {
63
+ return authConfig.token;
63
64
  }
64
65
  if (!authConfig.refreshToken) {
65
66
  (0, import_auth_config.writeAuthConfig)({});
66
- return null;
67
+ throw new import_auth_errors.RefreshAccessTokenFailedError("No refresh token available");
67
68
  }
68
69
  try {
69
70
  const tokenResponse = await (0, import_oauth.refreshTokenRequest)({
@@ -72,7 +73,7 @@ async function getVercelCliToken() {
72
73
  const [tokensError, tokens] = await (0, import_oauth.processTokenResponse)(tokenResponse);
73
74
  if (tokensError || !tokens) {
74
75
  (0, import_auth_config.writeAuthConfig)({});
75
- return null;
76
+ throw new import_auth_errors.RefreshAccessTokenFailedError(tokensError);
76
77
  }
77
78
  const updatedConfig = {
78
79
  token: tokens.access_token,
@@ -82,10 +83,13 @@ async function getVercelCliToken() {
82
83
  updatedConfig.refreshToken = tokens.refresh_token;
83
84
  }
84
85
  (0, import_auth_config.writeAuthConfig)(updatedConfig);
85
- return updatedConfig.token ?? null;
86
+ return updatedConfig.token;
86
87
  } catch (error) {
87
88
  (0, import_auth_config.writeAuthConfig)({});
88
- return null;
89
+ if (error instanceof import_auth_errors.AccessTokenMissingError || error instanceof import_auth_errors.RefreshAccessTokenFailedError) {
90
+ throw error;
91
+ }
92
+ throw new import_auth_errors.RefreshAccessTokenFailedError(error);
89
93
  }
90
94
  }
91
95
  async function getVercelOidcToken(authToken, projectId, teamId) {
@@ -181,17 +185,17 @@ function getTokenPayload(token) {
181
185
  );
182
186
  return JSON.parse(Buffer.from(padded, "base64").toString("utf8"));
183
187
  }
184
- function isExpired(token) {
185
- return token.exp * 1e3 < Date.now();
188
+ function isExpired(token, bufferMs = 0) {
189
+ return token.exp * 1e3 < Date.now() + bufferMs;
186
190
  }
187
191
  // Annotate the CommonJS export names for ESM import in node:
188
192
  0 && (module.exports = {
189
193
  assertVercelOidcTokenResponse,
190
194
  findProjectInfo,
191
195
  getTokenPayload,
192
- getVercelCliToken,
193
196
  getVercelDataDir,
194
197
  getVercelOidcToken,
198
+ getVercelToken,
195
199
  isExpired,
196
200
  loadToken,
197
201
  saveToken
@@ -25,12 +25,13 @@ var import_vitest = require("vitest");
25
25
  var import_token_util = require("./token-util");
26
26
  var authConfig = __toESM(require("./auth-config"));
27
27
  var oauth = __toESM(require("./oauth"));
28
+ var import_auth_errors = require("./auth-errors");
28
29
  import_vitest.vi.mock("fs");
29
30
  import_vitest.vi.mock("./token-io", () => ({
30
31
  getUserDataDir: import_vitest.vi.fn(() => "/mock/user/data"),
31
32
  findRootDir: import_vitest.vi.fn(() => "/mock/root")
32
33
  }));
33
- (0, import_vitest.describe)("getVercelCliToken", () => {
34
+ (0, import_vitest.describe)("getVercelToken", () => {
34
35
  (0, import_vitest.beforeEach)(() => {
35
36
  import_vitest.vi.clearAllMocks();
36
37
  });
@@ -47,14 +48,13 @@ import_vitest.vi.mock("./token-io", () => ({
47
48
  import_vitest.vi.spyOn(authConfig, "readAuthConfig").mockReturnValue(validToken);
48
49
  import_vitest.vi.spyOn(authConfig, "writeAuthConfig").mockImplementation(() => {
49
50
  });
50
- const token = await (0, import_token_util.getVercelCliToken)();
51
+ const token = await (0, import_token_util.getVercelToken)();
51
52
  (0, import_vitest.expect)(token).toBe("valid-access-token");
52
53
  (0, import_vitest.expect)(authConfig.writeAuthConfig).not.toHaveBeenCalled();
53
54
  });
54
- (0, import_vitest.it)("should return null if auth config does not exist", async () => {
55
+ (0, import_vitest.it)("should throw AccessTokenMissingError if auth config does not exist", async () => {
55
56
  import_vitest.vi.spyOn(authConfig, "readAuthConfig").mockReturnValue(null);
56
- const token = await (0, import_token_util.getVercelCliToken)();
57
- (0, import_vitest.expect)(token).toBeNull();
57
+ await (0, import_vitest.expect)((0, import_token_util.getVercelToken)()).rejects.toThrow(import_auth_errors.AccessTokenMissingError);
58
58
  });
59
59
  (0, import_vitest.it)("should refresh token if expired and refresh token exists", async () => {
60
60
  const expiredToken = {
@@ -76,7 +76,7 @@ import_vitest.vi.mock("./token-io", () => ({
76
76
  import_vitest.vi.spyOn(authConfig, "writeAuthConfig").mockImplementation(() => {
77
77
  });
78
78
  import_vitest.vi.spyOn(oauth, "refreshTokenRequest").mockResolvedValue(mockResponse);
79
- const token = await (0, import_token_util.getVercelCliToken)();
79
+ const token = await (0, import_token_util.getVercelToken)();
80
80
  (0, import_vitest.expect)(token).toBe("new-access-token");
81
81
  (0, import_vitest.expect)(oauth.refreshTokenRequest).toHaveBeenCalledWith({
82
82
  refresh_token: "valid-refresh-token"
@@ -89,7 +89,7 @@ import_vitest.vi.mock("./token-io", () => ({
89
89
  })
90
90
  );
91
91
  });
92
- (0, import_vitest.it)("should clear auth and return null if token expired and no refresh token", async () => {
92
+ (0, import_vitest.it)("should clear auth and throw RefreshAccessTokenFailedError if token expired and no refresh token", async () => {
93
93
  const expiredTokenNoRefresh = {
94
94
  token: "expired-access-token",
95
95
  expiresAt: Math.floor(Date.now() / 1e3) - 3600
@@ -99,11 +99,12 @@ import_vitest.vi.mock("./token-io", () => ({
99
99
  );
100
100
  import_vitest.vi.spyOn(authConfig, "writeAuthConfig").mockImplementation(() => {
101
101
  });
102
- const token = await (0, import_token_util.getVercelCliToken)();
103
- (0, import_vitest.expect)(token).toBeNull();
102
+ await (0, import_vitest.expect)((0, import_token_util.getVercelToken)()).rejects.toThrow(
103
+ import_auth_errors.RefreshAccessTokenFailedError
104
+ );
104
105
  (0, import_vitest.expect)(authConfig.writeAuthConfig).toHaveBeenCalledWith({});
105
106
  });
106
- (0, import_vitest.it)("should clear auth if refresh fails with OAuth error", async () => {
107
+ (0, import_vitest.it)("should clear auth and throw RefreshAccessTokenFailedError if refresh fails with OAuth error", async () => {
107
108
  const expiredToken = {
108
109
  token: "expired-access-token",
109
110
  refreshToken: "invalid-refresh-token",
@@ -120,11 +121,12 @@ import_vitest.vi.mock("./token-io", () => ({
120
121
  import_vitest.vi.spyOn(authConfig, "writeAuthConfig").mockImplementation(() => {
121
122
  });
122
123
  import_vitest.vi.spyOn(oauth, "refreshTokenRequest").mockResolvedValue(mockErrorResponse);
123
- const token = await (0, import_token_util.getVercelCliToken)();
124
- (0, import_vitest.expect)(token).toBeNull();
124
+ await (0, import_vitest.expect)((0, import_token_util.getVercelToken)()).rejects.toThrow(
125
+ import_auth_errors.RefreshAccessTokenFailedError
126
+ );
125
127
  (0, import_vitest.expect)(authConfig.writeAuthConfig).toHaveBeenCalledWith({});
126
128
  });
127
- (0, import_vitest.it)("should clear auth if refresh fails with network error", async () => {
129
+ (0, import_vitest.it)("should clear auth and throw RefreshAccessTokenFailedError if refresh fails with network error", async () => {
128
130
  const expiredToken = {
129
131
  token: "expired-access-token",
130
132
  refreshToken: "valid-refresh-token",
@@ -136,8 +138,9 @@ import_vitest.vi.mock("./token-io", () => ({
136
138
  import_vitest.vi.spyOn(oauth, "refreshTokenRequest").mockRejectedValue(
137
139
  new Error("Network error")
138
140
  );
139
- const token = await (0, import_token_util.getVercelCliToken)();
140
- (0, import_vitest.expect)(token).toBeNull();
141
+ await (0, import_vitest.expect)((0, import_token_util.getVercelToken)()).rejects.toThrow(
142
+ import_auth_errors.RefreshAccessTokenFailedError
143
+ );
141
144
  (0, import_vitest.expect)(authConfig.writeAuthConfig).toHaveBeenCalledWith({});
142
145
  });
143
146
  (0, import_vitest.it)("should treat token as valid if expiresAt is missing (--token case)", async () => {
@@ -147,7 +150,7 @@ import_vitest.vi.mock("./token-io", () => ({
147
150
  import_vitest.vi.spyOn(authConfig, "readAuthConfig").mockReturnValue(tokenWithoutExpiry);
148
151
  import_vitest.vi.spyOn(authConfig, "writeAuthConfig").mockImplementation(() => {
149
152
  });
150
- const token = await (0, import_token_util.getVercelCliToken)();
153
+ const token = await (0, import_token_util.getVercelToken)();
151
154
  (0, import_vitest.expect)(token).toBe("cli-provided-token");
152
155
  (0, import_vitest.expect)(authConfig.writeAuthConfig).not.toHaveBeenCalled();
153
156
  });
@@ -170,7 +173,7 @@ import_vitest.vi.mock("./token-io", () => ({
170
173
  import_vitest.vi.spyOn(authConfig, "writeAuthConfig").mockImplementation(() => {
171
174
  });
172
175
  import_vitest.vi.spyOn(oauth, "refreshTokenRequest").mockResolvedValue(mockResponse);
173
- await (0, import_token_util.getVercelCliToken)();
176
+ await (0, import_token_util.getVercelToken)();
174
177
  (0, import_vitest.expect)(authConfig.writeAuthConfig).toHaveBeenCalledWith(
175
178
  import_vitest.expect.objectContaining({
176
179
  refreshToken: "new-refresh-token"
@@ -196,7 +199,7 @@ import_vitest.vi.mock("./token-io", () => ({
196
199
  import_vitest.vi.spyOn(authConfig, "writeAuthConfig").mockImplementation(() => {
197
200
  });
198
201
  import_vitest.vi.spyOn(oauth, "refreshTokenRequest").mockResolvedValue(mockResponse);
199
- await (0, import_token_util.getVercelCliToken)();
202
+ await (0, import_token_util.getVercelToken)();
200
203
  const writeCall = import_vitest.vi.mocked(authConfig.writeAuthConfig).mock.calls[0][0];
201
204
  (0, import_vitest.expect)(writeCall).not.toHaveProperty("refreshToken");
202
205
  });
@@ -220,7 +223,7 @@ import_vitest.vi.mock("./token-io", () => ({
220
223
  });
221
224
  import_vitest.vi.spyOn(oauth, "refreshTokenRequest").mockResolvedValue(mockResponse);
222
225
  const beforeCall = Math.floor(Date.now() / 1e3);
223
- await (0, import_token_util.getVercelCliToken)();
226
+ await (0, import_token_util.getVercelToken)();
224
227
  const afterCall = Math.floor(Date.now() / 1e3);
225
228
  const writeCall = import_vitest.vi.mocked(authConfig.writeAuthConfig).mock.calls[0][0];
226
229
  (0, import_vitest.expect)(writeCall.expiresAt).toBeGreaterThanOrEqual(beforeCall + 7200);
package/dist/token.d.ts CHANGED
@@ -1 +1,19 @@
1
- export declare function refreshToken(): Promise<void>;
1
+ export interface RefreshTokenOptions {
2
+ /**
3
+ * Team ID (team_*) or slug to use for token refresh.
4
+ * When provided, this team will be used instead of reading from `.vercel/project.json`.
5
+ */
6
+ team?: string;
7
+ /**
8
+ * Project ID (prj_*) or slug to use for token refresh.
9
+ * When provided, this project will be used instead of reading from `.vercel/project.json`.
10
+ */
11
+ project?: string;
12
+ /**
13
+ * Optional time buffer in milliseconds before token expiry to consider it expired.
14
+ * When provided, the token will be refreshed if it expires within this buffer time.
15
+ * @default 0
16
+ */
17
+ expirationBufferMs?: number;
18
+ }
19
+ export declare function refreshToken(options?: RefreshTokenOptions): Promise<void>;
package/dist/token.js CHANGED
@@ -23,21 +23,28 @@ __export(token_exports, {
23
23
  module.exports = __toCommonJS(token_exports);
24
24
  var import_token_error = require("./token-error");
25
25
  var import_token_util = require("./token-util");
26
- async function refreshToken() {
27
- const { projectId, teamId } = (0, import_token_util.findProjectInfo)();
26
+ async function refreshToken(options) {
27
+ let projectId = options?.project;
28
+ let teamId = options?.team;
29
+ if (!projectId && !teamId) {
30
+ const projectInfo = (0, import_token_util.findProjectInfo)();
31
+ projectId = projectInfo.projectId;
32
+ teamId = projectInfo.teamId;
33
+ } else if (!projectId || !teamId) {
34
+ const projectInfo = (0, import_token_util.findProjectInfo)();
35
+ projectId = projectId ?? projectInfo.projectId;
36
+ teamId = teamId ?? projectInfo.teamId;
37
+ }
38
+ if (!projectId) {
39
+ throw new import_token_error.VercelOidcTokenError(
40
+ "Failed to refresh OIDC token: No project specified. Try re-linking your project with `vc link`"
41
+ );
42
+ }
28
43
  let maybeToken = (0, import_token_util.loadToken)(projectId);
29
- if (!maybeToken || (0, import_token_util.isExpired)((0, import_token_util.getTokenPayload)(maybeToken.token))) {
30
- const authToken = await (0, import_token_util.getVercelCliToken)();
31
- if (!authToken) {
32
- throw new import_token_error.VercelOidcTokenError(
33
- "Failed to refresh OIDC token: Log in to Vercel CLI and link your project with `vc link`"
34
- );
35
- }
36
- if (!projectId) {
37
- throw new import_token_error.VercelOidcTokenError(
38
- "Failed to refresh OIDC token: Try re-linking your project with `vc link`"
39
- );
40
- }
44
+ if (!maybeToken || (0, import_token_util.isExpired)((0, import_token_util.getTokenPayload)(maybeToken.token), options?.expirationBufferMs)) {
45
+ const authToken = await (0, import_token_util.getVercelToken)({
46
+ expirationBufferMs: options?.expirationBufferMs
47
+ });
41
48
  maybeToken = await (0, import_token_util.getVercelOidcToken)(authToken, projectId, teamId);
42
49
  if (!maybeToken) {
43
50
  throw new import_token_error.VercelOidcTokenError("Failed to refresh OIDC token");
@@ -35,7 +35,7 @@ import_vitest.vi.mock("./token-io");
35
35
  let userDataDir;
36
36
  let cliDataDir;
37
37
  let tokenDataDir;
38
- const projectId = "test-project-id";
38
+ const projectId = "prj_test123";
39
39
  (0, import_vitest.beforeEach)(() => {
40
40
  import_vitest.vi.clearAllMocks();
41
41
  process.env.VERCEL_OIDC_TOKEN = void 0;
@@ -57,7 +57,7 @@ import_vitest.vi.mock("./token-io");
57
57
  import_vitest.vi.spyOn(process, "cwd").mockReturnValue(rootDir);
58
58
  import_vitest.vi.mocked(import_token_io.findRootDir).mockReturnValue(rootDir);
59
59
  import_vitest.vi.mocked(import_token_io.getUserDataDir).mockReturnValue(userDataDir);
60
- import_vitest.vi.spyOn(tokenUtil, "getVercelCliToken").mockResolvedValue("test");
60
+ import_vitest.vi.spyOn(tokenUtil, "getVercelToken").mockResolvedValue("test");
61
61
  import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
62
62
  token: "test-token"
63
63
  });
@@ -81,4 +81,110 @@ import_vitest.vi.mock("./token-io");
81
81
  const token = JSON.parse(fs.readFileSync(tokenPath, "utf8"));
82
82
  (0, import_vitest.expect)(token).toEqual({ token: "test-token" });
83
83
  });
84
+ (0, import_vitest.test)("should use provided team and project instead of reading project.json", async () => {
85
+ const customProjectId = "prj_custom123";
86
+ const customTeamId = "team_custom456";
87
+ const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken");
88
+ const findRootDirSpy = import_vitest.vi.mocked(import_token_io.findRootDir);
89
+ await (0, import_token.refreshToken)({ team: customTeamId, project: customProjectId });
90
+ (0, import_vitest.expect)(findRootDirSpy).not.toHaveBeenCalled();
91
+ (0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
92
+ "test",
93
+ customProjectId,
94
+ customTeamId
95
+ );
96
+ const tokenPath = path.join(tokenDataDir, `${customProjectId}.json`);
97
+ (0, import_vitest.expect)(fs.existsSync(tokenPath)).toBe(true);
98
+ const savedToken = JSON.parse(fs.readFileSync(tokenPath, "utf8"));
99
+ (0, import_vitest.expect)(savedToken).toEqual({ token: "test-token" });
100
+ });
101
+ (0, import_vitest.test)("should merge provided project with team from project.json", async () => {
102
+ const customProjectId = "prj_custom234";
103
+ const projectTeamId = "team_fromproject567";
104
+ fs.writeFileSync(
105
+ path.join(rootDir, ".vercel", "project.json"),
106
+ JSON.stringify({ projectId, orgId: projectTeamId })
107
+ );
108
+ const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken");
109
+ await (0, import_token.refreshToken)({ project: customProjectId });
110
+ (0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
111
+ "test",
112
+ customProjectId,
113
+ projectTeamId
114
+ );
115
+ });
116
+ (0, import_vitest.test)("should merge provided team with project from project.json", async () => {
117
+ const customTeamId = "team_custom789";
118
+ const projectProjectId = "prj_fromjson123";
119
+ fs.writeFileSync(
120
+ path.join(rootDir, ".vercel", "project.json"),
121
+ JSON.stringify({ projectId: projectProjectId, orgId: "original-team" })
122
+ );
123
+ const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken");
124
+ await (0, import_token.refreshToken)({ team: customTeamId });
125
+ (0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
126
+ "test",
127
+ projectProjectId,
128
+ customTeamId
129
+ );
130
+ });
131
+ (0, import_vitest.test)("should use cached token when valid with custom project", async () => {
132
+ const customProjectId = "prj_customcached123";
133
+ const customTeamId = "team_customcached456";
134
+ const cachedToken = { token: "cached-valid-token" };
135
+ const tokenPath = path.join(tokenDataDir, `${customProjectId}.json`);
136
+ fs.writeFileSync(tokenPath, JSON.stringify(cachedToken));
137
+ const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken");
138
+ await (0, import_token.refreshToken)({ team: customTeamId, project: customProjectId });
139
+ (0, import_vitest.expect)(getVercelOidcTokenSpy).not.toHaveBeenCalled();
140
+ (0, import_vitest.expect)(process.env.VERCEL_OIDC_TOKEN).toBe("cached-valid-token");
141
+ });
142
+ (0, import_vitest.test)("should refresh token when cached token expires within buffer", async () => {
143
+ const customProjectId = "prj_buffertest123";
144
+ const customTeamId = "team_buffertest456";
145
+ const cachedToken = { token: "expiring-soon-token" };
146
+ const tokenPath = path.join(tokenDataDir, `${customProjectId}.json`);
147
+ fs.writeFileSync(tokenPath, JSON.stringify(cachedToken));
148
+ const expiresIn3Minutes = Math.floor((Date.now() + 18e4) / 1e3);
149
+ import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValue({
150
+ sub: "test-sub",
151
+ name: "test-name",
152
+ exp: expiresIn3Minutes
153
+ });
154
+ const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({ token: "fresh-token" });
155
+ await (0, import_token.refreshToken)({
156
+ team: customTeamId,
157
+ project: customProjectId,
158
+ expirationBufferMs: 3e5
159
+ });
160
+ (0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
161
+ "test",
162
+ customProjectId,
163
+ customTeamId
164
+ );
165
+ (0, import_vitest.expect)(process.env.VERCEL_OIDC_TOKEN).toBe("fresh-token");
166
+ const savedToken = JSON.parse(fs.readFileSync(tokenPath, "utf8"));
167
+ (0, import_vitest.expect)(savedToken).toEqual({ token: "fresh-token" });
168
+ });
169
+ (0, import_vitest.test)("should use cached token when it does not expire within buffer", async () => {
170
+ const customProjectId = "prj_buffervalid123";
171
+ const customTeamId = "team_buffervalid456";
172
+ const cachedToken = { token: "valid-cached-token" };
173
+ const tokenPath = path.join(tokenDataDir, `${customProjectId}.json`);
174
+ fs.writeFileSync(tokenPath, JSON.stringify(cachedToken));
175
+ const expiresIn10Minutes = Math.floor((Date.now() + 6e5) / 1e3);
176
+ import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValue({
177
+ sub: "test-sub",
178
+ name: "test-name",
179
+ exp: expiresIn10Minutes
180
+ });
181
+ const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken");
182
+ await (0, import_token.refreshToken)({
183
+ team: customTeamId,
184
+ project: customProjectId,
185
+ expirationBufferMs: 3e5
186
+ });
187
+ (0, import_vitest.expect)(getVercelOidcTokenSpy).not.toHaveBeenCalled();
188
+ (0, import_vitest.expect)(process.env.VERCEL_OIDC_TOKEN).toBe("valid-cached-token");
189
+ });
84
190
  });
package/docs/README.md CHANGED
@@ -2,11 +2,17 @@
2
2
 
3
3
  ## Table of contents
4
4
 
5
+ ### Classes
6
+
7
+ - [AccessTokenMissingError](classes/AccessTokenMissingError.md)
8
+ - [RefreshAccessTokenFailedError](classes/RefreshAccessTokenFailedError.md)
9
+
5
10
  ### Functions
6
11
 
7
12
  - [getContext](README.md#getcontext)
8
13
  - [getVercelOidcToken](README.md#getverceloidctoken)
9
14
  - [getVercelOidcTokenSync](README.md#getverceloidctokensync)
15
+ - [getVercelToken](README.md#getverceltoken)
10
16
 
11
17
  ## Functions
12
18
 
@@ -20,13 +26,13 @@
20
26
 
21
27
  #### Defined in
22
28
 
23
- [get-context.ts:7](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-context.ts#L7)
29
+ [packages/oidc/src/get-context.ts:7](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-context.ts#L7)
24
30
 
25
31
  ---
26
32
 
27
33
  ### getVercelOidcToken
28
34
 
29
- ▸ **getVercelOidcToken**(): [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`string`\>
35
+ ▸ **getVercelOidcToken**(`options?`): [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`string`\>
30
36
 
31
37
  Gets the current OIDC token from the request context or the environment variable.
32
38
 
@@ -56,6 +62,25 @@ getVercelOidcToken()
56
62
  });
57
63
  ```
58
64
 
65
+ **`Example`**
66
+
67
+ ```js
68
+ // Using the OIDC token with explicit team and project (supports IDs and slugs)
69
+ getVercelOidcToken({ team: 'my-team', project: 'my-project' })
70
+ .then(token => {
71
+ console.log('OIDC Token:', token);
72
+ })
73
+ .catch(error => {
74
+ console.error('Error:', error.message);
75
+ });
76
+ ```
77
+
78
+ #### Parameters
79
+
80
+ | Name | Type | Description |
81
+ | :--------- | :-------------------------- | :------------------------------------------ |
82
+ | `options?` | `GetVercelOidcTokenOptions` | Optional configuration for token retrieval. |
83
+
59
84
  #### Returns
60
85
 
61
86
  [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`string`\>
@@ -64,7 +89,7 @@ A promise that resolves to the OIDC token.
64
89
 
65
90
  #### Defined in
66
91
 
67
- [get-vercel-oidc-token.ts:30](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-vercel-oidc-token.ts#L30)
92
+ [packages/oidc/src/get-vercel-oidc-token.ts:64](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-vercel-oidc-token.ts#L64)
68
93
 
69
94
  ---
70
95
 
@@ -101,4 +126,24 @@ The OIDC token.
101
126
 
102
127
  #### Defined in
103
128
 
104
- [get-vercel-oidc-token.ts:85](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-vercel-oidc-token.ts#L85)
129
+ [packages/oidc/src/get-vercel-oidc-token.ts:124](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-vercel-oidc-token.ts#L124)
130
+
131
+ ---
132
+
133
+ ### getVercelToken
134
+
135
+ ▸ **getVercelToken**(`options?`): [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`string`\>
136
+
137
+ #### Parameters
138
+
139
+ | Name | Type |
140
+ | :--------- | :---------------------- |
141
+ | `options?` | `GetVercelTokenOptions` |
142
+
143
+ #### Returns
144
+
145
+ [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`string`\>
146
+
147
+ #### Defined in
148
+
149
+ [packages/oidc/src/token-util.ts:35](https://github.com/vercel/vercel/blob/main/packages/oidc/src/token-util.ts#L35)
@@ -0,0 +1,160 @@
1
+ # Class: AccessTokenMissingError
2
+
3
+ Error thrown when no authentication configuration is found.
4
+ This typically means the user needs to log in.
5
+
6
+ ## Hierarchy
7
+
8
+ - [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
9
+
10
+ ↳ **`AccessTokenMissingError`**
11
+
12
+ ## Table of contents
13
+
14
+ ### Constructors
15
+
16
+ - [constructor](AccessTokenMissingError.md#constructor)
17
+
18
+ ### Properties
19
+
20
+ - [message](AccessTokenMissingError.md#message)
21
+ - [name](AccessTokenMissingError.md#name)
22
+ - [stack](AccessTokenMissingError.md#stack)
23
+ - [prepareStackTrace](AccessTokenMissingError.md#preparestacktrace)
24
+ - [stackTraceLimit](AccessTokenMissingError.md#stacktracelimit)
25
+
26
+ ### Methods
27
+
28
+ - [captureStackTrace](AccessTokenMissingError.md#capturestacktrace)
29
+
30
+ ## Constructors
31
+
32
+ ### constructor
33
+
34
+ • **new AccessTokenMissingError**()
35
+
36
+ #### Overrides
37
+
38
+ Error.constructor
39
+
40
+ #### Defined in
41
+
42
+ [packages/oidc/src/auth-errors.ts:7](https://github.com/vercel/vercel/blob/main/packages/oidc/src/auth-errors.ts#L7)
43
+
44
+ ## Properties
45
+
46
+ ### message
47
+
48
+ • **message**: `string`
49
+
50
+ #### Inherited from
51
+
52
+ Error.message
53
+
54
+ #### Defined in
55
+
56
+ node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es5.d.ts:1054
57
+
58
+ ---
59
+
60
+ ### name
61
+
62
+ • **name**: `string` = `'AccessTokenMissingError'`
63
+
64
+ #### Overrides
65
+
66
+ Error.name
67
+
68
+ #### Defined in
69
+
70
+ [packages/oidc/src/auth-errors.ts:6](https://github.com/vercel/vercel/blob/main/packages/oidc/src/auth-errors.ts#L6)
71
+
72
+ ---
73
+
74
+ ### stack
75
+
76
+ • `Optional` **stack**: `string`
77
+
78
+ #### Inherited from
79
+
80
+ Error.stack
81
+
82
+ #### Defined in
83
+
84
+ node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es5.d.ts:1055
85
+
86
+ ---
87
+
88
+ ### prepareStackTrace
89
+
90
+ ▪ `Static` `Optional` **prepareStackTrace**: (`err`: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error), `stackTraces`: `CallSite`[]) => `any`
91
+
92
+ #### Type declaration
93
+
94
+ ▸ (`err`, `stackTraces`): `any`
95
+
96
+ Optional override for formatting stack traces
97
+
98
+ **`See`**
99
+
100
+ https://v8.dev/docs/stack-trace-api#customizing-stack-traces
101
+
102
+ ##### Parameters
103
+
104
+ | Name | Type |
105
+ | :------------ | :------------------------------------------------------------------------------------------------ |
106
+ | `err` | [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) |
107
+ | `stackTraces` | `CallSite`[] |
108
+
109
+ ##### Returns
110
+
111
+ `any`
112
+
113
+ #### Inherited from
114
+
115
+ Error.prepareStackTrace
116
+
117
+ #### Defined in
118
+
119
+ node_modules/.pnpm/@types+node@20.11.0/node_modules/@types/node/globals.d.ts:28
120
+
121
+ ---
122
+
123
+ ### stackTraceLimit
124
+
125
+ ▪ `Static` **stackTraceLimit**: `number`
126
+
127
+ #### Inherited from
128
+
129
+ Error.stackTraceLimit
130
+
131
+ #### Defined in
132
+
133
+ node_modules/.pnpm/@types+node@20.11.0/node_modules/@types/node/globals.d.ts:30
134
+
135
+ ## Methods
136
+
137
+ ### captureStackTrace
138
+
139
+ ▸ `Static` **captureStackTrace**(`targetObject`, `constructorOpt?`): `void`
140
+
141
+ Create .stack property on a target object
142
+
143
+ #### Parameters
144
+
145
+ | Name | Type |
146
+ | :---------------- | :------------------------------------------------------------------------------------------------------ |
147
+ | `targetObject` | `object` |
148
+ | `constructorOpt?` | [`Function`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) |
149
+
150
+ #### Returns
151
+
152
+ `void`
153
+
154
+ #### Inherited from
155
+
156
+ Error.captureStackTrace
157
+
158
+ #### Defined in
159
+
160
+ node_modules/.pnpm/@types+node@20.11.0/node_modules/@types/node/globals.d.ts:21
@@ -0,0 +1,166 @@
1
+ # Class: RefreshAccessTokenFailedError
2
+
3
+ Error thrown when attempting to refresh the authentication token fails.
4
+ This includes cases where no refresh token is available.
5
+
6
+ ## Hierarchy
7
+
8
+ - [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
9
+
10
+ ↳ **`RefreshAccessTokenFailedError`**
11
+
12
+ ## Table of contents
13
+
14
+ ### Constructors
15
+
16
+ - [constructor](RefreshAccessTokenFailedError.md#constructor)
17
+
18
+ ### Properties
19
+
20
+ - [message](RefreshAccessTokenFailedError.md#message)
21
+ - [name](RefreshAccessTokenFailedError.md#name)
22
+ - [stack](RefreshAccessTokenFailedError.md#stack)
23
+ - [prepareStackTrace](RefreshAccessTokenFailedError.md#preparestacktrace)
24
+ - [stackTraceLimit](RefreshAccessTokenFailedError.md#stacktracelimit)
25
+
26
+ ### Methods
27
+
28
+ - [captureStackTrace](RefreshAccessTokenFailedError.md#capturestacktrace)
29
+
30
+ ## Constructors
31
+
32
+ ### constructor
33
+
34
+ • **new RefreshAccessTokenFailedError**(`cause?`)
35
+
36
+ #### Parameters
37
+
38
+ | Name | Type |
39
+ | :------- | :-------- |
40
+ | `cause?` | `unknown` |
41
+
42
+ #### Overrides
43
+
44
+ Error.constructor
45
+
46
+ #### Defined in
47
+
48
+ [packages/oidc/src/auth-errors.ts:20](https://github.com/vercel/vercel/blob/main/packages/oidc/src/auth-errors.ts#L20)
49
+
50
+ ## Properties
51
+
52
+ ### message
53
+
54
+ • **message**: `string`
55
+
56
+ #### Inherited from
57
+
58
+ Error.message
59
+
60
+ #### Defined in
61
+
62
+ node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es5.d.ts:1054
63
+
64
+ ---
65
+
66
+ ### name
67
+
68
+ • **name**: `string` = `'RefreshAccessTokenFailedError'`
69
+
70
+ #### Overrides
71
+
72
+ Error.name
73
+
74
+ #### Defined in
75
+
76
+ [packages/oidc/src/auth-errors.ts:19](https://github.com/vercel/vercel/blob/main/packages/oidc/src/auth-errors.ts#L19)
77
+
78
+ ---
79
+
80
+ ### stack
81
+
82
+ • `Optional` **stack**: `string`
83
+
84
+ #### Inherited from
85
+
86
+ Error.stack
87
+
88
+ #### Defined in
89
+
90
+ node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es5.d.ts:1055
91
+
92
+ ---
93
+
94
+ ### prepareStackTrace
95
+
96
+ ▪ `Static` `Optional` **prepareStackTrace**: (`err`: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error), `stackTraces`: `CallSite`[]) => `any`
97
+
98
+ #### Type declaration
99
+
100
+ ▸ (`err`, `stackTraces`): `any`
101
+
102
+ Optional override for formatting stack traces
103
+
104
+ **`See`**
105
+
106
+ https://v8.dev/docs/stack-trace-api#customizing-stack-traces
107
+
108
+ ##### Parameters
109
+
110
+ | Name | Type |
111
+ | :------------ | :------------------------------------------------------------------------------------------------ |
112
+ | `err` | [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) |
113
+ | `stackTraces` | `CallSite`[] |
114
+
115
+ ##### Returns
116
+
117
+ `any`
118
+
119
+ #### Inherited from
120
+
121
+ Error.prepareStackTrace
122
+
123
+ #### Defined in
124
+
125
+ node_modules/.pnpm/@types+node@20.11.0/node_modules/@types/node/globals.d.ts:28
126
+
127
+ ---
128
+
129
+ ### stackTraceLimit
130
+
131
+ ▪ `Static` **stackTraceLimit**: `number`
132
+
133
+ #### Inherited from
134
+
135
+ Error.stackTraceLimit
136
+
137
+ #### Defined in
138
+
139
+ node_modules/.pnpm/@types+node@20.11.0/node_modules/@types/node/globals.d.ts:30
140
+
141
+ ## Methods
142
+
143
+ ### captureStackTrace
144
+
145
+ ▸ `Static` **captureStackTrace**(`targetObject`, `constructorOpt?`): `void`
146
+
147
+ Create .stack property on a target object
148
+
149
+ #### Parameters
150
+
151
+ | Name | Type |
152
+ | :---------------- | :------------------------------------------------------------------------------------------------------ |
153
+ | `targetObject` | `object` |
154
+ | `constructorOpt?` | [`Function`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) |
155
+
156
+ #### Returns
157
+
158
+ `void`
159
+
160
+ #### Inherited from
161
+
162
+ Error.captureStackTrace
163
+
164
+ #### Defined in
165
+
166
+ node_modules/.pnpm/@types+node@20.11.0/node_modules/@types/node/globals.d.ts:21
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "require": "./dist/index.js"
18
18
  }
19
19
  },
20
- "version": "3.1.0",
20
+ "version": "3.2.0",
21
21
  "repository": {
22
22
  "directory": "packages/oidc",
23
23
  "type": "git",