@zapier/zapier-sdk 0.103.0 → 0.105.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.
@@ -13,6 +13,12 @@ var ZAPIER_BASE_URL = globalThis.process?.env?.ZAPIER_BASE_URL || "https://zapie
13
13
  function getZapierSdkService() {
14
14
  return globalThis.process?.env?.ZAPIER_SDK_SERVICE;
15
15
  }
16
+ function getZapierCorrelationId() {
17
+ return globalThis.process?.env?.ZAPIER_CORRELATION_ID || void 0;
18
+ }
19
+ function getZapierCausationId() {
20
+ return globalThis.process?.env?.ZAPIER_CAUSATION_ID || void 0;
21
+ }
16
22
  var MAX_PAGE_LIMIT = 1e4;
17
23
  var DEFAULT_PAGE_SIZE = 100;
18
24
  var DEFAULT_ACTION_TIMEOUT_MILLISECONDS = 18e4;
@@ -706,7 +712,6 @@ function createDebugFetch(options) {
706
712
  // src/utils/retry-utils.ts
707
713
  var MAX_CONSECUTIVE_ERRORS = 3;
708
714
  var BASE_ERROR_BACKOFF_MILLISECONDS = 1e3;
709
- var BASE_EXPONENTIAL_BACKOFF_MILLISECONDS = 1e3;
710
715
  var JITTER_FACTOR = 0.5;
711
716
  function calculateErrorBackoffMs(baseInterval, errorCount) {
712
717
  const jitter = Math.random() * JITTER_FACTOR * baseInterval;
@@ -717,11 +722,6 @@ function calculateErrorBackoffMs(baseInterval, errorCount) {
717
722
  );
718
723
  return Math.floor(baseInterval + jitter + errorBackoff);
719
724
  }
720
- function calculateExponentialBackoffMs(attempt, baseDelayMs = BASE_EXPONENTIAL_BACKOFF_MILLISECONDS) {
721
- const baseDelay = baseDelayMs * Math.pow(2, attempt - 1);
722
- const jitter = Math.random() * JITTER_FACTOR * baseDelay;
723
- return Math.floor(baseDelay + jitter);
724
- }
725
725
  function sleep(ms, signal) {
726
726
  if (!signal) {
727
727
  return new Promise((resolve2) => setTimeout(resolve2, ms));
@@ -1076,7 +1076,114 @@ var sdkOptionsPluginRef = kitcore.declareOptionalProperty({
1076
1076
  id: SDK_OPTIONS_ID
1077
1077
  });
1078
1078
 
1079
+ // src/api/rate-limit.ts
1080
+ var EPOCH_THRESHOLD_SECONDS = 1e9;
1081
+ function parseRateLimitHeaders(response) {
1082
+ const info = {};
1083
+ const retryAfter = response.headers.get("retry-after");
1084
+ if (retryAfter) {
1085
+ const seconds = parseInt(retryAfter, 10);
1086
+ if (!isNaN(seconds)) {
1087
+ info.retryAfterMs = Math.max(0, seconds * 1e3);
1088
+ } else {
1089
+ const date = Date.parse(retryAfter);
1090
+ if (!isNaN(date)) {
1091
+ info.retryAfterMs = Math.max(0, date - Date.now());
1092
+ }
1093
+ }
1094
+ }
1095
+ const reset = response.headers.get("x-ratelimit-reset");
1096
+ if (reset) {
1097
+ const resetValue = parseInt(reset, 10);
1098
+ if (!isNaN(resetValue)) {
1099
+ const isEpoch = resetValue >= EPOCH_THRESHOLD_SECONDS;
1100
+ info.resetMs = isEpoch ? resetValue * 1e3 : Date.now() + resetValue * 1e3;
1101
+ if (info.retryAfterMs === void 0) {
1102
+ info.retryAfterMs = isEpoch ? Math.max(0, info.resetMs - Date.now()) : Math.max(0, resetValue * 1e3);
1103
+ }
1104
+ }
1105
+ }
1106
+ const limit = response.headers.get("x-ratelimit-limit");
1107
+ if (limit) {
1108
+ const limitNum = parseInt(limit, 10);
1109
+ if (!isNaN(limitNum)) {
1110
+ info.limit = limitNum;
1111
+ }
1112
+ }
1113
+ const remaining = response.headers.get("x-ratelimit-remaining");
1114
+ if (remaining) {
1115
+ const remainingNum = parseInt(remaining, 10);
1116
+ if (!isNaN(remainingNum)) {
1117
+ info.remaining = remainingNum;
1118
+ }
1119
+ }
1120
+ return info;
1121
+ }
1122
+
1123
+ // src/utils/type-guard-utils.ts
1124
+ function isPlainObject(value) {
1125
+ if (typeof value !== "object" || value === null) return false;
1126
+ const proto = Object.getPrototypeOf(value);
1127
+ return proto === Object.prototype || proto === null;
1128
+ }
1129
+ function isPromiseLike(value) {
1130
+ return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
1131
+ }
1132
+
1133
+ // src/plugins/transport/retry-events.ts
1134
+ var retryCounts = /* @__PURE__ */ new WeakMap();
1135
+ function retriesFor(request) {
1136
+ return retryCounts.get(request) ?? 0;
1137
+ }
1138
+ function createRetryObserver({
1139
+ onEvent,
1140
+ maxNetworkRetries
1141
+ }) {
1142
+ return ({ request, attemptNumber, delayMilliseconds, response }) => {
1143
+ retryCounts.set(request, attemptNumber);
1144
+ if (!onEvent || response?.status !== 429) return;
1145
+ const observed = onEvent({
1146
+ type: "api:rate_limit_retry",
1147
+ payload: {
1148
+ retry: attemptNumber,
1149
+ maxNetworkRetries,
1150
+ delayMs: delayMilliseconds,
1151
+ path: request.url,
1152
+ method: request.method ?? "GET",
1153
+ rateLimit: parseRateLimitHeaders(response)
1154
+ },
1155
+ timestamp: Date.now()
1156
+ });
1157
+ if (isPromiseLike(observed)) {
1158
+ void Promise.resolve(observed).catch(() => {
1159
+ });
1160
+ }
1161
+ };
1162
+ }
1163
+
1079
1164
  // src/plugins/transport/options.ts
1165
+ var RETRYABLE_STATUSES = [429, 500, 502, 503, 504];
1166
+ var NON_IDEMPOTENT_RETRYABLE_STATUSES = [429];
1167
+ function resolveRetryHttpRequestOptions({
1168
+ maxNetworkRetries,
1169
+ maxNetworkRetryDelayMilliseconds,
1170
+ onEvent
1171
+ }) {
1172
+ const retries = maxNetworkRetries ?? ZAPIER_MAX_NETWORK_RETRIES;
1173
+ return {
1174
+ maxAttempts: retries + 1,
1175
+ maxDelayMilliseconds: maxNetworkRetryDelayMilliseconds ?? ZAPIER_MAX_NETWORK_RETRY_DELAY_MILLISECONDS,
1176
+ retryStatuses: RETRYABLE_STATUSES,
1177
+ nonIdempotentRetryStatuses: NON_IDEMPOTENT_RETRYABLE_STATUSES,
1178
+ onRetry: createRetryObserver({ onEvent, maxNetworkRetries: retries })
1179
+ };
1180
+ }
1181
+ function resolveNetworkRetryDelayMilliseconds({
1182
+ maxNetworkRetryDelaySeconds,
1183
+ maxNetworkRetryDelayMs
1184
+ }) {
1185
+ return maxNetworkRetryDelaySeconds != null ? maxNetworkRetryDelaySeconds * 1e3 : maxNetworkRetryDelayMs;
1186
+ }
1080
1187
  function resolveTransportFetch({
1081
1188
  fetch: customFetch,
1082
1189
  debug = false
@@ -1104,15 +1211,29 @@ var httpFetchPlugin = kitcore.defineProperty({
1104
1211
  // src/plugins/transport/standalone.ts
1105
1212
  function createZapierSendHttpRequest({
1106
1213
  fetch: customFetch,
1107
- debug
1214
+ debug,
1215
+ maxNetworkRetries,
1216
+ maxNetworkRetryDelayMilliseconds,
1217
+ onEvent
1108
1218
  }) {
1109
1219
  const sdk = kitcore.createSdk(
1110
1220
  kitcore.definePlugin({
1111
1221
  name: "zapierStandaloneHttpTransport",
1112
- imports: [kitcore.sendHttpRequestPlugin, httpFetchPlugin],
1222
+ imports: [kitcore.sendHttpRequestPlugin, kitcore.retryHttpRequestPlugin, httpFetchPlugin],
1113
1223
  exports: [kitcore.sendHttpRequestPlugin]
1114
1224
  }),
1115
- { configuration: { [SDK_OPTIONS_ID]: { fetch: customFetch, debug } } }
1225
+ {
1226
+ configuration: {
1227
+ [SDK_OPTIONS_ID]: { fetch: customFetch, debug },
1228
+ // Filled by configuration rather than the graph's property plugin: the
1229
+ // caller here holds client-shaped ms options, not SDK options.
1230
+ [kitcore.RETRY_HTTP_REQUEST_OPTIONS_ID]: resolveRetryHttpRequestOptions({
1231
+ maxNetworkRetries,
1232
+ maxNetworkRetryDelayMilliseconds,
1233
+ onEvent
1234
+ })
1235
+ }
1236
+ }
1116
1237
  );
1117
1238
  return sdk.sendHttpRequest;
1118
1239
  }
@@ -1121,6 +1242,17 @@ function createZapierSendHttpRequest({
1121
1242
  var CORRELATION_CALL_ID = Symbol(
1122
1243
  "zapier.correlationCallId"
1123
1244
  );
1245
+ function resolveCorrelationId({
1246
+ options,
1247
+ callId
1248
+ }) {
1249
+ return options?.correlationId || getZapierCorrelationId() || callId || void 0;
1250
+ }
1251
+ function resolveCausationId({
1252
+ options
1253
+ }) {
1254
+ return options?.causationId || getZapierCausationId();
1255
+ }
1124
1256
  var ClientCredentialsObjectSchema = zod.z.object({
1125
1257
  type: zod.z.enum(["client_credentials"]).optional().meta({ internal: true }),
1126
1258
  clientId: zod.z.string().describe("OAuth client ID for authentication.").meta({ valueHint: "id" }),
@@ -1770,13 +1902,6 @@ async function invalidateCredentialsToken(options) {
1770
1902
  });
1771
1903
  }
1772
1904
  }
1773
-
1774
- // src/utils/type-guard-utils.ts
1775
- function isPlainObject(value) {
1776
- if (typeof value !== "object" || value === null) return false;
1777
- const proto = Object.getPrototypeOf(value);
1778
- return proto === Object.prototype || proto === null;
1779
- }
1780
1905
  var callerContext = kitcore.createAsyncContext();
1781
1906
  function runWithCallerContext(context, fn) {
1782
1907
  let parent;
@@ -2022,9 +2147,6 @@ function sniffDeprecationNotice({
2022
2147
  }
2023
2148
  }
2024
2149
  }
2025
- function isPromiseLike(value) {
2026
- return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
2027
- }
2028
2150
  function parseDeprecationDate(value) {
2029
2151
  if (!value) return void 0;
2030
2152
  const match = /^@(-?\d+)$/.exec(value.trim());
@@ -2553,7 +2675,7 @@ function logRouteOverride({
2553
2675
  }
2554
2676
 
2555
2677
  // src/sdk-version.ts
2556
- var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.103.0" : void 0) || "unknown";
2678
+ var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.105.0" : void 0) || "unknown";
2557
2679
 
2558
2680
  // src/utils/open-url.ts
2559
2681
  var nodePrefix = "node:";
@@ -2669,7 +2791,6 @@ var PollApprovalResponseSchema = zod.z.object({
2669
2791
  approval_url: zod.z.string().optional()
2670
2792
  });
2671
2793
  var APPROVAL_MAX_POLLING_INTERVAL_MILLISECONDS = 5e3;
2672
- var EPOCH_THRESHOLD_SECONDS = 1e9;
2673
2794
  function validateSdkPath(path) {
2674
2795
  if (!path.startsWith("/") || path.startsWith("//")) {
2675
2796
  throw new ZapierValidationError(
@@ -2677,57 +2798,17 @@ function validateSdkPath(path) {
2677
2798
  );
2678
2799
  }
2679
2800
  }
2680
- function parseRateLimitHeaders(response) {
2681
- const info = {};
2682
- const retryAfter = response.headers.get("retry-after");
2683
- if (retryAfter) {
2684
- const seconds = parseInt(retryAfter, 10);
2685
- if (!isNaN(seconds)) {
2686
- info.retryAfterMs = seconds * 1e3;
2687
- } else {
2688
- const date = Date.parse(retryAfter);
2689
- if (!isNaN(date)) {
2690
- info.retryAfterMs = Math.max(0, date - Date.now());
2691
- }
2692
- }
2693
- }
2694
- const reset = response.headers.get("x-ratelimit-reset");
2695
- if (reset) {
2696
- const resetValue = parseInt(reset, 10);
2697
- if (!isNaN(resetValue)) {
2698
- const isEpoch = resetValue >= EPOCH_THRESHOLD_SECONDS;
2699
- info.resetMs = isEpoch ? resetValue * 1e3 : Date.now() + resetValue * 1e3;
2700
- if (info.retryAfterMs === void 0) {
2701
- info.retryAfterMs = isEpoch ? Math.max(0, info.resetMs - Date.now()) : Math.max(0, resetValue * 1e3);
2702
- }
2703
- }
2704
- }
2705
- const limit = response.headers.get("x-ratelimit-limit");
2706
- if (limit) {
2707
- const limitNum = parseInt(limit, 10);
2708
- if (!isNaN(limitNum)) {
2709
- info.limit = limitNum;
2710
- }
2711
- }
2712
- const remaining = response.headers.get("x-ratelimit-remaining");
2713
- if (remaining) {
2714
- const remainingNum = parseInt(remaining, 10);
2715
- if (!isNaN(remainingNum)) {
2716
- info.remaining = remainingNum;
2717
- }
2718
- }
2719
- return info;
2720
- }
2721
2801
  var ZapierApiClient = class {
2722
2802
  constructor(options) {
2723
2803
  this.options = options;
2724
2804
  /**
2725
2805
  * Perform a request against an already-resolved URL.
2726
2806
  *
2727
- * Does auth, header merging, and 429 retry all the cross-cutting
2728
- * concerns that every Zapier-bound HTTP call needs. Callers that have a
2729
- * path (e.g. `/relay/...`) should use `rawFetch` instead, which does
2730
- * path URL resolution and delegates here.
2807
+ * Does auth and header merging, and converts a terminal 429 into
2808
+ * `ZapierRateLimitError` the cross-cutting concerns that every
2809
+ * Zapier-bound HTTP call needs and that the transport does not own. Callers
2810
+ * that have a path (e.g. `/relay/...`) should use `rawFetch` instead, which
2811
+ * does path → URL resolution and delegates here.
2731
2812
  *
2732
2813
  * Exposed as a separate helper so call sites with a server-supplied
2733
2814
  * absolute URL (e.g. an approval poll URL) can still share the same
@@ -2761,47 +2842,30 @@ var ZapierApiClient = class {
2761
2842
  resource: _resource,
2762
2843
  ...wireInit
2763
2844
  } = fetchInit;
2764
- let retries = 0;
2765
- while (true) {
2766
- const response = await this.options.sendHttpRequest({
2767
- ...wireInit,
2768
- // Set the resolved URL and merged headers after the spread so caller
2769
- // values cannot override them.
2770
- url,
2771
- headers: Object.fromEntries(mergedHeaders)
2772
- });
2773
- if (response.status !== 429) {
2774
- return response;
2775
- }
2776
- const rateLimitInfo = parseRateLimitHeaders(response);
2777
- const delayMs = rateLimitInfo.retryAfterMs ?? calculateExponentialBackoffMs(retries + 1);
2778
- if (delayMs > this.maxNetworkRetryDelayMilliseconds || retries >= this.maxNetworkRetries) {
2779
- throw new ZapierRateLimitError(
2780
- await this.readRateLimitErrorMessage(response),
2781
- {
2782
- statusCode: 429,
2783
- rateLimit: rateLimitInfo,
2784
- retries
2785
- }
2786
- );
2787
- }
2788
- retries++;
2789
- this.emitEvent("api:rate_limit_retry", {
2790
- retry: retries,
2791
- maxNetworkRetries: this.maxNetworkRetries,
2792
- delayMs,
2793
- path: url,
2794
- method: init?.method ?? "GET",
2795
- rateLimit: rateLimitInfo
2796
- });
2797
- await sleep(delayMs, init?.signal ?? void 0);
2845
+ const request = {
2846
+ ...wireInit,
2847
+ url,
2848
+ headers: Object.fromEntries(mergedHeaders)
2849
+ };
2850
+ const response = await this.options.sendHttpRequest(request);
2851
+ if (response.status !== 429) {
2852
+ return response;
2798
2853
  }
2854
+ throw new ZapierRateLimitError(
2855
+ await this.readRateLimitErrorMessage(response),
2856
+ {
2857
+ statusCode: 429,
2858
+ rateLimit: parseRateLimitHeaders(response),
2859
+ retries: retriesFor(request)
2860
+ }
2861
+ );
2799
2862
  };
2800
2863
  /**
2801
2864
  * Wrap an outbound HTTP call with the concurrency semaphore. Used by both
2802
2865
  * `rawFetch` (path-based) and the approval-poll path (absolute URL); each
2803
- * caller acquires per-attempt, so 429 retry sleep is held but the gap
2804
- * between approval polls and the human-approval wait are not.
2866
+ * caller acquires per request, so the transport's retry sleeps are held
2867
+ * inside the permit but the gap between approval polls and the
2868
+ * human-approval wait are not.
2805
2869
  *
2806
2870
  * The release is registered in a finally that wraps the entire post-
2807
2871
  * acquire flow — including the `wait_end` event emission — so a throwing
@@ -3051,8 +3115,6 @@ var ZapierApiClient = class {
3051
3115
  signal: options.signal
3052
3116
  });
3053
3117
  };
3054
- this.maxNetworkRetries = options.maxNetworkRetries ?? ZAPIER_MAX_NETWORK_RETRIES;
3055
- this.maxNetworkRetryDelayMilliseconds = options.maxNetworkRetryDelayMilliseconds ?? options.maxNetworkRetryDelayMs ?? ZAPIER_MAX_NETWORK_RETRY_DELAY_MILLISECONDS;
3056
3118
  const requested = options.maxConcurrentRequests;
3057
3119
  const limit = requested === void 0 || Number.isNaN(requested) ? ZAPIER_MAX_CONCURRENT_REQUESTS : requested;
3058
3120
  if (limit !== Infinity && (!Number.isInteger(limit) || limit < 1 || limit > MAX_CONCURRENCY_LIMIT)) {
@@ -3342,11 +3404,21 @@ var ZapierApiClient = class {
3342
3404
  headers.set("zapier-sdk-package-operation", packageOperation);
3343
3405
  }
3344
3406
  }
3345
- if (callId) {
3346
- headers.set("zapier-correlation-id", callId);
3407
+ const correlationId = resolveCorrelationId({
3408
+ options: this.options,
3409
+ callId
3410
+ });
3411
+ if (correlationId) {
3412
+ headers.set("zapier-correlation-id", correlationId);
3347
3413
  } else {
3348
3414
  headers.delete("zapier-correlation-id");
3349
3415
  }
3416
+ const causationId = resolveCausationId({ options: this.options });
3417
+ if (causationId) {
3418
+ headers.set("zapier-causation-id", causationId);
3419
+ } else {
3420
+ headers.delete("zapier-causation-id");
3421
+ }
3350
3422
  }
3351
3423
  // Helper to perform HTTP requests with JSON handling
3352
3424
  async fetchJson(method, path, data, options = {}) {
@@ -3808,7 +3880,13 @@ var createZapierApi = (options) => {
3808
3880
  fetch: debugFetch,
3809
3881
  // Built from the caller's own `fetch`, not `debugFetch`: the pipeline wraps
3810
3882
  // for debug itself, and passing the wrapped one would log twice.
3811
- sendHttpRequest: options.sendHttpRequest ?? createZapierSendHttpRequest({ fetch: options.fetch, debug }),
3883
+ sendHttpRequest: options.sendHttpRequest ?? createZapierSendHttpRequest({
3884
+ fetch: options.fetch,
3885
+ debug,
3886
+ onEvent: options.onEvent,
3887
+ maxNetworkRetries: options.maxNetworkRetries,
3888
+ maxNetworkRetryDelayMilliseconds: options.maxNetworkRetryDelayMilliseconds ?? options.maxNetworkRetryDelayMs
3889
+ }),
3812
3890
  debugLog,
3813
3891
  routingOptions
3814
3892
  });
@@ -3847,10 +3925,30 @@ function getOrCreateApiClient(config) {
3847
3925
  callerPackage
3848
3926
  });
3849
3927
  }
3928
+ var retryHttpRequestOptionsPlugin = kitcore.defineProperty({
3929
+ namespace: "kitcore",
3930
+ name: "retryHttpRequestOptions",
3931
+ imports: [sdkOptionsPluginRef],
3932
+ setup: ({ imports }) => resolveRetryHttpRequestOptions({
3933
+ maxNetworkRetries: imports.sdkOptions?.maxNetworkRetries,
3934
+ maxNetworkRetryDelayMilliseconds: resolveNetworkRetryDelayMilliseconds(
3935
+ imports.sdkOptions ?? {}
3936
+ ),
3937
+ onEvent: imports.sdkOptions?.onEvent
3938
+ }),
3939
+ get: ({ state }) => state
3940
+ });
3941
+
3942
+ // src/plugins/transport/index.ts
3850
3943
  var zapierHttpTransportPlugin = kitcore.definePlugin({
3851
3944
  namespace: "zapier",
3852
3945
  name: "httpTransport",
3853
- imports: [kitcore.sendHttpRequestPlugin, httpFetchPlugin],
3946
+ imports: [
3947
+ kitcore.sendHttpRequestPlugin,
3948
+ kitcore.retryHttpRequestPlugin,
3949
+ retryHttpRequestOptionsPlugin,
3950
+ httpFetchPlugin
3951
+ ],
3854
3952
  exports: [kitcore.sendHttpRequestPlugin]
3855
3953
  });
3856
3954
 
@@ -3900,7 +3998,9 @@ var apiPlugin = kitcore.defineProperty({
3900
3998
  approvalMode,
3901
3999
  openAutoModeApprovalsInBrowser,
3902
4000
  callerPackage,
3903
- routeOverrides
4001
+ routeOverrides,
4002
+ correlationId,
4003
+ causationId
3904
4004
  } = imports.sdkOptions ?? {};
3905
4005
  return createZapierApi({
3906
4006
  baseUrl,
@@ -3910,7 +4010,10 @@ var apiPlugin = kitcore.defineProperty({
3910
4010
  fetch: customFetch,
3911
4011
  onEvent,
3912
4012
  maxNetworkRetries,
3913
- maxNetworkRetryDelayMilliseconds: (maxNetworkRetryDelaySeconds != null ? maxNetworkRetryDelaySeconds * 1e3 : maxNetworkRetryDelayMs) ?? ZAPIER_MAX_NETWORK_RETRY_DELAY_MILLISECONDS,
4013
+ maxNetworkRetryDelayMilliseconds: resolveNetworkRetryDelayMilliseconds({
4014
+ maxNetworkRetryDelaySeconds,
4015
+ maxNetworkRetryDelayMs
4016
+ }) ?? ZAPIER_MAX_NETWORK_RETRY_DELAY_MILLISECONDS,
3914
4017
  maxConcurrentRequests,
3915
4018
  approvalTimeoutMilliseconds: approvalTimeoutSeconds != null ? approvalTimeoutSeconds * 1e3 : approvalTimeoutMs,
3916
4019
  maxApprovalRetries,
@@ -3920,7 +4023,12 @@ var apiPlugin = kitcore.defineProperty({
3920
4023
  routeOverrides,
3921
4024
  // Inject the graph-composed transport so host `dispatchHttpRequest` wraps
3922
4025
  // apply.
3923
- sendHttpRequest: imports.sendHttpRequest
4026
+ sendHttpRequest: imports.sendHttpRequest,
4027
+ // Pass through unresolved so `resolveCorrelationId` / `resolveCausationId`
4028
+ // do the option-then-env-var chain at request time — the same helper the
4029
+ // event-emission hook calls, so header and MethodCalledEvent stay aligned.
4030
+ correlationId,
4031
+ causationId
3924
4032
  });
3925
4033
  },
3926
4034
  get: ({ state, callContext }) => callContext?.callId ? withCorrelationId({ client: state, callId: callContext.callId }) : state
@@ -11679,7 +11787,7 @@ function computeArgumentCount(args) {
11679
11787
  }
11680
11788
  return args.filter((a) => a !== void 0).length;
11681
11789
  }
11682
- function makeMethodEndHook(emitMethodCalled) {
11790
+ function makeMethodEndHook(emitMethodCalled, { sdkOptions } = {}) {
11683
11791
  return ({
11684
11792
  methodName,
11685
11793
  args,
@@ -11695,9 +11803,9 @@ function makeMethodEndHook(emitMethodCalled) {
11695
11803
  const metadata = readMethodMetadata(annotations);
11696
11804
  emitMethodCalled({
11697
11805
  method_name: methodName,
11698
- // The per-call correlation id (also the `zapier-correlation-id` header on
11699
- // this call's requests). Not the `call_context` surface label.
11700
- correlation_id: callId ?? null,
11806
+ // Same resolution as the `zapier-correlation-id` header: SDK option >
11807
+ // env var > per-call kitcore id. Not the `call_context` surface label.
11808
+ correlation_id: resolveCorrelationId({ options: sdkOptions, callId }) ?? null,
11701
11809
  execution_duration_ms: durationMs,
11702
11810
  success_flag: !error,
11703
11811
  error_message: error?.message ?? null,
@@ -12091,17 +12199,20 @@ var eventEmissionPlugin = kitcore.defineProperty({
12091
12199
  var eventEmissionHookPlugin = kitcore.defineHook({
12092
12200
  namespace: "zapier",
12093
12201
  name: "eventEmissionHook",
12094
- imports: [eventEmissionPlugin],
12202
+ imports: [eventEmissionPlugin, sdkOptionsPluginRef],
12095
12203
  observe: {
12096
12204
  onMethodEnd: ({ imports, input }) => {
12097
12205
  if (input.methodName === "getRegistry") return;
12098
- const emitter = imports.eventEmission;
12099
- makeMethodEndHook((data) => {
12100
- emitter.emit(METHOD_CALLED_EVENT_SUBJECT, {
12101
- ...buildMethodCalledEvent(data),
12102
- call_context: emitter.config.callContext ?? "sdk"
12103
- });
12104
- })(input);
12206
+ const { eventEmission: emitter, sdkOptions } = imports;
12207
+ makeMethodEndHook(
12208
+ (data) => {
12209
+ emitter.emit(METHOD_CALLED_EVENT_SUBJECT, {
12210
+ ...buildMethodCalledEvent(data),
12211
+ call_context: emitter.config.callContext ?? "sdk"
12212
+ });
12213
+ },
12214
+ { sdkOptions }
12215
+ )(input);
12105
12216
  }
12106
12217
  }
12107
12218
  });
@@ -12315,17 +12426,20 @@ var BaseSdkOptionsSchema = zod.z.object({
12315
12426
  routeOverrides: zod.z.record(zod.z.string(), zod.z.string()).optional().describe("Maps SDK route prefixes to direct origins.").meta({ internal: true }),
12316
12427
  trackingBaseUrl: zod.z.string().optional().describe("Base URL for Zapier tracking endpoints.").meta({ valueHint: "url" }),
12317
12428
  /**
12318
- * Maximum number of retries for rate-limited requests (429 responses).
12429
+ * Maximum number of retries for rate-limited requests (429 responses) and,
12430
+ * on idempotent methods, retryable server errors (500, 502, 503, 504).
12319
12431
  * Set to 0 to disable retries. Default is 3.
12320
12432
  */
12321
- maxNetworkRetries: zod.z.number().optional().describe("Max retries for rate-limited requests (default: 3).").meta({ valueHint: "count" }),
12433
+ maxNetworkRetries: zod.z.number().optional().describe(
12434
+ "Max retries for rate-limited and server-error responses (default: 3)."
12435
+ ).meta({ valueHint: "count" }),
12322
12436
  /**
12323
- * Maximum delay in seconds to wait for a rate-limit retry.
12437
+ * Maximum delay in seconds to wait between network retries.
12324
12438
  * If the server requests a longer delay, the request fails immediately.
12325
12439
  * Default is 60 (60 seconds).
12326
12440
  */
12327
12441
  maxNetworkRetryDelaySeconds: zod.z.number().optional().describe(
12328
- "Max delay in seconds to wait for a rate-limit retry (default: 60)."
12442
+ "Max delay in seconds to wait between network retries (default: 60)."
12329
12443
  ).meta({ valueHint: "seconds" }),
12330
12444
  /** @deprecated Use `maxNetworkRetryDelaySeconds` instead. */
12331
12445
  maxNetworkRetryDelayMs: zod.z.number().optional().describe("Max delay in ms to wait for retry (default: 60000).").meta({ valueHint: "ms", deprecated: true }),
@@ -12359,6 +12473,12 @@ var BaseSdkOptionsSchema = zod.z.object({
12359
12473
  openAutoModeApprovalsInBrowser: zod.z.boolean().optional().describe(
12360
12474
  "By default, auto-mode approvals do not open in a browser. Enable this option to open the approval URL and watch the approval process. Resolution order is: explicit option, then ZAPIER_OPEN_AUTO_MODE_APPROVALS_IN_BROWSER, then false."
12361
12475
  ),
12476
+ correlationId: zod.z.string().optional().describe(
12477
+ "Correlation ID for request tracing. When set, emitted as the `zapier-correlation-id` header on every outbound request. Falls back to the ZAPIER_CORRELATION_ID environment variable."
12478
+ ).meta({ valueHint: "id" }),
12479
+ causationId: zod.z.string().optional().describe(
12480
+ "Causation ID for request tracing. When set, emitted as the `zapier-causation-id` header on every outbound request. Falls back to the ZAPIER_CAUSATION_ID environment variable."
12481
+ ).meta({ valueHint: "id" }),
12362
12482
  // Internal
12363
12483
  manifestPath: zod.z.string().optional().describe("Path to a .zapierrc manifest file for app version locking.").meta({ internal: true }),
12364
12484
  manifest: zod.z.custom().optional().describe("Manifest for app version locking.").meta({ internal: true }),
@@ -12728,6 +12848,8 @@ exports.getTableRecordPlugin = getTableRecordPlugin;
12728
12848
  exports.getTokenFromCliLogin = getTokenFromCliLogin;
12729
12849
  exports.getTtyContext = getTtyContext;
12730
12850
  exports.getZapierApprovalMode = getZapierApprovalMode;
12851
+ exports.getZapierCausationId = getZapierCausationId;
12852
+ exports.getZapierCorrelationId = getZapierCorrelationId;
12731
12853
  exports.getZapierDefaultApprovalMode = getZapierDefaultApprovalMode;
12732
12854
  exports.getZapierOpenAutoModeApprovalsInBrowser = getZapierOpenAutoModeApprovalsInBrowser;
12733
12855
  exports.getZapierSdkService = getZapierSdkService;