@zapier/zapier-sdk 0.107.0 → 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.
@@ -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.0" : 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
@@ -7978,6 +8155,13 @@ var ListConnectionsQuerySchema = connections.ListConnectionsQuerySchema.omit({
7978
8155
  // SDK specific property for pagination/iterable helpers
7979
8156
  cursor: zod.z.string().optional().describe("Cursor to start from")
7980
8157
  }).describe("List available connections with optional filtering");
8158
+ connections.ConnectionSchema.extend({
8159
+ is_stale: zod.z.boolean().optional(),
8160
+ is_shared: zod.z.boolean().optional(),
8161
+ members: zod.z.array(zod.z.record(zod.z.string(), zod.z.any())).optional(),
8162
+ customuser_id: zod.z.number().nullable().optional(),
8163
+ customuser_public_id: zod.z.string().nullable().optional()
8164
+ });
7981
8165
  function formatConnectionItem(item) {
7982
8166
  const details = [];
7983
8167
  const appKey = item.app_key ?? "unknown";
@@ -8289,6 +8473,76 @@ var getAppPlugin = kitcore.defineMethod({
8289
8473
  throw new ZapierAppNotFoundError("App not found", { appKey });
8290
8474
  }
8291
8475
  });
8476
+
8477
+ // src/normalizers/shared.ts
8478
+ function fastifyToString(value) {
8479
+ if (value === void 0) {
8480
+ return void 0;
8481
+ }
8482
+ if (typeof value === "string") {
8483
+ return value;
8484
+ }
8485
+ if (value === null) {
8486
+ return "";
8487
+ }
8488
+ if (value instanceof Date) {
8489
+ return value.toISOString();
8490
+ }
8491
+ if (value instanceof RegExp) {
8492
+ return value.source;
8493
+ }
8494
+ try {
8495
+ return String(value.toString());
8496
+ } catch {
8497
+ return "[unserializable]";
8498
+ }
8499
+ }
8500
+
8501
+ // src/normalizers/connection.ts
8502
+ function normalizeConnectionItem({
8503
+ connection,
8504
+ appKey: providedAppKey,
8505
+ appVersion: providedAppVersion,
8506
+ adaptError
8507
+ }) {
8508
+ let appKey = providedAppKey;
8509
+ let appVersion = providedAppVersion;
8510
+ if (connection.selected_api && typeof connection.selected_api === "string") {
8511
+ const [extractedAppKey, extractedVersion] = splitVersionedKey(
8512
+ connection.selected_api
8513
+ );
8514
+ if (!appKey) {
8515
+ appKey = extractedAppKey;
8516
+ }
8517
+ if (!appVersion) {
8518
+ appVersion = extractedVersion;
8519
+ }
8520
+ }
8521
+ const {
8522
+ selected_api: selectedApi,
8523
+ customuser_id: profileId,
8524
+ id,
8525
+ account_id: accountId,
8526
+ ...restOfConnection
8527
+ } = connection;
8528
+ const normalized = {
8529
+ ...restOfConnection,
8530
+ id: String(id),
8531
+ account_id: String(accountId),
8532
+ implementation_id: selectedApi,
8533
+ title: connection.title || connection.label || void 0,
8534
+ is_stale: fastifyToString(connection.is_stale),
8535
+ is_expired: fastifyToString(connection.is_stale),
8536
+ is_shared: fastifyToString(connection.is_shared),
8537
+ members: fastifyToString(connection.members),
8538
+ customuser_public_id: fastifyToString(connection.customuser_public_id),
8539
+ expired_at: connection.marked_stale_at,
8540
+ app_key: appKey,
8541
+ app_version: appVersion,
8542
+ profile_id: profileId != null ? String(profileId) : void 0
8543
+ };
8544
+ return kitcore.createValidator(connections.ConnectionItemSchema, { adaptError })(normalized);
8545
+ }
8292
8546
  var GetConnectionDescription = "Get details for a specific connection";
8293
8547
  var GetConnectionSchema = zod.z.object({
8294
8548
  connection: ConnectionPropertySchema
@@ -8310,7 +8564,7 @@ var GetConnectionInputSchema = zod.z.union([
8310
8564
  // src/plugins/getConnection/index.ts
8311
8565
  var getConnectionPlugin = kitcore.defineMethod({
8312
8566
  name: "getConnection",
8313
- imports: [apiPluginRef],
8567
+ imports: [apiPluginRef, kitcore.coreOptionsPluginRef],
8314
8568
  categories: ["connection"],
8315
8569
  itemType: "Connection",
8316
8570
  inputSchema: GetConnectionInputSchema,
@@ -8322,8 +8576,8 @@ var getConnectionPlugin = kitcore.defineMethod({
8322
8576
  run: async ({ imports, input }) => {
8323
8577
  const api = imports.api;
8324
8578
  const resolvedConnectionId = "connection" in input ? input.connection : "connectionId" in input ? input.connectionId : input.authenticationId;
8325
- const response = await api.get(
8326
- `/api/v0/connections/${encodeURIComponent(String(resolvedConnectionId))}`,
8579
+ const raw = await api.get(
8580
+ `/zapier/api/v4/authentications/${encodeURIComponent(String(resolvedConnectionId))}/`,
8327
8581
  {
8328
8582
  resource: {
8329
8583
  type: "connection",
@@ -8331,7 +8585,14 @@ var getConnectionPlugin = kitcore.defineMethod({
8331
8585
  }
8332
8586
  }
8333
8587
  );
8334
- return { data: transformConnectionItem(response.data) };
8588
+ return {
8589
+ data: transformConnectionItem(
8590
+ normalizeConnectionItem({
8591
+ connection: raw,
8592
+ adaptError: imports.coreOptions?.adaptError
8593
+ })
8594
+ )
8595
+ };
8335
8596
  }
8336
8597
  });
8337
8598