@zapier/zapier-sdk 0.18.3 → 1.0.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.
Files changed (112) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +1 -1
  3. package/dist/api/client.d.ts.map +1 -1
  4. package/dist/api/client.js +11 -24
  5. package/dist/api/client.test.js +82 -27
  6. package/dist/api/index.d.ts +3 -2
  7. package/dist/api/index.d.ts.map +1 -1
  8. package/dist/api/index.js +2 -3
  9. package/dist/api/schemas.d.ts +5 -114
  10. package/dist/api/schemas.d.ts.map +1 -1
  11. package/dist/api/schemas.js +0 -67
  12. package/dist/api/types.d.ts +10 -4
  13. package/dist/api/types.d.ts.map +1 -1
  14. package/dist/auth.d.ts +54 -26
  15. package/dist/auth.d.ts.map +1 -1
  16. package/dist/auth.js +211 -39
  17. package/dist/auth.test.js +338 -64
  18. package/dist/constants.d.ts +14 -0
  19. package/dist/constants.d.ts.map +1 -1
  20. package/dist/constants.js +14 -0
  21. package/dist/credentials.d.ts +57 -0
  22. package/dist/credentials.d.ts.map +1 -0
  23. package/dist/credentials.js +174 -0
  24. package/dist/index.cjs +644 -685
  25. package/dist/index.d.mts +265 -134
  26. package/dist/index.d.ts +3 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +5 -0
  29. package/dist/index.mjs +624 -684
  30. package/dist/plugins/api/index.d.ts +2 -0
  31. package/dist/plugins/api/index.d.ts.map +1 -1
  32. package/dist/plugins/api/index.js +8 -4
  33. package/dist/plugins/eventEmission/index.d.ts.map +1 -1
  34. package/dist/plugins/eventEmission/index.js +1 -3
  35. package/dist/plugins/eventEmission/index.test.js +14 -17
  36. package/dist/plugins/getAction/schemas.d.ts +1 -1
  37. package/dist/plugins/getInputFieldsSchema/schemas.d.ts +1 -1
  38. package/dist/plugins/listActions/index.test.js +1 -0
  39. package/dist/plugins/listActions/schemas.d.ts +1 -1
  40. package/dist/plugins/listApps/index.d.ts +2 -8
  41. package/dist/plugins/listApps/index.d.ts.map +1 -1
  42. package/dist/plugins/listApps/index.js +4 -6
  43. package/dist/plugins/listApps/index.test.js +62 -82
  44. package/dist/plugins/listApps/schemas.d.ts +35 -14
  45. package/dist/plugins/listApps/schemas.d.ts.map +1 -1
  46. package/dist/plugins/listApps/schemas.js +44 -14
  47. package/dist/plugins/listAuthentications/index.test.js +16 -0
  48. package/dist/plugins/listInputFieldChoices/schemas.d.ts +1 -1
  49. package/dist/plugins/listInputFields/schemas.d.ts +1 -1
  50. package/dist/plugins/runAction/schemas.d.ts +1 -1
  51. package/dist/schemas/Action.d.ts +1 -1
  52. package/dist/schemas/App.d.ts +28 -28
  53. package/dist/schemas/App.d.ts.map +1 -1
  54. package/dist/schemas/App.js +3 -8
  55. package/dist/sdk.d.ts +2 -1
  56. package/dist/sdk.d.ts.map +1 -1
  57. package/dist/sdk.test.js +17 -13
  58. package/dist/types/credentials.d.ts +65 -0
  59. package/dist/types/credentials.d.ts.map +1 -0
  60. package/dist/types/credentials.js +42 -0
  61. package/dist/types/properties.d.ts +1 -1
  62. package/dist/types/sdk.d.ts +12 -3
  63. package/dist/types/sdk.d.ts.map +1 -1
  64. package/dist/utils/logging.d.ts +13 -0
  65. package/dist/utils/logging.d.ts.map +1 -0
  66. package/dist/utils/logging.js +20 -0
  67. package/package.json +2 -2
  68. package/dist/api/client.integration.test.d.ts +0 -5
  69. package/dist/api/client.integration.test.d.ts.map +0 -1
  70. package/dist/api/client.integration.test.js +0 -318
  71. package/dist/api/client.methods.test.d.ts +0 -2
  72. package/dist/api/client.methods.test.d.ts.map +0 -1
  73. package/dist/api/client.methods.test.js +0 -158
  74. package/dist/api/router.d.ts +0 -16
  75. package/dist/api/router.d.ts.map +0 -1
  76. package/dist/api/router.js +0 -31
  77. package/dist/api/router.test.d.ts +0 -2
  78. package/dist/api/router.test.d.ts.map +0 -1
  79. package/dist/api/router.test.js +0 -103
  80. package/dist/temporary-internal-core/handlers/listApps.d.ts +0 -67
  81. package/dist/temporary-internal-core/handlers/listApps.d.ts.map +0 -1
  82. package/dist/temporary-internal-core/handlers/listApps.js +0 -134
  83. package/dist/temporary-internal-core/handlers/listApps.test.d.ts +0 -2
  84. package/dist/temporary-internal-core/handlers/listApps.test.d.ts.map +0 -1
  85. package/dist/temporary-internal-core/handlers/listApps.test.js +0 -367
  86. package/dist/temporary-internal-core/index.d.ts +0 -18
  87. package/dist/temporary-internal-core/index.d.ts.map +0 -1
  88. package/dist/temporary-internal-core/index.js +0 -18
  89. package/dist/temporary-internal-core/schemas/apps/index.d.ts +0 -175
  90. package/dist/temporary-internal-core/schemas/apps/index.d.ts.map +0 -1
  91. package/dist/temporary-internal-core/schemas/apps/index.js +0 -97
  92. package/dist/temporary-internal-core/schemas/errors/index.d.ts +0 -139
  93. package/dist/temporary-internal-core/schemas/errors/index.d.ts.map +0 -1
  94. package/dist/temporary-internal-core/schemas/errors/index.js +0 -129
  95. package/dist/temporary-internal-core/schemas/implementations/index.d.ts +0 -127
  96. package/dist/temporary-internal-core/schemas/implementations/index.d.ts.map +0 -1
  97. package/dist/temporary-internal-core/schemas/implementations/index.js +0 -79
  98. package/dist/temporary-internal-core/types/handler.d.ts +0 -51
  99. package/dist/temporary-internal-core/types/handler.d.ts.map +0 -1
  100. package/dist/temporary-internal-core/types/handler.js +0 -8
  101. package/dist/temporary-internal-core/types/index.d.ts +0 -5
  102. package/dist/temporary-internal-core/types/index.d.ts.map +0 -1
  103. package/dist/temporary-internal-core/types/index.js +0 -4
  104. package/dist/temporary-internal-core/utils/app-locators.d.ts +0 -34
  105. package/dist/temporary-internal-core/utils/app-locators.d.ts.map +0 -1
  106. package/dist/temporary-internal-core/utils/app-locators.js +0 -39
  107. package/dist/temporary-internal-core/utils/string-utils.d.ts +0 -28
  108. package/dist/temporary-internal-core/utils/string-utils.d.ts.map +0 -1
  109. package/dist/temporary-internal-core/utils/string-utils.js +0 -52
  110. package/dist/temporary-internal-core/utils/transformations.d.ts +0 -18
  111. package/dist/temporary-internal-core/utils/transformations.d.ts.map +0 -1
  112. package/dist/temporary-internal-core/utils/transformations.js +0 -36
