@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/index.js CHANGED
@@ -73,4 +73,5 @@ export { BaseSdkOptionsSchema } from "./types/sdk";
73
73
  export { definePlugin, createPluginMethod, createPaginatedPluginMethod, composePlugins, } from "./utils/plugin-utils";
74
74
  // Export registry plugin for manual use
75
75
  export { registryPlugin } from "./plugins/registry";
76
+ export { createZapierApi, getOrCreateApiClient } from "./api";
76
77
  export { generateEventId, getCurrentTimestamp, getReleaseId, getOsInfo, getPlatformVersions, isCi, getCiPlatform, getMemoryUsage, getCpuTime, buildApplicationLifecycleEvent, buildErrorEventWithContext, buildErrorEvent, createBaseEvent, buildMethodCalledEvent, } from "./plugins/eventEmission";
package/dist/index.mjs CHANGED
@@ -61,6 +61,21 @@ function parseIntEnvVar(name) {
61
61
  }
62
62
  var ZAPIER_MAX_NETWORK_RETRIES = parseIntEnvVar("ZAPIER_MAX_NETWORK_RETRIES") ?? 3;
63
63
  var ZAPIER_MAX_NETWORK_RETRY_DELAY_MS = parseIntEnvVar("ZAPIER_MAX_NETWORK_RETRY_DELAY_MS") ?? 6e4;
64
+ var MAX_CONCURRENCY_LIMIT = 1e4;
65
+ function parseConcurrencyEnvVar(name) {
66
+ const value = globalThis.process?.env?.[name];
67
+ if (!value) return void 0;
68
+ if (value === "Infinity") return Infinity;
69
+ if (/^[1-9]\d*$/.test(value)) {
70
+ const parsed = parseInt(value, 10);
71
+ if (parsed <= MAX_CONCURRENCY_LIMIT) return parsed;
72
+ }
73
+ console.warn(
74
+ `[zapier-sdk] Invalid value for ${name}: "${value}" (expected positive integer 1-${MAX_CONCURRENCY_LIMIT} or "Infinity")`
75
+ );
76
+ return void 0;
77
+ }
78
+ var ZAPIER_MAX_CONCURRENT_REQUESTS = parseConcurrencyEnvVar("ZAPIER_MAX_CONCURRENT_REQUESTS") ?? 200;
64
79
  function getZapierApprovalMode() {
65
80
  const value = globalThis.process?.env?.ZAPIER_APPROVAL_MODE;
66
81
  if (value === "disabled" || value === "poll" || value === "throw")
@@ -5233,33 +5248,40 @@ function getAuthorizationHeader(token) {
5233
5248
  }
5234
5249
  return `Bearer ${token}`;
5235
5250
  }
