@zapier/zapier-sdk 0.50.0 → 0.52.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 (63) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +2 -1
  3. package/dist/api/auth.d.ts +1 -6
  4. package/dist/api/auth.d.ts.map +1 -1
  5. package/dist/api/auth.js +34 -27
  6. package/dist/api/client.d.ts.map +1 -1
  7. package/dist/api/client.js +87 -9
  8. package/dist/api/concurrency.d.ts +28 -0
  9. package/dist/api/concurrency.d.ts.map +1 -0
  10. package/dist/api/concurrency.js +90 -0
  11. package/dist/api/index.d.ts +1 -1
  12. package/dist/api/index.d.ts.map +1 -1
  13. package/dist/api/index.js +1 -1
  14. package/dist/api/schemas.d.ts +3 -3
  15. package/dist/api/types.d.ts +6 -0
  16. package/dist/api/types.d.ts.map +1 -1
  17. package/dist/auth.d.ts +13 -2
  18. package/dist/auth.d.ts.map +1 -1
  19. package/dist/auth.js +95 -11
  20. package/dist/constants.d.ts +16 -0
  21. package/dist/constants.d.ts.map +1 -1
  22. package/dist/constants.js +29 -0
  23. package/dist/experimental.cjs +357 -34
  24. package/dist/experimental.d.mts +28 -28
  25. package/dist/experimental.d.ts +26 -26
  26. package/dist/experimental.mjs +353 -35
  27. package/dist/{index-BQ2ii0Bs.d.mts → index-DcdtPei-.d.mts} +132 -2
  28. package/dist/{index-BQ2ii0Bs.d.ts → index-DcdtPei-.d.ts} +132 -2
  29. package/dist/index.cjs +357 -34
  30. package/dist/index.d.mts +1 -1
  31. package/dist/index.d.ts +2 -1
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +1 -0
  34. package/dist/index.mjs +353 -35
  35. package/dist/plugins/api/index.d.ts.map +1 -1
  36. package/dist/plugins/api/index.js +3 -2
  37. package/dist/plugins/apps/index.d.ts +2 -2
  38. package/dist/plugins/deprecated/inputFields.d.ts +18 -18
  39. package/dist/plugins/getAction/index.d.ts +6 -6
  40. package/dist/plugins/getAction/schemas.d.ts +4 -4
  41. package/dist/plugins/getActionInputFieldsSchema/index.d.ts +5 -5
  42. package/dist/plugins/getActionInputFieldsSchema/schemas.d.ts +4 -4
  43. package/dist/plugins/listActionInputFieldChoices/index.d.ts +5 -5
  44. package/dist/plugins/listActionInputFieldChoices/schemas.d.ts +4 -4
  45. package/dist/plugins/listActionInputFields/index.d.ts +5 -5
  46. package/dist/plugins/listActionInputFields/schemas.d.ts +4 -4
  47. package/dist/plugins/listActions/index.d.ts +3 -3
  48. package/dist/plugins/listActions/schemas.d.ts +4 -4
  49. package/dist/plugins/runAction/index.d.ts +5 -5
  50. package/dist/plugins/runAction/schemas.d.ts +4 -4
  51. package/dist/plugins/triggers/getTriggerInputFieldsSchema/index.d.ts +2 -2
  52. package/dist/plugins/triggers/listTriggerInputFieldChoices/index.d.ts +2 -2
  53. package/dist/plugins/triggers/listTriggerInputFields/index.d.ts +2 -2
  54. package/dist/schemas/Action.d.ts +1 -1
  55. package/dist/sdk.d.ts +52 -52
  56. package/dist/types/properties.d.ts +1 -1
  57. package/dist/types/sdk.d.ts +1 -0
  58. package/dist/types/sdk.d.ts.map +1 -1
  59. package/dist/types/sdk.js +25 -0
  60. package/dist/utils/telemetry.d.ts +11 -0
  61. package/dist/utils/telemetry.d.ts.map +1 -0
  62. package/dist/utils/telemetry.js +19 -0
  63. package/package.json +1 -1
package/dist/auth.js CHANGED
@@ -9,6 +9,8 @@
9
9
  * @zapier/zapier-sdk-cli package (imported via its `./login` subpath).
10
10
  */
11
11
  import { isClientCredentials, isPkceCredentials } from "./types/credentials";