package/dist/auth.d.ts CHANGED
@@ -2,51 +2,79 @@
2
2
  * SDK Authentication Utilities
3
3
  *
4
4
  * This module provides SDK-level authentication utilities focused
5
- * solely on token acquisition. CLI-specific functionality like login/logout
6
- * is handled by the @zapier/zapier-sdk-cli-login package.
5
+ * on token acquisition. It uses the credentials system for resolution
6
+ * and handles different credential types appropriately.
7
+ *
8
+ * CLI-specific functionality like login/logout is handled by the
9
+ * @zapier/zapier-sdk-cli-login package.
7
10
  */
8
11
  import type { EventCallback } from "./types/events";
12
+ import type { Credentials } from "./types/credentials";
9
13
  export type { SdkEvent, AuthEvent, ApiEvent, LoadingEvent, EventCallback, } from "./types/events";
10
- export interface AuthOptions {
14
+ export type { Credentials, ResolvedCredentials, CredentialsObject, ClientCredentialsObject, PkceCredentialsObject, } from "./types/credentials";
15
+ export { isClientCredentials, isPkceCredentials, isCredentialsObject, isCredentialsFunction, } from "./types/credentials";
16
+ /**
17
+ * Options for resolving auth tokens.
18
+ */
19
+ export interface ResolveAuthTokenOptions {
20
+ credentials?: Credentials;
21
+ /** @deprecated Use `credentials` instead */
22
+ token?: string;
11
23
  onEvent?: EventCallback;
12
24
  fetch?: typeof globalThis.fetch;
13
25
  baseUrl?: string;
14
- authBaseUrl?: string;
15
- authClientId?: string;
16
- }
17
- export interface ResolveAuthTokenOptions extends AuthOptions {
18
- token?: string;
19
- getToken?: () => Promise<string | undefined> | string | undefined;
20
26
  }
21
27
  /**
22
- * Gets the ZAPIER_TOKEN from environment variables.
23
- * Returns undefined if not set.
28
+ * Clear the token cache. Useful for testing or forcing re-authentication.
29
+ */
30
+ export declare function clearTokenCache(): void;
31
+ /**
32
+ * Invalidate a cached token. Called when we get a 401 response.
33
+ */
34
+ export declare function invalidateCachedToken(clientId: string): void;
35
+ /**
36
+ * Options for getTokenFromCliLogin.
24
37
  */
25
- export declare function getTokenFromEnv(): string | undefined;
38
+ interface CliLoginOptions {
39
+ onEvent?: EventCallback;
40
+ fetch?: typeof globalThis.fetch;
41
+ credentials?: {
42
+ type?: "pkce";
43
+ clientId: string;
44
+ baseUrl?: string;
45
+ scope?: string;
46
+ };
47
+ }
26
48
  /**
27
49
  * Attempts to get a token by optionally importing from CLI login package.
28
50
  * This provides a graceful fallback when the CLI login package is not available.
29
51
  *
30
52
  * Returns undefined if no valid token is found or CLI package is not available.
31
53
  */
32
- export declare function getTokenFromCliLogin(options?: AuthOptions): Promise<string | undefined>;
54
+ export declare function getTokenFromCliLogin(options: CliLoginOptions): Promise<string | undefined>;
33
55
  /**
34
- * Attempts to get a token with the following precedence:
35
- * 1. ZAPIER_TOKEN environment variable
36
- * 2. CLI login package (if available) with auto-refresh
56
+ * Resolves an auth token from wherever it can be found.
37
57
  *
38
- * Returns undefined if no valid token is found.
39
- */
40
- export declare function getTokenFromEnvOrConfig(options?: AuthOptions): Promise<string | undefined>;
41
- /**
42
- * Resolves an auth token from all possible sources with the following precedence:
43
- * 1. Explicitly provided token in options
44
- * 2. Token from getToken callback in options
45
- * 3. ZAPIER_TOKEN environment variable
46
- * 4. CLI login package (if available)
58
+ * Resolution order:
59
+ * 1. Explicit credentials option (or deprecated token option)
60
+ * 2. Environment variables
61
+ * 3. CLI login package (if available)
62
+ *
63
+ * For different credential types:
64
+ * - String: Used directly as the token
65
+ * - Client credentials: Exchanged for an access token (with caching)
66
+ * - PKCE: Delegates to CLI login (throws if not available)
47
67
  *
48
- * This is the canonical token resolution logic used throughout the SDK.
49
68
  * Returns undefined if no valid token is found.
50
69
  */
51
70
  export declare function resolveAuthToken(options?: ResolveAuthTokenOptions): Promise<string | undefined>;
71
+ /**
72
+ * Invalidate the cached token for the given credentials, if applicable.
73
+ * This is called when we receive a 401 response, indicating the token
74
+ * is no longer valid. Only affects client_credentials flow tokens.
75
+ */
76
+ export declare function invalidateCredentialsToken(options: {
77
+ credentials?: Credentials;
78
+ token?: string;
79
+ }): Promise<void>;
52
80
  //# sourceMappingURL=auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGpD,YAAY,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,aAAa,GACd,MAAM,gBAAgB,CAAC;AAGxB,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,uBAAwB,SAAQ,WAAW;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC;CACnE;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,GAAG,SAAS,CAEpD;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAS7B;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAS7B;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAgB7B"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAuB,MAAM,qBAAqB,CAAC;AAM5E,YAAY,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,aAAa,GACd,MAAM,gBAAgB,CAAC;AAGxB,YAAY,EACV,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAE7B;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAsBD;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAGtC;AAoCD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE5D;AAsFD;;GAEG;AACH,UAAU,eAAe;IACvB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,WAAW,CAAC,EAAE;QACZ,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAa7B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAiB7B;AAuED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAAC,OAAO,EAAE;IACxD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMhB"}
package/dist/auth.js CHANGED
@@ -2,15 +2,129 @@
2
2
  * SDK Authentication Utilities
3
3
  *
4
4
  * This module provides SDK-level authentication utilities focused
5
- * solely on token acquisition. CLI-specific functionality like login/logout
6
- * is handled by the @zapier/zapier-sdk-cli-login package.
5
+ * on token acquisition. It uses the credentials system for resolution
6
+ * and handles different credential types appropriately.
7
+ *
8
+ * CLI-specific functionality like login/logout is handled by the
9
+ * @zapier/zapier-sdk-cli-login package.
10
+ */
11
+ import { isClientCredentials, isPkceCredentials } from "./types/credentials";
12
+ import { resolveCredentials, getClientIdFromCredentials } from "./credentials";
13
+ import { ZAPIER_BASE_URL } from "./constants";
14
+ export { isClientCredentials, isPkceCredentials, isCredentialsObject, isCredentialsFunction, } from "./types/credentials";
15
+ /**
16
+ * In-memory cache for tokens obtained via client credentials flow.
17
+ * Keyed by clientId.
18
+ */
19
+ const tokenCache = new Map();
20
+ /**
21
+ * In-flight token exchange promises to prevent duplicate exchanges.
22
+ * When an exchange is in progress, subsequent calls await the same promise.
23
+ */
24
+ const pendingExchanges = new Map();
25
+ /**
26
+ * Clear the token cache. Useful for testing or forcing re-authentication.
27
+ */
28
+ export function clearTokenCache() {
29
+ tokenCache.clear();
30
+ pendingExchanges.clear();
31
+ }
32
+ const TOKEN_EXPIRATION_BUFFER = 5 * 60 * 1000; // 5 minutes
33
+ /**
34
+ * Get a cached token if it exists and is not expired.
35
+ * Returns undefined if no valid cached token exists.
7
36
  */
37
+ function getCachedToken(clientId) {
38
+ const cached = tokenCache.get(clientId);
39
+ if (!cached)
40
+ return undefined;
41
+ // Check if token is still valid (with expiration buffer)
42
+ if (cached.expiresAt > Date.now() + TOKEN_EXPIRATION_BUFFER) {
43
+ return cached.accessToken;
44
+ }
45
+ // Token expired, remove from cache
46
+ tokenCache.delete(clientId);
47
+ return undefined;
48
+ }
49
+ /**
50
+ * Cache a token obtained from client credentials flow.
51
+ */
52
+ function cacheToken(clientId, accessToken, expiresIn) {
53
+ tokenCache.set(clientId, {
54
+ accessToken,
55
+ expiresAt: Date.now() + expiresIn * 1000,
56
+ });
57
+ }
58
+ /**
59
+ * Invalidate a cached token. Called when we get a 401 response.
60
+ */
61
+ export function invalidateCachedToken(clientId) {
62
+ tokenCache.delete(clientId);
63
+ }
8
64
  /**
9
- * Gets the ZAPIER_TOKEN from environment variables.
10
- * Returns undefined if not set.
65
+ * Get the token endpoint URL for client credentials exchange.
11
66
  */
12
- export function getTokenFromEnv() {
13
- return process.env.ZAPIER_TOKEN;
67
+ function getTokenEndpointUrl(baseUrl) {
68
+ const base = baseUrl || ZAPIER_BASE_URL;
69
+ return `${base}/oauth/token/`;
70
+ }
71
+ /**
72
+ * Exchange client credentials for an access token.
73
+ */
74
+ async function exchangeClientCredentials(options) {
75
+ const { clientId, clientSecret, baseUrl, scope, onEvent } = options;
76
+ const fetchFn = options.fetch || globalThis.fetch;
77
+ const tokenUrl = getTokenEndpointUrl(baseUrl);
78
+ onEvent?.({
79
+ type: "auth_exchanging",
80
+ payload: {
81
+ message: "Exchanging client credentials for token...",
82
+ operation: "client_credentials",
83
+ },
84
+ timestamp: Date.now(),
85
+ });
86
+ const response = await fetchFn(tokenUrl, {
87
+ method: "POST",
88
+ headers: {
89
+ "Content-Type": "application/x-www-form-urlencoded",
90
+ },
91
+ body: new URLSearchParams({
92
+ grant_type: "client_credentials",
93
+ client_id: clientId,
94
+ client_secret: clientSecret,
95
+ scope: scope || "external",
96
+ audience: "zapier.com",
97
+ }),
98
+ });
99
+ if (!response.ok) {
100
+ const errorText = await response.text();
101
+ onEvent?.({
102
+ type: "auth_error",
103
+ payload: {
104
+ message: `Client credentials exchange failed: ${response.status}`,
105
+ error: errorText,
106
+ operation: "client_credentials",
107
+ },
108
+ timestamp: Date.now(),
109
+ });
110
+ throw new Error(`Client credentials exchange failed: ${response.status} ${response.statusText}`);
111
+ }
112
+ const data = await response.json();
113
+ if (!data.access_token) {
114
+ throw new Error("Client credentials response missing access_token");
115
+ }
116
+ // Cache the token
117
+ const expiresIn = data.expires_in || 3600; // Default to 1 hour
118
+ cacheToken(clientId, data.access_token, expiresIn);
119
+ onEvent?.({
120
+ type: "auth_success",
121
+ payload: {
122
+ message: "Client credentials exchange successful",
123
+ operation: "client_credentials",
124
+ },
125
+ timestamp: Date.now(),
126
+ });
127
+ return data.access_token;
14
128
  }
15
129
  /**
16
130
  * Attempts to get a token by optionally importing from CLI login package.
@@ -18,11 +132,13 @@ export function getTokenFromEnv() {
18
132
  *
19
133
  * Returns undefined if no valid token is found or CLI package is not available.
20
134
  */
21
- export async function getTokenFromCliLogin(options = {}) {
135
+ export async function getTokenFromCliLogin(options) {
22
136
  try {
23
- // Dynamically import the CLI login package if available
24
- const { getToken } = await import("@zapier/zapier-sdk-cli-login");
25
- return await getToken(options);
137
+ // Dynamically import the CLI login package if available.
138
+ // This is intentionally an async import because this module is a dependency
139
+ // of the CLI and is only available when the CLI is installed!
140
+ const cliLogin = await import("@zapier/zapier-sdk-cli-login");
141
+ return await cliLogin.getToken(options);
26
142
  }
27
143
  catch {
28
144
  // CLI login package is not available, return undefined
@@ -30,43 +146,99 @@ export async function getTokenFromCliLogin(options = {}) {
30
146
  }
31
147
  }
32
148
  /**
33
- * Attempts to get a token with the following precedence:
34
- * 1. ZAPIER_TOKEN environment variable
35
- * 2. CLI login package (if available) with auto-refresh
149
+ * Resolves an auth token from wherever it can be found.
150
+ *
151
+ * Resolution order:
152
+ * 1. Explicit credentials option (or deprecated token option)
153
+ * 2. Environment variables
154
+ * 3. CLI login package (if available)
155
+ *
156
+ * For different credential types:
157
+ * - String: Used directly as the token
158
+ * - Client credentials: Exchanged for an access token (with caching)
159
+ * - PKCE: Delegates to CLI login (throws if not available)
36
160
  *
37
161
  * Returns undefined if no valid token is found.
38
162
  */
39
- export async function getTokenFromEnvOrConfig(options = {}) {
40
- // First priority: environment variable
41
- const envToken = getTokenFromEnv();
42
- if (envToken) {
43
- return envToken;
163
+ export async function resolveAuthToken(options = {}) {
164
+ // Resolve credentials from options and env vars
165
+ const credentials = await resolveCredentials({
166
+ credentials: options.credentials,
167
+ token: options.token,
168
+ });
169
+ // If we got credentials, process them based on type
170
+ if (credentials !== undefined) {
171
+ return resolveAuthTokenFromCredentials(credentials, options);
44
172
  }
45
- // Second priority: CLI login package (if available)
46
- return getTokenFromCliLogin(options);
173
+ // No credentials from options or env, try CLI login for stored token
174
+ return getTokenFromCliLogin({
175
+ onEvent: options.onEvent,
176
+ fetch: options.fetch,
177
+ });
47
178
  }
48
179
  /**
49
- * Resolves an auth token from all possible sources with the following precedence:
50
- * 1. Explicitly provided token in options
51
- * 2. Token from getToken callback in options
52
- * 3. ZAPIER_TOKEN environment variable
53
- * 4. CLI login package (if available)
54
- *
55
- * This is the canonical token resolution logic used throughout the SDK.
56
- * Returns undefined if no valid token is found.
180
+ * Resolve an auth token from resolved credentials.
57
181
  */
58
- export async function resolveAuthToken(options = {}) {
59
- // First priority: explicitly provided token
60
- if (options.token) {
61
- return options.token;
182
+ async function resolveAuthTokenFromCredentials(credentials, options) {
183
+ // String credentials are used directly as tokens
184
+ if (typeof credentials === "string") {
185
+ return credentials;
186
+ }
187
+ // Client credentials: exchange for token
188
+ if (isClientCredentials(credentials)) {
189
+ const { clientId } = credentials;
190
+ // Check cache first
191
+ const cached = getCachedToken(clientId);
192
+ if (cached) {
193
+ return cached;
194
+ }
195
+ // Check if there's already an exchange in progress for this clientId
196
+ const pending = pendingExchanges.get(clientId);
197
+ if (pending) {
198
+ return pending;
199
+ }
200
+ // Start new exchange and cache the promise to prevent duplicate exchanges
201
+ const exchangePromise = exchangeClientCredentials({
202
+ clientId: credentials.clientId,
203
+ clientSecret: credentials.clientSecret,
204
+ baseUrl: credentials.baseUrl || options.baseUrl,
205
+ scope: credentials.scope,
206
+ fetch: options.fetch,
207
+ onEvent: options.onEvent,
208
+ }).finally(() => {
209
+ // Remove from pending when done (success or failure)
210
+ pendingExchanges.delete(clientId);
211
+ });
212
+ pendingExchanges.set(clientId, exchangePromise);
213
+ return exchangePromise;
62
214
  }
63
- // Second priority: getToken callback
64
- if (options.getToken) {
65
- const token = await options.getToken();
66
- if (token) {
67
- return token;
215
+ // PKCE credentials: delegate to CLI login
216
+ if (isPkceCredentials(credentials)) {
217
+ // Try to get stored token from CLI login
218
+ const storedToken = await getTokenFromCliLogin({
219
+ onEvent: options.onEvent,
220
+ fetch: options.fetch,
221
+ credentials,
222
+ });
223
+ if (storedToken) {
224
+ return storedToken;
68
225
  }
226
+ // No stored token - user needs to run login
227
+ throw new Error("PKCE credentials require interactive login. " +
228
+ "Please run the 'login' command with the CLI first, or use client_credentials flow.");
229
+ }
230
+ // Should not reach here, but handle gracefully
231
+ throw new Error("Unknown credentials type");
232
+ }
233
+ /**
234
+ * Invalidate the cached token for the given credentials, if applicable.
235
+ * This is called when we receive a 401 response, indicating the token
236
+ * is no longer valid. Only affects client_credentials flow tokens.
237
+ */
238
+ export async function invalidateCredentialsToken(options) {
239
+ const resolved = await resolveCredentials(options);
240
+ const clientId = getClientIdFromCredentials(resolved);
241
+ if (clientId) {
242
+ invalidateCachedToken(clientId);
69
243
  }
70
- // Third and fourth priorities: environment variable or CLI login
71
- return getTokenFromEnvOrConfig(options);
72
244
  }