5236
- function extractUserIdsFromJwt(token) {
5251
+ function readJwtPayload(token) {
5237
5252
  const parts = parseJwt(token);
5238
- if (!parts) {
5239
- return { customuser_id: null, account_id: null };
5240
- }
5253
+ if (!parts) return null;
5254
+ let payload;
5241
5255
  try {
5242
- const payload = JSON.parse(
5243
- Buffer.from(parts[1], "base64url").toString("utf-8")
5244
- );
5245
- let actualPayload = payload;
5246
- if (payload.sub_type === "service" && payload.njwt) {
5247
- const nestedParts = payload.njwt.split(".");
5248
- if (nestedParts.length === 3) {
5249
- actualPayload = JSON.parse(
5256
+ payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf-8"));
5257
+ } catch {
5258
+ return null;
5259
+ }
5260
+ if (payload["sub_type"] === "service" && typeof payload["njwt"] === "string") {
5261
+ const nestedParts = parseJwt(payload["njwt"]);
5262
+ if (nestedParts) {
5263
+ try {
5264
+ return JSON.parse(
5250
5265
  Buffer.from(nestedParts[1], "base64url").toString("utf-8")
5251
5266
  );
5267
+ } catch {
5252
5268
  }
5253
5269
  }
5254
- const accountId = actualPayload["zap:acc"] != null ? parseInt(String(actualPayload["zap:acc"]), 10) : null;
5255
- const customUserId = actualPayload.sub_type === "customuser" && actualPayload.sub != null ? parseInt(String(actualPayload.sub), 10) : null;
5256
- return {
5257
- customuser_id: customUserId !== null && !isNaN(customUserId) ? customUserId : null,
5258
- account_id: accountId !== null && !isNaN(accountId) ? accountId : null
5259
- };
5260
- } catch {
5270
+ }
5271
+ return payload;
5272
+ }
5273
+ function extractUserIdsFromJwt(token) {
5274
+ const payload = readJwtPayload(token);
5275
+ if (!payload) {
5261
5276
  return { customuser_id: null, account_id: null };
5262
5277
  }
5278
+ const accRaw = payload["zap:acc"];
5279
+ const accountId = accRaw != null ? parseInt(String(accRaw), 10) : null;
5280
+ const customUserId = payload["sub_type"] === "customuser" && payload["sub"] != null ? parseInt(String(payload["sub"]), 10) : null;
5281
+ return {
5282
+ customuser_id: customUserId !== null && !isNaN(customUserId) ? customUserId : null,
5283
+ account_id: accountId !== null && !isNaN(accountId) ? accountId : null
5284
+ };
5263
5285
  }
5264
5286
 
5265
5287
  // src/api/debug.ts
@@ -5567,6 +5589,83 @@ async function pollUntilComplete(options) {
5567
5589
  }
5568
5590
  }
5569
5591
  }
5592
+
5593
+ // src/api/concurrency.ts
5594
+ var NO_OP_RELEASE = () => {
5595
+ };
5596
+ var NO_OP_SEMAPHORE = {
5597
+ acquire: async () => NO_OP_RELEASE,
5598
+ tryAcquire: () => NO_OP_RELEASE
5599
+ };
5600
+ function createSemaphore(maxPermits) {
5601
+ if (maxPermits === Infinity) {
5602
+ return NO_OP_SEMAPHORE;
5603
+ }
5604
+ if (!Number.isInteger(maxPermits) || maxPermits <= 0) {
5605
+ throw new Error(
5606
+ `maxPermits must be a positive integer or Infinity, got: ${maxPermits}`
5607
+ );
5608
+ }
5609
+ let permits = maxPermits;
5610
+ const waiters = [];
5611
+ const release = () => {
5612
+ const next = waiters.shift();
5613
+ if (next) {
5614
+ next.grant();
5615
+ } else {
5616
+ permits++;
5617
+ }
5618
+ };
5619
+ const makeReleaseOnce = () => {
5620
+ let released = false;
5621
+ return () => {
5622
+ if (released) return;
5623
+ released = true;
5624
+ release();
5625
+ };
5626
+ };
5627
+ return {
5628
+ tryAcquire() {
5629
+ if (permits > 0) {
5630
+ permits--;
5631
+ return makeReleaseOnce();
5632
+ }
5633
+ return null;
5634
+ },
5635
+ async acquire(signal) {
5636
+ if (signal?.aborted) {
5637
+ throw signal.reason ?? new DOMException("Aborted", "AbortError");
5638
+ }
5639
+ if (permits > 0) {
5640
+ permits--;
5641
+ return makeReleaseOnce();
5642
+ }
5643
+ return new Promise((resolve2, reject) => {
5644
+ const onAbort = () => {
5645
+ const idx = waiters.indexOf(waiter);
5646
+ if (idx !== -1) {
5647
+ waiters.splice(idx, 1);
5648
+ waiter.cancel(
5649
+ signal?.reason ?? new DOMException("Aborted", "AbortError")
5650
+ );
5651
+ }
5652
+ };
5653
+ const waiter = {
5654
+ grant: () => {
5655
+ signal?.removeEventListener("abort", onAbort);
5656
+ resolve2(makeReleaseOnce());
5657
+ },
5658
+ cancel: (reason) => {
5659
+ signal?.removeEventListener("abort", onAbort);
5660
+ reject(reason);
5661
+ }
5662
+ };
5663
+ signal?.addEventListener("abort", onAbort);
5664
+ waiters.push(waiter);
5665
+ });
5666
+ }
5667
+ };
5668
+ }
5570
5669
  var ClientCredentialsObjectSchema = z.object({
5571
5670
  type: z.enum(["client_credentials"]).optional().meta({ internal: true }),
5572
5671
  clientId: z.string().describe("OAuth client ID for authentication.").meta({ valueHint: "id" }),
@@ -5608,6 +5707,19 @@ function isCredentialsFunction(credentials) {
5608
5707
  return typeof credentials === "function";
5609
5708
  }
5610
5709
 
5710
+ // src/utils/telemetry.ts
5711
+ var emittedOnce = /* @__PURE__ */ new WeakMap();
5712
+ function emitOnce(onEvent, event) {
5713
+ if (!emittedOnce.has(onEvent)) {
5714
+ emittedOnce.set(onEvent, /* @__PURE__ */ new Set());
5715
+ }
5716
+ const fired = emittedOnce.get(onEvent);
5717
+ if (!fired.has(event.type)) {
5718
+ fired.add(event.type);
5719
+ onEvent(event);
5720
+ }
5721
+ }
5722
+
5611
5723
  // src/utils/url-utils.ts
5612
5724
  function getZapierBaseUrl(baseUrl) {
5613
5725
  if (!baseUrl) {
@@ -5830,8 +5942,10 @@ async function resolveCache(options) {
5830
5942
  if (cliLogin?.createCache) {
5831
5943
  try {
5832
5944
  const cache = cliLogin.createCache();
5833
- cachedDefaultCache = cache;
5834
- return cache;
5945
+ if (cache) {
5946
+ cachedDefaultCache = cache;
5947
+ return cache;
5948
+ }
5835
5949
  } catch {
5836
5950
  }
5837
5951
  }
@@ -5843,6 +5957,11 @@ function entryIsValid(entry) {
5843
5957
  if (entry.expiresAt === void 0) return true;
5844
5958
  return entry.expiresAt > Date.now() + TOKEN_EXPIRATION_BUFFER_MS;
5845
5959
  }
5960
+ async function readCachedToken(cacheKey, cache) {
5961
+ const cached = await cache.get(cacheKey);
5962
+ if (cached && entryIsValid(cached)) return cached.value;
5963
+ return void 0;
5964
+ }
5846
5965
  async function invalidateCachedToken(options) {
5847
5966
  const cacheKey = buildCacheKey(options);
5848
5967
  pendingExchanges.delete(cacheKey);
@@ -5956,11 +6075,76 @@ function isCliLoginAvailable() {
5956
6075
  if (cachedCliLogin === void 0) return void 0;
5957
6076
  return cachedCliLogin !== false;
5958
6077
  }
6078
+ function emitAuthResolved(onEvent, mechanism) {
6079
+ if (onEvent) {
6080
+ emitOnce(onEvent, {
6081
+ type: "auth_resolved",
6082
+ payload: { mechanism },
6083
+ timestamp: Date.now()
6084
+ });
6085
+ }
6086
+ }
6087
+ async function getActiveCredentialsFromCli(baseUrl) {
6088
+ const cliLogin = await getCliLogin();
6089
+ return cliLogin?.getActiveCredentials?.({ baseUrl });
6090
+ }
6091
+ async function getStoredClientCredentialsFromCli(baseUrl) {
6092
+ const cliLogin = await getCliLogin();
6093
+ return cliLogin?.getStoredClientCredentials?.({ baseUrl });
6094
+ }
5959
6095
  async function getTokenFromCliLogin(options) {
5960
6096
  const cliLogin = await getCliLogin();
5961
6097
  if (!cliLogin) return void 0;
5962
6098
  return await cliLogin.getToken(options);
5963
6099
  }
6100
+ async function tryStoredClientCredentialToken(options) {
6101
+ const activeCredential = await getActiveCredentialsFromCli(options.baseUrl);
6102
+ if (!activeCredential) return void 0;
6103
+ const resolvedBaseUrl = activeCredential.baseUrl || options.baseUrl || DEFAULT_AUTH_BASE_URL;
6104
+ const mergedScopes = mergeScopes(
6105
+ activeCredential.scopes.join(" "),
6106
+ options.requiredScopes
6107
+ );
6108
+ const cacheKey = buildCacheKey({
6109
+ clientId: activeCredential.clientId,
6110
+ scopes: mergedScopes,
6111
+ baseUrl: resolvedBaseUrl
6112
+ });
6113
+ const cache = await resolveCache(options);
6114
+ const pending = pendingExchanges.get(cacheKey);
6115
+ if (pending) return pending;
6116
+ const cached = await readCachedToken(cacheKey, cache);
6117
+ if (cached !== void 0) {
6118
+ if (options.debug)
6119
+ console.log(
6120
+ `[auth] Using cached token (clientId: ${activeCredential.clientId})`
6121
+ );
6122
+ emitAuthResolved(options.onEvent, "client_credentials");
6123
+ return cached;
6124
+ }
6125
+ const storedCredential = await getStoredClientCredentialsFromCli(resolvedBaseUrl);
6126
+ if (!storedCredential) {
6127
+ await invalidateCachedToken({
6128
+ clientId: activeCredential.clientId,
6129
+ scopes: activeCredential.scopes,
6130
+ baseUrl: resolvedBaseUrl,
6131
+ cache: options.cache
6132
+ });
6133
+ throw new ZapierAuthenticationError(
6134
+ `Stored client credential is missing its secret (clientId: ${activeCredential.clientId}). Run \`zapier-sdk login\` to recreate it.`
6135
+ );
6136
+ }
6137
+ if (options.debug)
6138
+ console.log(
6139
+ `[auth] Using stored client credential (clientId: ${storedCredential.clientId})`
6140
+ );
6141
+ const token = await resolveAuthTokenFromCredentials(
6142
+ storedCredential,
6143
+ options
6144
+ );
6145
+ emitAuthResolved(options.onEvent, "client_credentials");
6146
+ return token;
6147
+ }
5964
6148
  async function resolveAuthToken(options = {}) {
5965
6149
  const credentials = await resolveCredentials({
5966
6150
  credentials: options.credentials,
@@ -5970,14 +6154,24 @@ async function resolveAuthToken(options = {}) {
5970
6154
  if (credentials !== void 0) {
5971
6155
  return resolveAuthTokenFromCredentials(credentials, options);
5972
6156
  }
5973
- return getTokenFromCliLogin({
6157
+ const storedToken = await tryStoredClientCredentialToken(options);
6158
+ if (storedToken !== void 0) return storedToken;
6159
+ if (options.debug) {
6160
+ console.log("[auth] Using JWT (no stored client credential found)");
6161
+ }
6162
+ const jwtToken = await getTokenFromCliLogin({
5974
6163
  onEvent: options.onEvent,
5975
6164
  fetch: options.fetch,
5976
6165
  debug: options.debug
5977
6166
  });
6167
+ if (jwtToken !== void 0) {
6168
+ emitAuthResolved(options.onEvent, "jwt");
6169
+ }
6170
+ return jwtToken;
5978
6171
  }
5979
6172
  async function resolveAuthTokenFromCredentials(credentials, options) {
5980
6173
  if (typeof credentials === "string") {
6174
+ emitAuthResolved(options.onEvent, "token");
5981
6175
  return credentials;
5982
6176
  }
5983
6177
  if (isClientCredentials(credentials)) {
@@ -5990,15 +6184,25 @@ async function resolveAuthTokenFromCredentials(credentials, options) {
5990
6184
  baseUrl: resolvedBaseUrl
5991
6185
  });
5992
6186
  const cache = await resolveCache(options);
5993
- const cached = await cache.get(cacheKey);
5994
- if (cached && entryIsValid(cached)) {
5995
- return cached.value;
6187
+ const cached = await readCachedToken(cacheKey, cache);
6188
+ if (cached !== void 0) {
6189
+ if (options.debug) {
6190
+ console.log(`[auth] Using cached token (clientId: ${clientId})`);
6191
+ }
6192
+ return cached;
5996
6193
  }
5997
6194
  const pending = pendingExchanges.get(cacheKey);
5998
6195
  if (pending) return pending;
5999
6196
  const runLocked = async () => {
6000
- const recheck = await cache.get(cacheKey);
6001
- if (recheck && entryIsValid(recheck)) return recheck.value;
6197
+ const recheck = await readCachedToken(cacheKey, cache);
6198
+ if (recheck !== void 0) {
6199
+ if (options.debug) {
6200
+ console.log(
6201
+ `[auth] Using cached token (clientId: ${clientId}, locked recheck)`
6202
+ );
6203
+ }
6204
+ return recheck;
6205
+ }
6002
6206
  const { accessToken, expiresIn } = await exchangeClientCredentials({
6003
6207
  clientId: credentials.clientId,
6004
6208
  clientSecret: credentials.clientSecret,
@@ -6056,7 +6260,7 @@ async function invalidateCredentialsToken(options) {
6056
6260
  }
6057
6261
 
6058
6262
  // src/sdk-version.ts
6059
- var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.50.0" : void 0) || "unknown";
6263
+ var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.52.0" : void 0) || "unknown";
6060
6264
 
6061
6265
  // src/utils/open-url.ts
6062
6266
  var nodePrefix = "node:";
@@ -6266,9 +6470,61 @@ var ZapierApiClient = class {
6266
6470
  await sleep(delayMs, init?.signal ?? void 0);
6267
6471
  }
6268
6472
  };
6473
+ /**
6474
+ * Wrap an outbound HTTP call with the concurrency semaphore. Used by both
6475
+ * `rawFetch` (path-based) and the approval-poll path (absolute URL); each
6476
+ * caller acquires per-attempt, so 429 retry sleep is held but the gap
6477
+ * between approval polls and the human-approval wait are not.
6478
+ *
6479
+ * The release is registered in a finally that wraps the entire post-
6480
+ * acquire flow — including the `wait_end` event emission — so a throwing
6481
+ * `onEvent` handler can never leak a permit.
6482
+ *
6483
+ * Slot lifetime is intentionally tied to "fetch resolves" (headers
6484
+ * received), NOT to "response body fully consumed". WHATWG `fetch()`
6485
+ * resolves once headers are in; the body is still streaming. We rely on
6486
+ * that boundary so streaming responses (SSE, long-running chunked reads)
6487
+ * don't pin a permit for the lifetime of the stream — a single SSE
6488
+ * consumer would otherwise hold one of N slots for as long as the
6489
+ * connection stays open. Do not move the release into a path that awaits
6490
+ * body consumption (e.g. `parseResult` / `response.text()`); doing so
6491
+ * would silently break streaming consumers without failing any of the
6492
+ * short-request tests.
6493
+ */
6494
+ this.withSemaphore = async (context, fn) => {
6495
+ const fastRelease = this.semaphore.tryAcquire();
6496
+ let waitStart = null;
6497
+ let release = fastRelease;
6498
+ if (release === null) {
6499
+ waitStart = Date.now();
6500
+ this.emitEvent("api:concurrency_wait_start", {
6501
+ url: context.url,
6502
+ method: context.method
6503
+ });
6504
+ release = await this.semaphore.acquire(context.signal ?? void 0);
6505
+ }
6506
+ const acquiredRelease = release;
6507
+ try {
6508
+ if (waitStart !== null) {
6509
+ this.emitEvent("api:concurrency_wait_end", {
6510
+ url: context.url,
6511
+ method: context.method,
6512
+ waitedMs: Date.now() - waitStart
6513
+ });
6514
+ }
6515
+ return await fn();
6516
+ } finally {
6517
+ acquiredRelease();
6518
+ }
6519
+ };
6269
6520
  /**
6270
6521
  * Perform a request with auth, header merging, and rate-limit (429) retries.
6271
6522
  * Does NOT handle 403 approval_required — that's routed by `fetch`.
6523
+ *
6524
+ * Concurrency: a semaphore slot is held across the entire call, including
6525
+ * the 429 retry sleep inside `rawFetchUrl`. That keeps backpressure
6526
+ * coherent — when the server is rate-limiting us, we don't dump more
6527
+ * parallelism into the queue.
6272
6528
  */
6273
6529
  this.rawFetch = async (path, init) => {
6274
6530
  if (!path.startsWith("/")) {
@@ -6277,7 +6533,10 @@ var ZapierApiClient = class {
6277
6533
  );
6278
6534
  }
6279
6535
  const { url, pathConfig: pathConfig2 } = this.buildUrl(path, init?.searchParams);
6280
- return this.rawFetchUrl(url, init, pathConfig2);
6536
+ return this.withSemaphore(
6537
+ { url, method: init?.method ?? "GET", signal: init?.signal },
6538
+ () => this.rawFetchUrl(url, init, pathConfig2)
6539
+ );
6281
6540
  };
6282
6541
  /**
6283
6542
  * Approval-aware HTTP fetch.
@@ -6385,6 +6644,15 @@ var ZapierApiClient = class {
6385
6644
  };
6386
6645
  this.maxNetworkRetries = options.maxNetworkRetries ?? ZAPIER_MAX_NETWORK_RETRIES;
6387
6646
  this.maxNetworkRetryDelayMs = options.maxNetworkRetryDelayMs ?? ZAPIER_MAX_NETWORK_RETRY_DELAY_MS;
6647
+ const requested = options.maxConcurrentRequests;
6648
+ const limit = requested === void 0 || Number.isNaN(requested) ? ZAPIER_MAX_CONCURRENT_REQUESTS : requested;
6649
+ if (limit !== Infinity && (!Number.isInteger(limit) || limit < 1 || limit > MAX_CONCURRENCY_LIMIT)) {
6650
+ throw new ZapierConfigurationError(
6651
+ `Invalid maxConcurrentRequests: ${limit} (expected positive integer 1-${MAX_CONCURRENCY_LIMIT} or Infinity)`,
6652
+ { configType: "maxConcurrentRequests" }
6653
+ );
6654
+ }
6655
+ this.semaphore = createSemaphore(limit);
6388
6656
  }
6389
6657
  // Emit an event if onEvent handler is configured
6390
6658
  emitEvent(type, payload) {
@@ -6637,7 +6905,9 @@ var ZapierApiClient = class {
6637
6905
  if (data && typeof data === "object") {
6638
6906
  headers["Content-Type"] = "application/json";
6639
6907
  }
6640
- const wasMissingAuthToken = options.authRequired && await this.getAuthToken({ requiredScopes: options.requiredScopes }) == null;
6908
+ const wasMissingAuthToken = options.authRequired && await this.getAuthToken({
6909
+ requiredScopes: options.requiredScopes
6910
+ }) == null;
6641
6911
  const response = await this.fetch(path, {
6642
6912
  ...options,
6643
6913
  method,
@@ -6760,10 +7030,16 @@ var ZapierApiClient = class {
6760
7030
  // poll_url is an absolute URL supplied by the server, so we use
6761
7031
  // rawFetchUrl directly (skipping path resolution) but still share
6762
7032
  // auth + interactive-header + 429-retry with the rest of the SDK.
6763
- fetchPoll: () => this.rawFetchUrl(approval.poll_url, {
6764
- method: "GET",
6765
- headers: { Accept: "application/json" }
6766
- }),
7033
+ // Each individual poll request goes through the concurrency
7034
+ // semaphore — but we deliberately do not hold a slot across the
7035
+ // sleep between polls or across the human-approval wait.
7036
+ fetchPoll: () => this.withSemaphore(
7037
+ { url: approval.poll_url, method: "GET" },
7038
+ () => this.rawFetchUrl(approval.poll_url, {
7039
+ method: "GET",
7040
+ headers: { Accept: "application/json" }
7041
+ })
7042
+ ),
6767
7043
  timeoutMs,
6768
7044
  isPending: (body2) => {
6769
7045
  const parsed = PollApprovalResponseSchema.safeParse(body2);
@@ -6831,6 +7107,28 @@ var createZapierApi = (options) => {
6831
7107
  });
6832
7108
  };
6833
7109
 
7110
+ // src/api/index.ts
7111
+ function getOrCreateApiClient(config) {
7112
+ const {
7113
+ baseUrl = ZAPIER_BASE_URL,
7114
+ credentials,
7115
+ token,
7116
+ api: providedApi,
7117
+ debug = false,
7118
+ fetch: customFetch
7119
+ } = config;
7120
+ if (providedApi) {
7121
+ return providedApi;
7122
+ }
7123
+ return createZapierApi({
7124
+ baseUrl,
7125
+ credentials,
7126
+ token,
7127
+ debug,
7128
+ fetch: customFetch
7129
+ });
7130
+ }
7131
+
6834
7132
  // src/plugins/api/index.ts
6835
7133
  var apiPlugin = definePlugin(
6836
7134
  (sdk) => {
@@ -6843,6 +7141,7 @@ var apiPlugin = definePlugin(
6843
7141
  debug = false,
6844
7142
  maxNetworkRetries = ZAPIER_MAX_NETWORK_RETRIES,
6845
7143
  maxNetworkRetryDelayMs = ZAPIER_MAX_NETWORK_RETRY_DELAY_MS,
7144
+ maxConcurrentRequests = ZAPIER_MAX_CONCURRENT_REQUESTS,
6846
7145
  approvalTimeoutMs,
6847
7146
  maxApprovalRetries,
6848
7147
  approvalMode,
@@ -6857,6 +7156,7 @@ var apiPlugin = definePlugin(
6857
7156
  onEvent,
6858
7157
  maxNetworkRetries,
6859
7158
  maxNetworkRetryDelayMs,
7159
+ maxConcurrentRequests,
6860
7160
  approvalTimeoutMs,
6861
7161
  maxApprovalRetries,
6862
7162
  approvalMode,
@@ -8742,6 +9042,24 @@ var BaseSdkOptionsSchema = z.object({
8742
9042
  * Default is 60000 (60 seconds).
8743
9043
  */
8744
9044
  maxNetworkRetryDelayMs: z.number().optional().describe("Max delay in ms to wait for retry (default: 60000).").meta({ valueHint: "ms" }),
9045
+ /**
9046
+ * Maximum number of concurrent in-flight HTTP requests per client.
9047
+ * Requests beyond this limit queue in FIFO order until a slot frees.
9048
+ * Pass `Infinity` to disable. Default: 200.
9049
+ *
9050
+ * The description and meta are duplicated across the outer wrapper and
9051
+ * the inner numeric branch because the SDK and CLI doc generators walk
9052
+ * the schema differently — the SDK reader looks at wrappers only, while
9053
+ * the CLI reader recurses into union branches.
9054
+ */
9055
+ maxConcurrentRequests: z.union([
9056
+ z.number().int().min(1).max(MAX_CONCURRENCY_LIMIT).describe(
9057
+ `Max concurrent in-flight HTTP requests (default: 200, max: ${MAX_CONCURRENCY_LIMIT}).`
9058
+ ).meta({ valueHint: "count" }),
9059
+ z.literal(Infinity)
9060
+ ]).optional().describe(
9061
+ `Max concurrent in-flight HTTP requests (default: 200, max: ${MAX_CONCURRENCY_LIMIT}).`
9062
+ ).meta({ valueHint: "count" }),
8745
9063
  approvalTimeoutMs: z.number().optional().describe("Timeout in ms for approval polling. Default: 600000 (10 min).").meta({ valueHint: "ms" }),
8746
9064
  maxApprovalRetries: z.number().optional().describe(
8747
9065
  "Maximum number of sequential approval rounds per request (one per gating policy) before giving up. Default: 2."
@@ -8773,4 +9091,4 @@ var registryPlugin = definePlugin((_sdk) => {
8773
9091
  return {};
8774
9092
  });
8775
9093
 
8776
- export { ActionKeyPropertySchema, ActionPropertySchema, ActionTimeoutMsPropertySchema, ActionTypePropertySchema, AppKeyPropertySchema, AppPropertySchema, AppsPropertySchema, AuthenticationIdPropertySchema, BaseSdkOptionsSchema, CONTEXT_CACHE_MAX_SIZE, CONTEXT_CACHE_TTL_MS, ClientCredentialsObjectSchema, ConnectionEntrySchema, ConnectionIdPropertySchema, ConnectionPropertySchema, ConnectionsMapSchema, ConnectionsPropertySchema, CredentialsFunctionSchema, CredentialsObjectSchema, CredentialsSchema, DEFAULT_ACTION_TIMEOUT_MS, DEFAULT_APPROVAL_TIMEOUT_MS, DEFAULT_CONFIG_PATH, DEFAULT_MAX_APPROVAL_RETRIES, DEFAULT_PAGE_SIZE, DebugPropertySchema, FieldsPropertySchema, InputFieldPropertySchema, InputsPropertySchema, LeaseLimitPropertySchema, LeasePropertySchema, LeaseSecondsPropertySchema, LimitPropertySchema, MAX_PAGE_LIMIT, OffsetPropertySchema, OutputPropertySchema, ParamsPropertySchema, PkceCredentialsObjectSchema, RecordPropertySchema, RecordsPropertySchema, RelayFetchSchema, RelayRequestSchema, ResolvedCredentialsSchema, TablePropertySchema, TablesPropertySchema, TriggerInboxNamePropertySchema, TriggerInboxPropertySchema, ZAPIER_BASE_URL, ZAPIER_MAX_NETWORK_RETRIES, ZAPIER_MAX_NETWORK_RETRY_DELAY_MS, ZapierAbortDrainSignal, ZapierActionError, ZapierApiError, ZapierAppNotFoundError, ZapierApprovalError, ZapierAuthenticationError, ZapierBundleError, ZapierConfigurationError, ZapierConflictError, ZapierError, ZapierNotFoundError, ZapierRateLimitError, ZapierRelayError, ZapierReleaseTriggerMessageSignal, ZapierResourceNotFoundError, ZapierSignal, ZapierTimeoutError, ZapierUnknownError, ZapierValidationError, actionKeyResolver, actionTypeResolver, apiPlugin, appKeyResolver, appsPlugin, connectionIdGenericResolver as authenticationIdGenericResolver, connectionIdResolver as authenticationIdResolver, batch, buildApplicationLifecycleEvent, buildCapabilityMessage, buildErrorEvent, buildErrorEventWithContext, buildMethodCalledEvent, clearTokenCache, clientCredentialsNameResolver, clientIdResolver, composePlugins, connectionIdGenericResolver, connectionIdResolver, connectionsPlugin, createBaseEvent, createClientCredentialsPlugin, createFunction, createMemoryCache, createOptionsPlugin, createPaginatedPluginMethod, createPluginMethod, createSdk, createTableFieldsPlugin, createTablePlugin, createTableRecordsPlugin, createZapierSdk, createZapierSdkWithoutRegistry, definePlugin, deleteClientCredentialsPlugin, deleteTableFieldsPlugin, deleteTablePlugin, deleteTableRecordsPlugin, fetchPlugin, findFirstConnectionPlugin, findManifestEntry, findUniqueConnectionPlugin, formatErrorMessage, generateEventId, getActionInputFieldsSchemaPlugin, getActionPlugin, getAppPlugin, getBaseUrlFromCredentials, getCiPlatform, getClientIdFromCredentials, getConnectionPlugin, getCpuTime, getCurrentTimestamp, getMemoryUsage, getOsInfo, getPlatformVersions, getPreferredManifestEntryKey, getProfilePlugin, getReleaseId, getTablePlugin, getTableRecordPlugin, getTokenFromCliLogin, getZapierApprovalMode, getZapierSdkService, injectCliLogin, inputFieldKeyResolver, inputsAllOptionalResolver, inputsResolver, invalidateCachedToken, invalidateCredentialsToken, isCi, isCliLoginAvailable, isClientCredentials, isCredentialsFunction, isCredentialsObject, isPkceCredentials, isPositional, listActionInputFieldChoicesPlugin, listActionInputFieldsPlugin, listActionsPlugin, listAppsPlugin, listClientCredentialsPlugin, listConnectionsPlugin, listTableFieldsPlugin, listTableRecordsPlugin, listTablesPlugin, logDeprecation, manifestPlugin, readManifestFromFile, registryPlugin, requestPlugin, resetDeprecationWarnings, resolveAuthToken, resolveCredentials, resolveCredentialsFromEnv, runActionPlugin, runWithTelemetryContext, tableFieldIdsResolver, tableFieldsResolver, tableFiltersResolver, tableIdResolver, tableNameResolver, tableRecordIdResolver, tableRecordIdsResolver, tableRecordsResolver, tableSortResolver, tableUpdateRecordsResolver, toSnakeCase, toTitleCase, triggerInboxResolver, updateTableRecordsPlugin };
9094
+ export { ActionKeyPropertySchema, ActionPropertySchema, ActionTimeoutMsPropertySchema, ActionTypePropertySchema, AppKeyPropertySchema, AppPropertySchema, AppsPropertySchema, AuthenticationIdPropertySchema, BaseSdkOptionsSchema, CONTEXT_CACHE_MAX_SIZE, CONTEXT_CACHE_TTL_MS, ClientCredentialsObjectSchema, ConnectionEntrySchema, ConnectionIdPropertySchema, ConnectionPropertySchema, ConnectionsMapSchema, ConnectionsPropertySchema, CredentialsFunctionSchema, CredentialsObjectSchema, CredentialsSchema, DEFAULT_ACTION_TIMEOUT_MS, DEFAULT_APPROVAL_TIMEOUT_MS, DEFAULT_CONFIG_PATH, DEFAULT_MAX_APPROVAL_RETRIES, DEFAULT_PAGE_SIZE, DebugPropertySchema, FieldsPropertySchema, InputFieldPropertySchema, InputsPropertySchema, LeaseLimitPropertySchema, LeasePropertySchema, LeaseSecondsPropertySchema, LimitPropertySchema, MAX_CONCURRENCY_LIMIT, MAX_PAGE_LIMIT, OffsetPropertySchema, OutputPropertySchema, ParamsPropertySchema, PkceCredentialsObjectSchema, RecordPropertySchema, RecordsPropertySchema, RelayFetchSchema, RelayRequestSchema, ResolvedCredentialsSchema, TablePropertySchema, TablesPropertySchema, TriggerInboxNamePropertySchema, TriggerInboxPropertySchema, ZAPIER_BASE_URL, ZAPIER_MAX_CONCURRENT_REQUESTS, ZAPIER_MAX_NETWORK_RETRIES, ZAPIER_MAX_NETWORK_RETRY_DELAY_MS, ZapierAbortDrainSignal, ZapierActionError, ZapierApiError, ZapierAppNotFoundError, ZapierApprovalError, ZapierAuthenticationError, ZapierBundleError, ZapierConfigurationError, ZapierConflictError, ZapierError, ZapierNotFoundError, ZapierRateLimitError, ZapierRelayError, ZapierReleaseTriggerMessageSignal, ZapierResourceNotFoundError, ZapierSignal, ZapierTimeoutError, ZapierUnknownError, ZapierValidationError, actionKeyResolver, actionTypeResolver, apiPlugin, appKeyResolver, appsPlugin, connectionIdGenericResolver as authenticationIdGenericResolver, connectionIdResolver as authenticationIdResolver, batch, buildApplicationLifecycleEvent, buildCapabilityMessage, buildErrorEvent, buildErrorEventWithContext, buildMethodCalledEvent, clearTokenCache, clientCredentialsNameResolver, clientIdResolver, composePlugins, connectionIdGenericResolver, connectionIdResolver, connectionsPlugin, createBaseEvent, createClientCredentialsPlugin, createFunction, createMemoryCache, createOptionsPlugin, createPaginatedPluginMethod, createPluginMethod, createSdk, createTableFieldsPlugin, createTablePlugin, createTableRecordsPlugin, createZapierApi, createZapierSdk, createZapierSdkWithoutRegistry, definePlugin, deleteClientCredentialsPlugin, deleteTableFieldsPlugin, deleteTablePlugin, deleteTableRecordsPlugin, fetchPlugin, findFirstConnectionPlugin, findManifestEntry, findUniqueConnectionPlugin, formatErrorMessage, generateEventId, getActionInputFieldsSchemaPlugin, getActionPlugin, getAppPlugin, getBaseUrlFromCredentials, getCiPlatform, getClientIdFromCredentials, getConnectionPlugin, getCpuTime, getCurrentTimestamp, getMemoryUsage, getOrCreateApiClient, getOsInfo, getPlatformVersions, getPreferredManifestEntryKey, getProfilePlugin, getReleaseId, getTablePlugin, getTableRecordPlugin, getTokenFromCliLogin, getZapierApprovalMode, getZapierSdkService, injectCliLogin, inputFieldKeyResolver, inputsAllOptionalResolver, inputsResolver, invalidateCachedToken, invalidateCredentialsToken, isCi, isCliLoginAvailable, isClientCredentials, isCredentialsFunction, isCredentialsObject, isPkceCredentials, isPositional, listActionInputFieldChoicesPlugin, listActionInputFieldsPlugin, listActionsPlugin, listAppsPlugin, listClientCredentialsPlugin, listConnectionsPlugin, listTableFieldsPlugin, listTableRecordsPlugin, listTablesPlugin, logDeprecation, manifestPlugin, parseConcurrencyEnvVar, readManifestFromFile, registryPlugin, requestPlugin, resetDeprecationWarnings, resolveAuthToken, resolveCredentials, resolveCredentialsFromEnv, runActionPlugin, runWithTelemetryContext, tableFieldIdsResolver, tableFieldsResolver, tableFiltersResolver, tableIdResolver, tableNameResolver, tableRecordIdResolver, tableRecordIdsResolver, tableRecordsResolver, tableSortResolver, tableUpdateRecordsResolver, toSnakeCase, toTitleCase, triggerInboxResolver, updateTableRecordsPlugin };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/api/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAStD,MAAM,WAAW,gBAAiB,SAAQ,cAAc;CAAG;AAE3D,eAAO,MAAM,SAAS;aACH;QAAE,OAAO,EAAE,cAAc,CAAA;KAAE;;;;;;;;;;;;;;;;;;;;;CA6C7C,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/api/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAUtD,MAAM,WAAW,gBAAiB,SAAQ,cAAc;CAAG;AAE3D,eAAO,MAAM,SAAS;aACH;QAAE,OAAO,EAAE,cAAc,CAAA;KAAE;;;;;;;;;;;;;;;;;;;;;CA+C7C,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC"}
@@ -1,10 +1,10 @@
1
1
  import { createZapierApi } from "../../api";
2
2
  import { definePlugin } from "../../utils/plugin-utils";
3
3
  import { resolveCredentials } from "../../credentials";
4
- import { ZAPIER_BASE_URL, ZAPIER_MAX_NETWORK_RETRIES, ZAPIER_MAX_NETWORK_RETRY_DELAY_MS, } from "../../constants";
4
+ import { ZAPIER_BASE_URL, ZAPIER_MAX_CONCURRENT_REQUESTS, ZAPIER_MAX_NETWORK_RETRIES, ZAPIER_MAX_NETWORK_RETRY_DELAY_MS, } from "../../constants";
5
5
  export const apiPlugin = definePlugin((sdk) => {
6
6
  // Extract all options - everything passed to the plugin
7
- const { fetch: customFetch = globalThis.fetch, baseUrl = ZAPIER_BASE_URL, credentials, token, onEvent, debug = false, maxNetworkRetries = ZAPIER_MAX_NETWORK_RETRIES, maxNetworkRetryDelayMs = ZAPIER_MAX_NETWORK_RETRY_DELAY_MS, approvalTimeoutMs, maxApprovalRetries, approvalMode, callerPackage, } = sdk.context.options;
7
+ const { fetch: customFetch = globalThis.fetch, baseUrl = ZAPIER_BASE_URL, credentials, token, onEvent, debug = false, maxNetworkRetries = ZAPIER_MAX_NETWORK_RETRIES, maxNetworkRetryDelayMs = ZAPIER_MAX_NETWORK_RETRY_DELAY_MS, maxConcurrentRequests = ZAPIER_MAX_CONCURRENT_REQUESTS, approvalTimeoutMs, maxApprovalRetries, approvalMode, callerPackage, } = sdk.context.options;
8
8
  // Create the API client - it will handle token resolution internally
9
9
  const api = createZapierApi({
10
10
  baseUrl,
@@ -15,6 +15,7 @@ export const apiPlugin = definePlugin((sdk) => {
15
15
  onEvent,
16
16
  maxNetworkRetries,
17
17
  maxNetworkRetryDelayMs,
18
+ maxConcurrentRequests,
18
19
  approvalTimeoutMs,
19
20
  maxApprovalRetries,
20
21
  approvalMode,
@@ -38,7 +38,7 @@ export declare const appsPlugin: (sdk: {
38
38
  } & {
39
39
  runAction: (options?: (({
40
40
  app: string;
41
- actionType: "filter" | "read" | "read_bulk" | "run" | "search" | "search_and_write" | "search_or_write" | "write";
41
+ actionType: "filter" | "write" | "read" | "read_bulk" | "run" | "search" | "search_and_write" | "search_or_write";
42
42
  action: string;
43
43
  connection?: string | number | undefined;
44
44
  connectionId?: string | number | null | undefined;
@@ -50,7 +50,7 @@ export declare const appsPlugin: (sdk: {
50
50
  cursor?: string | undefined;
51
51
  } | {
52
52
  appKey: string;
53
- actionType: "filter" | "read" | "read_bulk" | "run" | "search" | "search_and_write" | "search_or_write" | "write";
53
+ actionType: "filter" | "write" | "read" | "read_bulk" | "run" | "search" | "search_and_write" | "search_or_write";
54
54
  actionKey: string;
55
55
  connection?: string | number | undefined;
56
56
  connectionId?: string | number | null | undefined;