12
+ import { ZapierAuthenticationError } from "./types/errors";
13
+ import { emitOnce } from "./utils/telemetry";
12
14
  import { resolveCredentials, getClientIdFromCredentials } from "./credentials";
13
15
  import { createMemoryCache } from "./cache";
14
16
  const DEFAULT_AUTH_BASE_URL = "https://zapier.com";
@@ -61,8 +63,10 @@ async function resolveCache(options) {
61
63
  if (cliLogin?.createCache) {
62
64
  try {
63
65
  const cache = cliLogin.createCache();
64
- cachedDefaultCache = cache;
65
- return cache;
66
+ if (cache) {
67
+ cachedDefaultCache = cache;
68
+ return cache;
69
+ }
66
70
  }
67
71
  catch {
68
72
  // Fall through to in-memory if the CLI provider can't be constructed.
@@ -77,6 +81,12 @@ function entryIsValid(entry) {
77
81
  return true;
78
82
  return entry.expiresAt > Date.now() + TOKEN_EXPIRATION_BUFFER_MS;
79
83
  }
84
+ async function readCachedToken(cacheKey, cache) {
85
+ const cached = await cache.get(cacheKey);
86
+ if (cached && entryIsValid(cached))
87
+ return cached.value;
88
+ return undefined;
89
+ }
80
90
  /**
81
91
  * Invalidate the cached token for a given client_credentials identity.
82
92
  * Called on 401 so the next request re-exchanges. Clears both the
@@ -227,6 +237,23 @@ export function isCliLoginAvailable() {
227
237
  return undefined;
228
238
  return cachedCliLogin !== false;
229
239
  }
240
+ function emitAuthResolved(onEvent, mechanism) {
241
+ if (onEvent) {
242
+ emitOnce(onEvent, {
243
+ type: "auth_resolved",
244
+ payload: { mechanism },
245
+ timestamp: Date.now(),
246
+ });
247
+ }
248
+ }
249
+ async function getActiveCredentialsFromCli(baseUrl) {
250
+ const cliLogin = await getCliLogin();
251
+ return cliLogin?.getActiveCredentials?.({ baseUrl });
252
+ }
253
+ async function getStoredClientCredentialsFromCli(baseUrl) {
254
+ const cliLogin = await getCliLogin();
255
+ return cliLogin?.getStoredClientCredentials?.({ baseUrl });
256
+ }
230
257
  /**
231
258
  * Attempts to get a token from the CLI login package.
232
259
  *
@@ -239,6 +266,47 @@ export async function getTokenFromCliLogin(options) {
239
266
  return undefined;
240
267
  return await cliLogin.getToken(options);
241
268
  }
269
+ async function tryStoredClientCredentialToken(options) {
270
+ const activeCredential = await getActiveCredentialsFromCli(options.baseUrl);
271
+ if (!activeCredential)
272
+ return undefined;
273
+ const resolvedBaseUrl = activeCredential.baseUrl || options.baseUrl || DEFAULT_AUTH_BASE_URL;
274
+ const mergedScopes = mergeScopes(activeCredential.scopes.join(" "), options.requiredScopes);
275
+ const cacheKey = buildCacheKey({
276
+ clientId: activeCredential.clientId,
277
+ scopes: mergedScopes,
278
+ baseUrl: resolvedBaseUrl,
279
+ });
280
+ const cache = await resolveCache(options);
281
+ const pending = pendingExchanges.get(cacheKey);
282
+ if (pending)
283
+ return pending;
284
+ const cached = await readCachedToken(cacheKey, cache);
285
+ if (cached !== undefined) {
286
+ if (options.debug)
287
+ console.log(`[auth] Using cached token (clientId: ${activeCredential.clientId})`);
288
+ emitAuthResolved(options.onEvent, "client_credentials");
289
+ return cached;
290
+ }
291
+ const storedCredential = await getStoredClientCredentialsFromCli(resolvedBaseUrl);
292
+ if (!storedCredential) {
293
+ // Active credential pointer exists but the keychain secret is missing.
294
+ // Falling back to JWT would silently downgrade a migrated user; surface
295
+ // the broken state so they re-run login to recreate the secret.
296
+ await invalidateCachedToken({
297
+ clientId: activeCredential.clientId,
298
+ scopes: activeCredential.scopes,
299
+ baseUrl: resolvedBaseUrl,
300
+ cache: options.cache,
301
+ });
302
+ throw new ZapierAuthenticationError(`Stored client credential is missing its secret (clientId: ${activeCredential.clientId}). Run \`zapier-sdk login\` to recreate it.`);
303
+ }
304
+ if (options.debug)
305
+ console.log(`[auth] Using stored client credential (clientId: ${storedCredential.clientId})`);
306
+ const token = await resolveAuthTokenFromCredentials(storedCredential, options);
307
+ emitAuthResolved(options.onEvent, "client_credentials");
308
+ return token;
309
+ }
242
310
  /**
243
311
  * Resolves an auth token from wherever it can be found.
244
312
  *
@@ -265,19 +333,28 @@ export async function resolveAuthToken(options = {}) {
265
333
  if (credentials !== undefined) {
266
334
  return resolveAuthTokenFromCredentials(credentials, options);
267
335
  }
268
- // No credentials from options or env, try CLI login for stored token
269
- return getTokenFromCliLogin({
336
+ const storedToken = await tryStoredClientCredentialToken(options);
337
+ if (storedToken !== undefined)
338
+ return storedToken;
339
+ if (options.debug) {
340
+ console.log("[auth] Using JWT (no stored client credential found)");
341
+ }
342
+ const jwtToken = await getTokenFromCliLogin({
270
343
  onEvent: options.onEvent,
271
344
  fetch: options.fetch,
272
345
  debug: options.debug,
273
346
  });
347
+ if (jwtToken !== undefined) {
348
+ emitAuthResolved(options.onEvent, "jwt");
349
+ }
350
+ return jwtToken;
274
351
  }
275
352
  /**
276
353
  * Resolve an auth token from resolved credentials.
277
354
  */
278
355
  async function resolveAuthTokenFromCredentials(credentials, options) {
279
- // String credentials are used directly as tokens
280
356
  if (typeof credentials === "string") {
357
+ emitAuthResolved(options.onEvent, "token");
281
358
  return credentials;
282
359
  }
283
360
  // Client credentials: exchange + cache through a pluggable cache
@@ -299,9 +376,12 @@ async function resolveAuthTokenFromCredentials(credentials, options) {
299
376
  });
300
377
  const cache = await resolveCache(options);
301
378
  // Fast-path read
302
- const cached = await cache.get(cacheKey);
303
- if (cached && entryIsValid(cached)) {
304
- return cached.value;
379
+ const cached = await readCachedToken(cacheKey, cache);
380
+ if (cached !== undefined) {
381
+ if (options.debug) {
382
+ console.log(`[auth] Using cached token (clientId: ${clientId})`);
383
+ }
384
+ return cached;
305
385
  }
306
386
  // In-process dedup
307
387
  const pending = pendingExchanges.get(cacheKey);
@@ -312,9 +392,13 @@ async function resolveAuthTokenFromCredentials(credentials, options) {
312
392
  // cache under the lock and uses the first's token instead of firing
313
393
  // another exchange.
314
394
  const runLocked = async () => {
315
- const recheck = await cache.get(cacheKey);
316
- if (recheck && entryIsValid(recheck))
317
- return recheck.value;
395
+ const recheck = await readCachedToken(cacheKey, cache);
396
+ if (recheck !== undefined) {
397
+ if (options.debug) {
398
+ console.log(`[auth] Using cached token (clientId: ${clientId}, locked recheck)`);
399
+ }
400
+ return recheck;
401
+ }
318
402
  const { accessToken, expiresIn } = await exchangeClientCredentials({
319
403
  clientId: credentials.clientId,
320
404
  clientSecret: credentials.clientSecret,
@@ -30,6 +30,22 @@ export declare const DEFAULT_ACTION_TIMEOUT_MS = 180000;
30
30
  */
31
31
  export declare const ZAPIER_MAX_NETWORK_RETRIES: number;
32
32
  export declare const ZAPIER_MAX_NETWORK_RETRY_DELAY_MS: number;
33
+ /**
34
+ * Upper bound on the concurrency cap. Anything beyond this is almost
35
+ * certainly a configuration mistake and would also bypass IEEE 754 safe
36
+ * integer range for inputs like "9".repeat(309), which would silently
37
+ * become Infinity and disable throttling.
38
+ */
39
+ export declare const MAX_CONCURRENCY_LIMIT = 10000;
40
+ export declare function parseConcurrencyEnvVar(name: string): number | undefined;
41
+ /**
42
+ * Default cap on concurrent in-flight HTTP requests per SDK instance.
43
+ * Beyond this, requests queue (FIFO) until a slot frees up. Sized for
44
+ * production workloads that fan out hundreds of action runs in parallel;
45
+ * lower it when running against a smaller backend or to be more
46
+ * conservative. Pass `Infinity` to disable.
47
+ */
48
+ export declare const ZAPIER_MAX_CONCURRENT_REQUESTS: number;
33
49
  /**
34
50
  * Approval flow behavior from environment variable.
35
51
  * - "disabled": (default when env var is unset) Throw a ZapierApprovalError on
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,eAAO,MAAM,eAAe,QACsC,CAAC;AAEnE;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAExD;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,QAAQ,CAAC;AAEpC;;GAEG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC;;GAEG;AACH,eAAO,MAAM,yBAAyB,SAAU,CAAC;AAejD;;GAEG;AACH,eAAO,MAAM,0BAA0B,QACY,CAAC;AACpD,eAAO,MAAM,iCAAiC,QACiB,CAAC;AAEhE;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,IACjC,UAAU,GACV,MAAM,GACN,OAAO,GACP,SAAS,CAKZ;AAED;;GAEG;AACH,eAAO,MAAM,2BAA2B,QAAiB,CAAC;AAE1D;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,IAAI,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,eAAO,MAAM,eAAe,QACsC,CAAC;AAEnE;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAExD;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,QAAQ,CAAC;AAEpC;;GAEG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC;;GAEG;AACH,eAAO,MAAM,yBAAyB,SAAU,CAAC;AAejD;;GAEG;AACH,eAAO,MAAM,0BAA0B,QACY,CAAC;AACpD,eAAO,MAAM,iCAAiC,QACiB,CAAC;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAE5C,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAYvE;AAED;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B,QACsB,CAAC;AAElE;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,IACjC,UAAU,GACV,MAAM,GACN,OAAO,GACP,SAAS,CAKZ;AAED;;GAEG;AACH,eAAO,MAAM,2BAA2B,QAAiB,CAAC;AAE1D;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,IAAI,CAAC"}
package/dist/constants.js CHANGED
@@ -43,6 +43,35 @@ function parseIntEnvVar(name) {
43
43
  */
44
44
  export const ZAPIER_MAX_NETWORK_RETRIES = parseIntEnvVar("ZAPIER_MAX_NETWORK_RETRIES") ?? 3;
45
45
  export const ZAPIER_MAX_NETWORK_RETRY_DELAY_MS = parseIntEnvVar("ZAPIER_MAX_NETWORK_RETRY_DELAY_MS") ?? 60000;
46
+ /**
47
+ * Upper bound on the concurrency cap. Anything beyond this is almost
48
+ * certainly a configuration mistake and would also bypass IEEE 754 safe
49
+ * integer range for inputs like "9".repeat(309), which would silently
50
+ * become Infinity and disable throttling.
51
+ */
52
+ export const MAX_CONCURRENCY_LIMIT = 10000;
53
+ export function parseConcurrencyEnvVar(name) {
54
+ const value = globalThis.process?.env?.[name];
55
+ if (!value)
56
+ return undefined;
57
+ if (value === "Infinity")
58
+ return Infinity;
59
+ if (/^[1-9]\d*$/.test(value)) {
60
+ const parsed = parseInt(value, 10);
61
+ if (parsed <= MAX_CONCURRENCY_LIMIT)
62
+ return parsed;
63
+ }
64
+ console.warn(`[zapier-sdk] Invalid value for ${name}: "${value}" (expected positive integer 1-${MAX_CONCURRENCY_LIMIT} or "Infinity")`);
65
+ return undefined;
66
+ }
67
+ /**
68
+ * Default cap on concurrent in-flight HTTP requests per SDK instance.
69
+ * Beyond this, requests queue (FIFO) until a slot frees up. Sized for
70
+ * production workloads that fan out hundreds of action runs in parallel;
71
+ * lower it when running against a smaller backend or to be more
72
+ * conservative. Pass `Infinity` to disable.
73
+ */
74
+ export const ZAPIER_MAX_CONCURRENT_REQUESTS = parseConcurrencyEnvVar("ZAPIER_MAX_CONCURRENT_REQUESTS") ?? 200;
46
75
  /**
47
76
  * Approval flow behavior from environment variable.
48
77
  * - "disabled": (default when env var is unset) Throw a ZapierApprovalError on