@zapier/zapier-sdk 0.107.1 → 0.107.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @zapier/zapier-sdk
2
2
 
3
+ ## 0.107.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 48996ac: _This release contains no user-facing changes._
8
+
3
9
  ## 0.107.1
4
10
 
5
11
  ### Patch Changes
@@ -1308,6 +1308,16 @@ function emitOnce(onEvent, event) {
1308
1308
  var { logDeprecation, resetDeprecationWarnings } = createDeprecationLogger("zapier-sdk");
1309
1309
 
1310
1310
  // src/utils/url-utils.ts
1311
+ function withSearchParams({
1312
+ url,
1313
+ searchParams
1314
+ }) {
1315
+ const result = new URL(url);
1316
+ for (const [key, value] of Object.entries(searchParams ?? {})) {
1317
+ result.searchParams.set(key, value);
1318
+ }
1319
+ return result.toString();
1320
+ }
1311
1321
  function getZapierBaseUrl(baseUrl) {
1312
1322
  if (!baseUrl) {
1313
1323
  return void 0;
@@ -2152,6 +2162,88 @@ function parseDeprecationDate(value) {
2152
2162
  if (!match) return void 0;
2153
2163
  return Number(match[1]) * 1e3;
2154
2164
  }
2165
+ var RELAY_ERROR_HEADER = "x-relay-error";
2166
+ var RELAY_TIMEOUT_HEADER = "x-relay-extended-timeout";
2167
+ var SDK_CORRELATION_HEADER = "zapier-correlation-id";
2168
+ var SDK_MAX_TIME_HEADER = "x-zapier-sdk-max-time";
2169
+ var RELAY_NATIVE_TIMEOUT_SECONDS = 30;
2170
+ var RELAY_TIMEOUT_TIERS = [
2171
+ { seconds: 60, headerValue: "1m" },
2172
+ { seconds: 180, headerValue: "3m" },
2173
+ { seconds: 300, headerValue: "5m" },
2174
+ { seconds: 600, headerValue: "10m" }
2175
+ ];
2176
+ function transformRelayRequestHeaders({
2177
+ headers,
2178
+ debugLog
2179
+ }) {
2180
+ applyTimeoutTierPolicy({ headers, debugLog });
2181
+ applyCorrelationIdPolicy({ headers });
2182
+ return headers;
2183
+ }
2184
+ function applyCorrelationIdPolicy({ headers }) {
2185
+ const correlationId = headers.get(SDK_CORRELATION_HEADER);
2186
+ if (correlationId !== null && !isValidRelayCorrelationId(correlationId)) {
2187
+ headers.delete(SDK_CORRELATION_HEADER);
2188
+ }
2189
+ }
2190
+ function applyTimeoutTierPolicy({
2191
+ headers,
2192
+ debugLog
2193
+ }) {
2194
+ const sdkMaxTimeSeconds = headers.get(SDK_MAX_TIME_HEADER);
2195
+ headers.delete(SDK_MAX_TIME_HEADER);
2196
+ if (headers.has(RELAY_TIMEOUT_HEADER) || sdkMaxTimeSeconds === null) {
2197
+ return;
2198
+ }
2199
+ const seconds = parsePositiveInteger(sdkMaxTimeSeconds);
2200
+ if (seconds === void 0 || seconds <= RELAY_NATIVE_TIMEOUT_SECONDS) {
2201
+ return;
2202
+ }
2203
+ const match = RELAY_TIMEOUT_TIERS.find(
2204
+ (candidate) => candidate.seconds >= seconds
2205
+ );
2206
+ const tier = match ?? RELAY_TIMEOUT_TIERS[RELAY_TIMEOUT_TIERS.length - 1];
2207
+ if (!match) {
2208
+ debugLog?.(
2209
+ `Relay timeout of ${seconds}s exceeds the largest tier; capping to ${tier.headerValue}`
2210
+ );
2211
+ }
2212
+ headers.set(RELAY_TIMEOUT_HEADER, tier.headerValue);
2213
+ }
2214
+ function transformRelayResponseHeaders({
2215
+ headers
2216
+ }) {
2217
+ const relayError = headers.get(RELAY_ERROR_HEADER);
2218
+ if (!relayError?.startsWith("Authentication Template Failure")) {
2219
+ return headers;
2220
+ }
2221
+ const templateMatch = relayError.match(
2222
+ /Unable to find template for ([^@]+)@/
2223
+ );
2224
+ if (!templateMatch?.[1]) {
2225
+ return headers;
2226
+ }
2227
+ const appName = templateMatch[1].replace(/CLIAPI$/, "").replace(/([a-z])([A-Z])/g, "$1 $2").trim();
2228
+ if (!appName) {
2229
+ return headers;
2230
+ }
2231
+ headers.set(
2232
+ RELAY_ERROR_HEADER,
2233
+ `${appName} does not support direct HTTP requests. Use zapier.apps.{appKey} or zapier.runAction() to use Actions built for this app.`
2234
+ );
2235
+ return headers;
2236
+ }
2237
+ var RelayCorrelationIdSchema = z.uuid();
2238
+ function isValidRelayCorrelationId(value) {
2239
+ return RelayCorrelationIdSchema.safeParse(value).success;
2240
+ }
2241
+ function parsePositiveInteger(value) {
2242
+ if (!/^[1-9]\d*$/.test(value)) {
2243
+ return void 0;
2244
+ }
2245
+ return Number(value);
2246
+ }
2155
2247
 
2156
2248
  // src/api/routing/config.ts
2157
2249
  var pathConfig = {
@@ -2159,7 +2251,11 @@ var pathConfig = {
2159
2251
  "/relay": {
2160
2252
  authHeader: "X-Relay-Authorization",
2161
2253
  pathPrefix: "/api/v0/sdk/relay",
2162
- omitDeprecationMessaging: true
2254
+ omitDeprecationMessaging: true,
2255
+ override: {
2256
+ transformRequestHeaders: transformRelayRequestHeaders,
2257
+ transformResponseHeaders: transformRelayResponseHeaders
2258
+ }
2163
2259
  },
2164
2260
  // The concrete gateway form of the relay route. Callers that pass the
2165
2261
  // already-prefixed path reach the same third-party upstreams, so it must
@@ -2434,10 +2530,13 @@ function resolveOverrideRoute({
2434
2530
  }) {
2435
2531
  const { matchedPrefix, routeConfig, override } = overrideMatch;
2436
2532
  const directPath = deriveDirectPath({ path, matchedPrefix, routeConfig });
2533
+ const overrideConfig = routeConfig.override?.enabled === false ? void 0 : routeConfig.override;
2437
2534
  return {
2438
2535
  url: buildRouteOverrideUrl({ origin: override.origin, path: directPath }),
2439
2536
  pathConfig: routeConfig,
2440
- canSendDeprecationMessaging: false
2537
+ canSendDeprecationMessaging: false,
2538
+ ...overrideConfig?.transformRequestHeaders ? { transformRequestHeaders: overrideConfig.transformRequestHeaders } : {},
2539
+ ...overrideConfig?.transformResponseHeaders ? { transformResponseHeaders: overrideConfig.transformResponseHeaders } : {}
2441
2540
  };
2442
2541
  }
2443
2542
  function deriveDirectPath({
@@ -2617,6 +2716,89 @@ function isRouteOverrideEnabled({
2617
2716
  return routeConfig.override?.enabled !== false;
2618
2717
  }
2619
2718
 
2719
+ // src/api/routing/headers/request.ts
2720
+ function applyRequestHeaderTransform({
2721
+ headers,
2722
+ resolvedRoute,
2723
+ debugLog
2724
+ }) {
2725
+ return resolvedRoute?.transformRequestHeaders?.({ headers, debugLog }) ?? headers;
2726
+ }
2727
+
2728
+ // src/api/routing/headers/response.ts
2729
+ var NULL_BODY_RESPONSE_STATUSES = /* @__PURE__ */ new Set([204, 205, 304]);
2730
+ function applyResponseHeaderTransform({
2731
+ response,
2732
+ resolvedRoute
2733
+ }) {
2734
+ const transformHeaders = resolvedRoute?.transformResponseHeaders;
2735
+ if (!transformHeaders) {
2736
+ return response;
2737
+ }
2738
+ if (!Number.isInteger(response.status) || response.status < 200 || response.status > 599 || response.bodyUsed || response.body?.locked) {
2739
+ return response;
2740
+ }
2741
+ const originalHeaders = response.headers;
2742
+ if (!originalHeaders) {
2743
+ return response;
2744
+ }
2745
+ const transformedHeaders = transformHeaders({
2746
+ headers: new Headers(originalHeaders)
2747
+ });
2748
+ if (areHeadersEqual({ first: originalHeaders, second: transformedHeaders })) {
2749
+ return response;
2750
+ }
2751
+ const transformedResponse = new Response(
2752
+ NULL_BODY_RESPONSE_STATUSES.has(response.status) ? null : response.body,
2753
+ {
2754
+ status: response.status,
2755
+ statusText: response.statusText,
2756
+ headers: transformedHeaders
2757
+ }
2758
+ );
2759
+ return preserveResponseMetadata({
2760
+ response: transformedResponse,
2761
+ source: response
2762
+ });
2763
+ }
2764
+ function preserveResponseMetadata({
2765
+ response,
2766
+ source
2767
+ }) {
2768
+ const nativeClone = response.clone;
2769
+ Object.defineProperties(response, {
2770
+ clone: {
2771
+ configurable: true,
2772
+ writable: true,
2773
+ value: function clone() {
2774
+ const clonedResponse = nativeClone.call(this);
2775
+ return this === response ? preserveResponseMetadata({ response: clonedResponse, source }) : clonedResponse;
2776
+ }
2777
+ },
2778
+ ...sourceMetadataDescriptors(source)
2779
+ });
2780
+ return response;
2781
+ }
2782
+ function sourceMetadataDescriptors(source) {
2783
+ const descriptors = {};
2784
+ for (const key of ["redirected", "type", "url"]) {
2785
+ if (source[key] !== void 0) {
2786
+ descriptors[key] = { configurable: true, value: source[key] };
2787
+ }
2788
+ }
2789
+ return descriptors;
2790
+ }
2791
+ function areHeadersEqual({
2792
+ first,
2793
+ second
2794
+ }) {
2795
+ const firstEntries = [...first.entries()];
2796
+ const secondEntries = [...second.entries()];
2797
+ return firstEntries.length === secondEntries.length && firstEntries.every(
2798
+ ([key, value], index) => secondEntries[index]?.[0] === key && secondEntries[index]?.[1] === value
2799
+ );
2800
+ }
2801
+
2620
2802
  // src/api/routing/index.ts
2621
2803
  var routingConfig = createRoutingConfig({ pathConfig });
2622
2804
  function parseRoutingOptions({
@@ -2684,7 +2866,7 @@ function logRouteOverride({
2684
2866
  }
2685
2867
 
2686
2868
  // src/sdk-version.ts
2687
- var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.107.1" : void 0) || "unknown";
2869
+ var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.107.2" : void 0) || "unknown";
2688
2870
 
2689
2871
  // src/utils/open-url.ts
2690
2872
  var nodePrefix = "node:";
@@ -2824,14 +3006,14 @@ var ZapierApiClient = class {
2824
3006
  * auth/retry pipeline instead of reaching for `this.options.fetch`
2825
3007
  * directly and drifting.
2826
3008
  */
2827
- this.rawFetchUrl = async (url, init, pathConfig2) => {
3009
+ this.rawFetchUrl = async (url, init, resolvedRoute) => {
2828
3010
  const { [CORRELATION_CALL_ID]: callId, ...fetchInit } = init ?? {};
2829
3011
  if (fetchInit.body && (isPlainObject(fetchInit.body) || Array.isArray(fetchInit.body))) {
2830
3012
  fetchInit.body = JSON.stringify(fetchInit.body);
2831
3013
  }
2832
3014
  const builtHeaders = await this.buildHeaders(
2833
3015
  fetchInit,
2834
- pathConfig2
3016
+ resolvedRoute?.pathConfig
2835
3017
  );
2836
3018
  const inputHeaders = new Headers(fetchInit.headers ?? {});
2837
3019
  const mergedHeaders = new Headers();
@@ -2842,6 +3024,11 @@ var ZapierApiClient = class {
2842
3024
  mergedHeaders.set(key, value);
2843
3025
  });
2844
3026
  this.applyTelemetryHeaders({ headers: mergedHeaders, callId });
3027
+ const outboundHeaders = applyRequestHeaderTransform({
3028
+ headers: mergedHeaders,
3029
+ resolvedRoute,
3030
+ debugLog: this.options.debugLog
3031
+ });
2845
3032
  const {
2846
3033
  authRequired: _authRequired,
2847
3034
  requiredScopes: _requiredScopes,
@@ -2854,11 +3041,11 @@ var ZapierApiClient = class {
2854
3041
  const request = {
2855
3042
  ...wireInit,
2856
3043
  url,
2857
- headers: Object.fromEntries(mergedHeaders)
3044
+ headers: Object.fromEntries(outboundHeaders)
2858
3045
  };
2859
3046
  const response = await this.options.sendHttpRequest(request);
2860
3047
  if (response.status !== 429) {
2861
- return response;
3048
+ return applyResponseHeaderTransform({ response, resolvedRoute });
2862
3049
  }
2863
3050
  throw new ZapierRateLimitError(
2864
3051
  await this.readRateLimitErrorMessage(response),
@@ -2928,10 +3115,10 @@ var ZapierApiClient = class {
2928
3115
  */
2929
3116
  this.rawFetch = async (path, init) => {
2930
3117
  validateSdkPath(path);
2931
- const { url, pathConfig: pathConfig2 } = this.buildUrl(path, init?.searchParams);
3118
+ const { url, resolvedRoute } = this.buildUrl(path, init?.searchParams);
2932
3119
  return this.withSemaphore(
2933
3120
  { url, method: init?.method ?? "GET", signal: init?.signal },
2934
- () => this.rawFetchUrl(url, init, pathConfig2)
3121
+ () => this.rawFetchUrl(url, init, resolvedRoute)
2935
3122
  );
2936
3123
  };
2937
3124
  this.runApprovalFetchLoop = async ({
@@ -3341,22 +3528,12 @@ var ZapierApiClient = class {
3341
3528
  debugLog: this.options.debugLog
3342
3529
  });
3343
3530
  }
3344
- // Helper to build full URLs and return routing info
3345
3531
  buildUrl(path, searchParams) {
3346
- const {
3347
- url,
3348
- pathConfig: config,
3349
- canSendDeprecationMessaging
3350
- } = this.applyPathConfiguration(path);
3351
- if (searchParams) {
3352
- Object.entries(searchParams).forEach(([key, value]) => {
3353
- url.searchParams.set(key, value);
3354
- });
3355
- }
3532
+ const resolvedRoute = this.applyPathConfiguration(path);
3356
3533
  return {
3357
- url: url.toString(),
3358
- pathConfig: config,
3359
- canSendDeprecationMessaging
3534
+ url: withSearchParams({ url: resolvedRoute.url, searchParams }),
3535
+ resolvedRoute,
3536
+ canSendDeprecationMessaging: resolvedRoute.canSendDeprecationMessaging
3360
3537
  };
3361
3538
  }
3362
3539
  // Helper to build headers
@@ -1309,6 +1309,16 @@ function emitOnce(onEvent, event) {
1309
1309
  var { logDeprecation, resetDeprecationWarnings } = kitcore.createDeprecationLogger("zapier-sdk");
1310
1310
 
1311
1311
  // src/utils/url-utils.ts
1312
+ function withSearchParams({
1313
+ url,
1314
+ searchParams
1315
+ }) {
1316
+ const result = new URL(url);
1317
+ for (const [key, value] of Object.entries(searchParams ?? {})) {
1318
+ result.searchParams.set(key, value);
1319
+ }
1320
+ return result.toString();
1321
+ }
1312
1322
  function getZapierBaseUrl(baseUrl) {
1313
1323
  if (!baseUrl) {
1314
1324
  return void 0;
@@ -2153,6 +2163,88 @@ function parseDeprecationDate(value) {
2153
2163
  if (!match) return void 0;
2154
2164
  return Number(match[1]) * 1e3;
2155
2165
  }
2166
+ var RELAY_ERROR_HEADER = "x-relay-error";
2167
+ var RELAY_TIMEOUT_HEADER = "x-relay-extended-timeout";
2168
+ var SDK_CORRELATION_HEADER = "zapier-correlation-id";
2169
+ var SDK_MAX_TIME_HEADER = "x-zapier-sdk-max-time";
2170
+ var RELAY_NATIVE_TIMEOUT_SECONDS = 30;
2171
+ var RELAY_TIMEOUT_TIERS = [
2172
+ { seconds: 60, headerValue: "1m" },
2173
+ { seconds: 180, headerValue: "3m" },
2174
+ { seconds: 300, headerValue: "5m" },
2175
+ { seconds: 600, headerValue: "10m" }
2176
+ ];
2177
+ function transformRelayRequestHeaders({
2178
+ headers,
2179
+ debugLog
2180
+ }) {
2181
+ applyTimeoutTierPolicy({ headers, debugLog });
2182
+ applyCorrelationIdPolicy({ headers });
2183
+ return headers;
2184
+ }
2185
+ function applyCorrelationIdPolicy({ headers }) {
2186
+ const correlationId = headers.get(SDK_CORRELATION_HEADER);
2187
+ if (correlationId !== null && !isValidRelayCorrelationId(correlationId)) {
2188
+ headers.delete(SDK_CORRELATION_HEADER);
2189
+ }
2190
+ }
2191
+ function applyTimeoutTierPolicy({
2192
+ headers,
2193
+ debugLog
2194
+ }) {
2195
+ const sdkMaxTimeSeconds = headers.get(SDK_MAX_TIME_HEADER);
2196
+ headers.delete(SDK_MAX_TIME_HEADER);
2197
+ if (headers.has(RELAY_TIMEOUT_HEADER) || sdkMaxTimeSeconds === null) {
2198
+ return;
2199
+ }
2200
+ const seconds = parsePositiveInteger(sdkMaxTimeSeconds);
2201
+ if (seconds === void 0 || seconds <= RELAY_NATIVE_TIMEOUT_SECONDS) {
2202
+ return;
2203
+ }
2204
+ const match = RELAY_TIMEOUT_TIERS.find(
2205
+ (candidate) => candidate.seconds >= seconds
2206
+ );
2207
+ const tier = match ?? RELAY_TIMEOUT_TIERS[RELAY_TIMEOUT_TIERS.length - 1];
2208
+ if (!match) {
2209
+ debugLog?.(
2210
+ `Relay timeout of ${seconds}s exceeds the largest tier; capping to ${tier.headerValue}`
2211
+ );
2212
+ }
2213
+ headers.set(RELAY_TIMEOUT_HEADER, tier.headerValue);
2214
+ }
2215
+ function transformRelayResponseHeaders({
2216
+ headers
2217
+ }) {
2218
+ const relayError = headers.get(RELAY_ERROR_HEADER);
2219
+ if (!relayError?.startsWith("Authentication Template Failure")) {
2220
+ return headers;
2221
+ }
2222
+ const templateMatch = relayError.match(
2223
+ /Unable to find template for ([^@]+)@/
2224
+ );
2225
+ if (!templateMatch?.[1]) {
2226
+ return headers;
2227
+ }
2228
+ const appName = templateMatch[1].replace(/CLIAPI$/, "").replace(/([a-z])([A-Z])/g, "$1 $2").trim();
2229
+ if (!appName) {
2230
+ return headers;
2231
+ }
2232
+ headers.set(
2233
+ RELAY_ERROR_HEADER,
2234
+ `${appName} does not support direct HTTP requests. Use zapier.apps.{appKey} or zapier.runAction() to use Actions built for this app.`
2235
+ );
2236
+ return headers;
2237
+ }
2238
+ var RelayCorrelationIdSchema = zod.z.uuid();
2239
+ function isValidRelayCorrelationId(value) {
2240
+ return RelayCorrelationIdSchema.safeParse(value).success;
2241
+ }
2242
+ function parsePositiveInteger(value) {
2243
+ if (!/^[1-9]\d*$/.test(value)) {
2244
+ return void 0;
2245
+ }
2246
+ return Number(value);
2247
+ }
2156
2248
 
2157
2249
  // src/api/routing/config.ts
2158
2250
  var pathConfig = {
@@ -2160,7 +2252,11 @@ var pathConfig = {
2160
2252
  "/relay": {
2161
2253
  authHeader: "X-Relay-Authorization",
2162
2254
  pathPrefix: "/api/v0/sdk/relay",
2163
- omitDeprecationMessaging: true
2255
+ omitDeprecationMessaging: true,
2256
+ override: {
2257
+ transformRequestHeaders: transformRelayRequestHeaders,
2258
+ transformResponseHeaders: transformRelayResponseHeaders
2259
+ }
2164
2260
  },
2165
2261
  // The concrete gateway form of the relay route. Callers that pass the
2166
2262
  // already-prefixed path reach the same third-party upstreams, so it must
@@ -2435,10 +2531,13 @@ function resolveOverrideRoute({
2435
2531
  }) {
2436
2532
  const { matchedPrefix, routeConfig, override } = overrideMatch;
2437
2533
  const directPath = deriveDirectPath({ path, matchedPrefix, routeConfig });
2534
+ const overrideConfig = routeConfig.override?.enabled === false ? void 0 : routeConfig.override;
2438
2535
  return {
2439
2536
  url: buildRouteOverrideUrl({ origin: override.origin, path: directPath }),
2440
2537
  pathConfig: routeConfig,
2441
- canSendDeprecationMessaging: false
2538
+ canSendDeprecationMessaging: false,
2539
+ ...overrideConfig?.transformRequestHeaders ? { transformRequestHeaders: overrideConfig.transformRequestHeaders } : {},
2540
+ ...overrideConfig?.transformResponseHeaders ? { transformResponseHeaders: overrideConfig.transformResponseHeaders } : {}
2442
2541
  };
2443
2542
  }
2444
2543
  function deriveDirectPath({
@@ -2618,6 +2717,89 @@ function isRouteOverrideEnabled({
2618
2717
  return routeConfig.override?.enabled !== false;
2619
2718
  }
2620
2719
 
2720
+ // src/api/routing/headers/request.ts
2721
+ function applyRequestHeaderTransform({
2722
+ headers,
2723
+ resolvedRoute,
2724
+ debugLog
2725
+ }) {
2726
+ return resolvedRoute?.transformRequestHeaders?.({ headers, debugLog }) ?? headers;
2727
+ }
2728
+
2729
+ // src/api/routing/headers/response.ts
2730
+ var NULL_BODY_RESPONSE_STATUSES = /* @__PURE__ */ new Set([204, 205, 304]);
2731
+ function applyResponseHeaderTransform({
2732
+ response,
2733
+ resolvedRoute
2734
+ }) {
2735
+ const transformHeaders = resolvedRoute?.transformResponseHeaders;
2736
+ if (!transformHeaders) {
2737
+ return response;
2738
+ }
2739
+ if (!Number.isInteger(response.status) || response.status < 200 || response.status > 599 || response.bodyUsed || response.body?.locked) {
2740
+ return response;
2741
+ }
2742
+ const originalHeaders = response.headers;
2743
+ if (!originalHeaders) {
2744
+ return response;
2745
+ }
2746
+ const transformedHeaders = transformHeaders({
2747
+ headers: new Headers(originalHeaders)
2748
+ });
2749
+ if (areHeadersEqual({ first: originalHeaders, second: transformedHeaders })) {
2750
+ return response;
2751
+ }
2752
+ const transformedResponse = new Response(
2753
+ NULL_BODY_RESPONSE_STATUSES.has(response.status) ? null : response.body,
2754
+ {
2755
+ status: response.status,
2756
+ statusText: response.statusText,
2757
+ headers: transformedHeaders
2758
+ }
2759
+ );
2760
+ return preserveResponseMetadata({
2761
+ response: transformedResponse,
2762
+ source: response
2763
+ });
2764
+ }
2765
+ function preserveResponseMetadata({
2766
+ response,
2767
+ source
2768
+ }) {
2769
+ const nativeClone = response.clone;
2770
+ Object.defineProperties(response, {
2771
+ clone: {
2772
+ configurable: true,
2773
+ writable: true,
2774
+ value: function clone() {
2775
+ const clonedResponse = nativeClone.call(this);
2776
+ return this === response ? preserveResponseMetadata({ response: clonedResponse, source }) : clonedResponse;
2777
+ }
2778
+ },
2779
+ ...sourceMetadataDescriptors(source)
2780
+ });
2781
+ return response;
2782
+ }
2783
+ function sourceMetadataDescriptors(source) {
2784
+ const descriptors = {};
2785
+ for (const key of ["redirected", "type", "url"]) {
2786
+ if (source[key] !== void 0) {
2787
+ descriptors[key] = { configurable: true, value: source[key] };
2788
+ }
2789
+ }
2790
+ return descriptors;
2791
+ }
2792
+ function areHeadersEqual({
2793
+ first,
2794
+ second
2795
+ }) {
2796
+ const firstEntries = [...first.entries()];
2797
+ const secondEntries = [...second.entries()];
2798
+ return firstEntries.length === secondEntries.length && firstEntries.every(
2799
+ ([key, value], index) => secondEntries[index]?.[0] === key && secondEntries[index]?.[1] === value
2800
+ );
2801
+ }
2802
+
2621
2803
  // src/api/routing/index.ts
2622
2804
  var routingConfig = createRoutingConfig({ pathConfig });
2623
2805
  function parseRoutingOptions({
@@ -2685,7 +2867,7 @@ function logRouteOverride({
2685
2867
  }
2686
2868
 
2687
2869
  // src/sdk-version.ts
2688
- var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.107.1" : void 0) || "unknown";
2870
+ var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.107.2" : void 0) || "unknown";
2689
2871
 
2690
2872
  // src/utils/open-url.ts
2691
2873
  var nodePrefix = "node:";
@@ -2825,14 +3007,14 @@ var ZapierApiClient = class {
2825
3007
  * auth/retry pipeline instead of reaching for `this.options.fetch`
2826
3008
  * directly and drifting.
2827
3009
  */
2828
- this.rawFetchUrl = async (url, init, pathConfig2) => {
3010
+ this.rawFetchUrl = async (url, init, resolvedRoute) => {
2829
3011
  const { [CORRELATION_CALL_ID]: callId, ...fetchInit } = init ?? {};
2830
3012
  if (fetchInit.body && (isPlainObject(fetchInit.body) || Array.isArray(fetchInit.body))) {
2831
3013
  fetchInit.body = JSON.stringify(fetchInit.body);
2832
3014
  }
2833
3015
  const builtHeaders = await this.buildHeaders(
2834
3016
  fetchInit,
2835
- pathConfig2
3017
+ resolvedRoute?.pathConfig
2836
3018
  );
2837
3019
  const inputHeaders = new Headers(fetchInit.headers ?? {});
2838
3020
  const mergedHeaders = new Headers();
@@ -2843,6 +3025,11 @@ var ZapierApiClient = class {
2843
3025
  mergedHeaders.set(key, value);
2844
3026
  });
2845
3027
  this.applyTelemetryHeaders({ headers: mergedHeaders, callId });
3028
+ const outboundHeaders = applyRequestHeaderTransform({
3029
+ headers: mergedHeaders,
3030
+ resolvedRoute,
3031
+ debugLog: this.options.debugLog
3032
+ });
2846
3033
  const {
2847
3034
  authRequired: _authRequired,
2848
3035
  requiredScopes: _requiredScopes,
@@ -2855,11 +3042,11 @@ var ZapierApiClient = class {
2855
3042
  const request = {
2856
3043
  ...wireInit,
2857
3044
  url,
2858
- headers: Object.fromEntries(mergedHeaders)
3045
+ headers: Object.fromEntries(outboundHeaders)
2859
3046
  };
2860
3047
  const response = await this.options.sendHttpRequest(request);
2861
3048
  if (response.status !== 429) {
2862
- return response;
3049
+ return applyResponseHeaderTransform({ response, resolvedRoute });
2863
3050
  }
2864
3051
  throw new ZapierRateLimitError(
2865
3052
  await this.readRateLimitErrorMessage(response),
@@ -2929,10 +3116,10 @@ var ZapierApiClient = class {
2929
3116
  */
2930
3117
  this.rawFetch = async (path, init) => {
2931
3118
  validateSdkPath(path);
2932
- const { url, pathConfig: pathConfig2 } = this.buildUrl(path, init?.searchParams);
3119
+ const { url, resolvedRoute } = this.buildUrl(path, init?.searchParams);
2933
3120
  return this.withSemaphore(
2934
3121
  { url, method: init?.method ?? "GET", signal: init?.signal },
2935
- () => this.rawFetchUrl(url, init, pathConfig2)
3122
+ () => this.rawFetchUrl(url, init, resolvedRoute)
2936
3123
  );
2937
3124
  };
2938
3125
  this.runApprovalFetchLoop = async ({
@@ -3342,22 +3529,12 @@ var ZapierApiClient = class {
3342
3529
  debugLog: this.options.debugLog
3343
3530
  });
3344
3531
  }
3345
- // Helper to build full URLs and return routing info
3346
3532
  buildUrl(path, searchParams) {
3347
- const {
3348
- url,
3349
- pathConfig: config,
3350
- canSendDeprecationMessaging
3351
- } = this.applyPathConfiguration(path);
3352
- if (searchParams) {
3353
- Object.entries(searchParams).forEach(([key, value]) => {
3354
- url.searchParams.set(key, value);
3355
- });
3356
- }
3533
+ const resolvedRoute = this.applyPathConfiguration(path);
3357
3534
  return {
3358
- url: url.toString(),
3359
- pathConfig: config,
3360
- canSendDeprecationMessaging
3535
+ url: withSearchParams({ url: resolvedRoute.url, searchParams }),
3536
+ resolvedRoute,
3537
+ canSendDeprecationMessaging: resolvedRoute.canSendDeprecationMessaging
3361
3538
  };
3362
3539
  }
3363
3540
  // Helper to build headers