@zapier/zapier-sdk 0.102.4 → 0.104.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.
- package/CHANGELOG.md +18 -0
- package/README.md +2 -2
- package/dist/{chunk-6TIBB6TI.mjs → chunk-CJKNVBRZ.mjs} +723 -239
- package/dist/{chunk-WVRZG6I6.cjs → chunk-ZEZNG44W.cjs} +722 -238
- package/dist/experimental.cjs +355 -355
- package/dist/experimental.d.mts +4 -3
- package/dist/experimental.d.ts +4 -3
- package/dist/experimental.mjs +2 -2
- package/dist/{index-CfJjkJU-.d.mts → index-Blmu5pN3.d.mts} +25 -4
- package/dist/{index-CfJjkJU-.d.ts → index-Blmu5pN3.d.ts} +25 -4
- package/dist/index.cjs +277 -277
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __require } from './chunk-Y6FXYEAI.mjs';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { withPositional, declareOptionalProperty, defineProperty, createDeprecationLogger, createAsyncContext, definePlugin, sendHttpRequestPlugin, declareProperty, defineMethod, coreOptionsPluginRef, createValidator, defineFormatter, declareMethod, defineResolver, concatLists, openEnum, defineHook, getRegistryPlugin, paginate, toSnakeCase, isCoreError, toTitleCase, createSdk, CORE_ERROR_SYMBOL, CoreErrorCode, CORE_SIGNAL_SYMBOL, isCoreSignal, CORE_OPTIONS_ID } from '@zapier/kitcore';
|
|
3
|
+
import { withPositional, declareOptionalProperty, defineProperty, createDeprecationLogger, createAsyncContext, definePlugin, sendHttpRequestPlugin, retryHttpRequestPlugin, declareProperty, defineMethod, coreOptionsPluginRef, createValidator, defineFormatter, declareMethod, defineResolver, concatLists, openEnum, defineHook, getRegistryPlugin, paginate, toSnakeCase, isCoreError, toTitleCase, createSdk, RETRY_HTTP_REQUEST_OPTIONS_ID, CORE_ERROR_SYMBOL, CoreErrorCode, CORE_SIGNAL_SYMBOL, isCoreSignal, CORE_OPTIONS_ID } from '@zapier/kitcore';
|
|
4
4
|
export { CONTEXT, CORE_ERROR_SYMBOL, CORE_OPTIONS_ID, CORE_SIGNAL_SYMBOL, CoreCancelledSignal, CoreDisposeError, CoreErrorCode, CoreSignal, addPlugin, composePlugins, createController, createCorePlugin, createFunction, createPaginatedFunction, createPaginatedPluginMethod, createPluginMethod, createPluginStack, createSdk, declareMethod, declareOptionalProperty, declarePlugin, declareProperty, defineFormatter, defineLegacyMerge, defineMethod, defineMethodOverride, defineOverride, definePlugin, defineProperty, defineResolver, disposeSdk, fromFunctionPlugin, getContext, getCoreErrorCause, getCoreErrorCode, getNegatable, getRegistryPlugin, isCoreCancelledSignal, isCoreError, isCoreSignal, isPositional, omitExports, resolvePlugin, runInMethodScope, runWithTelemetryContext, selectExports, toSnakeCase, toTitleCase } from '@zapier/kitcore';
|
|
5
5
|
import { buildHttpRequestContext, buildActionRunContext } from '@zapier/policy-context';
|
|
6
6
|
import { ListAppsQuerySchema, AppItemSchema as AppItemSchema$1 } from '@zapier/zapier-sdk-core/v0/schemas/apps';
|
|
@@ -705,7 +705,6 @@ function createDebugFetch(options) {
|
|
|
705
705
|
// src/utils/retry-utils.ts
|
|
706
706
|
var MAX_CONSECUTIVE_ERRORS = 3;
|
|
707
707
|
var BASE_ERROR_BACKOFF_MILLISECONDS = 1e3;
|
|
708
|
-
var BASE_EXPONENTIAL_BACKOFF_MILLISECONDS = 1e3;
|
|
709
708
|
var JITTER_FACTOR = 0.5;
|
|
710
709
|
function calculateErrorBackoffMs(baseInterval, errorCount) {
|
|
711
710
|
const jitter = Math.random() * JITTER_FACTOR * baseInterval;
|
|
@@ -716,11 +715,6 @@ function calculateErrorBackoffMs(baseInterval, errorCount) {
|
|
|
716
715
|
);
|
|
717
716
|
return Math.floor(baseInterval + jitter + errorBackoff);
|
|
718
717
|
}
|
|
719
|
-
function calculateExponentialBackoffMs(attempt, baseDelayMs = BASE_EXPONENTIAL_BACKOFF_MILLISECONDS) {
|
|
720
|
-
const baseDelay = baseDelayMs * Math.pow(2, attempt - 1);
|
|
721
|
-
const jitter = Math.random() * JITTER_FACTOR * baseDelay;
|
|
722
|
-
return Math.floor(baseDelay + jitter);
|
|
723
|
-
}
|
|
724
718
|
function sleep(ms, signal) {
|
|
725
719
|
if (!signal) {
|
|
726
720
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
@@ -1075,7 +1069,114 @@ var sdkOptionsPluginRef = declareOptionalProperty({
|
|
|
1075
1069
|
id: SDK_OPTIONS_ID
|
|
1076
1070
|
});
|
|
1077
1071
|
|
|
1072
|
+
// src/api/rate-limit.ts
|
|
1073
|
+
var EPOCH_THRESHOLD_SECONDS = 1e9;
|
|
1074
|
+
function parseRateLimitHeaders(response) {
|
|
1075
|
+
const info = {};
|
|
1076
|
+
const retryAfter = response.headers.get("retry-after");
|
|
1077
|
+
if (retryAfter) {
|
|
1078
|
+
const seconds = parseInt(retryAfter, 10);
|
|
1079
|
+
if (!isNaN(seconds)) {
|
|
1080
|
+
info.retryAfterMs = Math.max(0, seconds * 1e3);
|
|
1081
|
+
} else {
|
|
1082
|
+
const date = Date.parse(retryAfter);
|
|
1083
|
+
if (!isNaN(date)) {
|
|
1084
|
+
info.retryAfterMs = Math.max(0, date - Date.now());
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
const reset = response.headers.get("x-ratelimit-reset");
|
|
1089
|
+
if (reset) {
|
|
1090
|
+
const resetValue = parseInt(reset, 10);
|
|
1091
|
+
if (!isNaN(resetValue)) {
|
|
1092
|
+
const isEpoch = resetValue >= EPOCH_THRESHOLD_SECONDS;
|
|
1093
|
+
info.resetMs = isEpoch ? resetValue * 1e3 : Date.now() + resetValue * 1e3;
|
|
1094
|
+
if (info.retryAfterMs === void 0) {
|
|
1095
|
+
info.retryAfterMs = isEpoch ? Math.max(0, info.resetMs - Date.now()) : Math.max(0, resetValue * 1e3);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
const limit = response.headers.get("x-ratelimit-limit");
|
|
1100
|
+
if (limit) {
|
|
1101
|
+
const limitNum = parseInt(limit, 10);
|
|
1102
|
+
if (!isNaN(limitNum)) {
|
|
1103
|
+
info.limit = limitNum;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
const remaining = response.headers.get("x-ratelimit-remaining");
|
|
1107
|
+
if (remaining) {
|
|
1108
|
+
const remainingNum = parseInt(remaining, 10);
|
|
1109
|
+
if (!isNaN(remainingNum)) {
|
|
1110
|
+
info.remaining = remainingNum;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
return info;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// src/utils/type-guard-utils.ts
|
|
1117
|
+
function isPlainObject(value) {
|
|
1118
|
+
if (typeof value !== "object" || value === null) return false;
|
|
1119
|
+
const proto = Object.getPrototypeOf(value);
|
|
1120
|
+
return proto === Object.prototype || proto === null;
|
|
1121
|
+
}
|
|
1122
|
+
function isPromiseLike(value) {
|
|
1123
|
+
return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// src/plugins/transport/retry-events.ts
|
|
1127
|
+
var retryCounts = /* @__PURE__ */ new WeakMap();
|
|
1128
|
+
function retriesFor(request) {
|
|
1129
|
+
return retryCounts.get(request) ?? 0;
|
|
1130
|
+
}
|
|
1131
|
+
function createRetryObserver({
|
|
1132
|
+
onEvent,
|
|
1133
|
+
maxNetworkRetries
|
|
1134
|
+
}) {
|
|
1135
|
+
return ({ request, attemptNumber, delayMilliseconds, response }) => {
|
|
1136
|
+
retryCounts.set(request, attemptNumber);
|
|
1137
|
+
if (!onEvent || response?.status !== 429) return;
|
|
1138
|
+
const observed = onEvent({
|
|
1139
|
+
type: "api:rate_limit_retry",
|
|
1140
|
+
payload: {
|
|
1141
|
+
retry: attemptNumber,
|
|
1142
|
+
maxNetworkRetries,
|
|
1143
|
+
delayMs: delayMilliseconds,
|
|
1144
|
+
path: request.url,
|
|
1145
|
+
method: request.method ?? "GET",
|
|
1146
|
+
rateLimit: parseRateLimitHeaders(response)
|
|
1147
|
+
},
|
|
1148
|
+
timestamp: Date.now()
|
|
1149
|
+
});
|
|
1150
|
+
if (isPromiseLike(observed)) {
|
|
1151
|
+
void Promise.resolve(observed).catch(() => {
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1078
1157
|
// src/plugins/transport/options.ts
|
|
1158
|
+
var RETRYABLE_STATUSES = [429, 500, 502, 503, 504];
|
|
1159
|
+
var NON_IDEMPOTENT_RETRYABLE_STATUSES = [429];
|
|
1160
|
+
function resolveRetryHttpRequestOptions({
|
|
1161
|
+
maxNetworkRetries,
|
|
1162
|
+
maxNetworkRetryDelayMilliseconds,
|
|
1163
|
+
onEvent
|
|
1164
|
+
}) {
|
|
1165
|
+
const retries = maxNetworkRetries ?? ZAPIER_MAX_NETWORK_RETRIES;
|
|
1166
|
+
return {
|
|
1167
|
+
maxAttempts: retries + 1,
|
|
1168
|
+
maxDelayMilliseconds: maxNetworkRetryDelayMilliseconds ?? ZAPIER_MAX_NETWORK_RETRY_DELAY_MILLISECONDS,
|
|
1169
|
+
retryStatuses: RETRYABLE_STATUSES,
|
|
1170
|
+
nonIdempotentRetryStatuses: NON_IDEMPOTENT_RETRYABLE_STATUSES,
|
|
1171
|
+
onRetry: createRetryObserver({ onEvent, maxNetworkRetries: retries })
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
function resolveNetworkRetryDelayMilliseconds({
|
|
1175
|
+
maxNetworkRetryDelaySeconds,
|
|
1176
|
+
maxNetworkRetryDelayMs
|
|
1177
|
+
}) {
|
|
1178
|
+
return maxNetworkRetryDelaySeconds != null ? maxNetworkRetryDelaySeconds * 1e3 : maxNetworkRetryDelayMs;
|
|
1179
|
+
}
|
|
1079
1180
|
function resolveTransportFetch({
|
|
1080
1181
|
fetch: customFetch,
|
|
1081
1182
|
debug = false
|
|
@@ -1103,15 +1204,29 @@ var httpFetchPlugin = defineProperty({
|
|
|
1103
1204
|
// src/plugins/transport/standalone.ts
|
|
1104
1205
|
function createZapierSendHttpRequest({
|
|
1105
1206
|
fetch: customFetch,
|
|
1106
|
-
debug
|
|
1207
|
+
debug,
|
|
1208
|
+
maxNetworkRetries,
|
|
1209
|
+
maxNetworkRetryDelayMilliseconds,
|
|
1210
|
+
onEvent
|
|
1107
1211
|
}) {
|
|
1108
1212
|
const sdk = createSdk(
|
|
1109
1213
|
definePlugin({
|
|
1110
1214
|
name: "zapierStandaloneHttpTransport",
|
|
1111
|
-
imports: [sendHttpRequestPlugin, httpFetchPlugin],
|
|
1215
|
+
imports: [sendHttpRequestPlugin, retryHttpRequestPlugin, httpFetchPlugin],
|
|
1112
1216
|
exports: [sendHttpRequestPlugin]
|
|
1113
1217
|
}),
|
|
1114
|
-
{
|
|
1218
|
+
{
|
|
1219
|
+
configuration: {
|
|
1220
|
+
[SDK_OPTIONS_ID]: { fetch: customFetch, debug },
|
|
1221
|
+
// Filled by configuration rather than the graph's property plugin: the
|
|
1222
|
+
// caller here holds client-shaped ms options, not SDK options.
|
|
1223
|
+
[RETRY_HTTP_REQUEST_OPTIONS_ID]: resolveRetryHttpRequestOptions({
|
|
1224
|
+
maxNetworkRetries,
|
|
1225
|
+
maxNetworkRetryDelayMilliseconds,
|
|
1226
|
+
onEvent
|
|
1227
|
+
})
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1115
1230
|
);
|
|
1116
1231
|
return sdk.sendHttpRequest;
|
|
1117
1232
|
}
|
|
@@ -1769,13 +1884,6 @@ async function invalidateCredentialsToken(options) {
|
|
|
1769
1884
|
});
|
|
1770
1885
|
}
|
|
1771
1886
|
}
|
|
1772
|
-
|
|
1773
|
-
// src/utils/type-guard-utils.ts
|
|
1774
|
-
function isPlainObject(value) {
|
|
1775
|
-
if (typeof value !== "object" || value === null) return false;
|
|
1776
|
-
const proto = Object.getPrototypeOf(value);
|
|
1777
|
-
return proto === Object.prototype || proto === null;
|
|
1778
|
-
}
|
|
1779
1887
|
var callerContext = createAsyncContext();
|
|
1780
1888
|
function runWithCallerContext(context, fn) {
|
|
1781
1889
|
let parent;
|
|
@@ -2021,9 +2129,6 @@ function sniffDeprecationNotice({
|
|
|
2021
2129
|
}
|
|
2022
2130
|
}
|
|
2023
2131
|
}
|
|
2024
|
-
function isPromiseLike(value) {
|
|
2025
|
-
return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
|
|
2026
|
-
}
|
|
2027
2132
|
function parseDeprecationDate(value) {
|
|
2028
2133
|
if (!value) return void 0;
|
|
2029
2134
|
const match = /^@(-?\d+)$/.exec(value.trim());
|
|
@@ -2031,8 +2136,528 @@ function parseDeprecationDate(value) {
|
|
|
2031
2136
|
return Number(match[1]) * 1e3;
|
|
2032
2137
|
}
|
|
2033
2138
|
|
|
2139
|
+
// src/api/routing/config.ts
|
|
2140
|
+
var pathConfig = {
|
|
2141
|
+
// e.g. /relay -> https://sdkapi.zapier.com/api/v0/sdk/relay/...
|
|
2142
|
+
"/relay": {
|
|
2143
|
+
authHeader: "X-Relay-Authorization",
|
|
2144
|
+
pathPrefix: "/api/v0/sdk/relay",
|
|
2145
|
+
omitDeprecationMessaging: true
|
|
2146
|
+
},
|
|
2147
|
+
// The concrete gateway form of the relay route. Callers that pass the
|
|
2148
|
+
// already-prefixed path reach the same third-party upstreams, so it must
|
|
2149
|
+
// classify as relay too; without this entry it would match nothing and
|
|
2150
|
+
// sniff deprecation headers off a relay response.
|
|
2151
|
+
"/api/v0/sdk/relay": {
|
|
2152
|
+
override: { enabled: false },
|
|
2153
|
+
omitDeprecationMessaging: true
|
|
2154
|
+
},
|
|
2155
|
+
// Concrete sdkapi routes that do not live behind /api/v0/sdk/<service>.
|
|
2156
|
+
"/api/v0": {},
|
|
2157
|
+
// e.g. /zapier -> https://sdkapi.zapier.com/api/v0/sdk/zapier/...
|
|
2158
|
+
"/zapier": {
|
|
2159
|
+
authHeader: "Authorization",
|
|
2160
|
+
pathPrefix: "/api/v0/sdk/zapier"
|
|
2161
|
+
},
|
|
2162
|
+
// e.g. /tables -> https://sdkapi.zapier.com/api/v0/sdk/tables/...
|
|
2163
|
+
"/tables": {
|
|
2164
|
+
authHeader: "Authorization",
|
|
2165
|
+
pathPrefix: "/api/v0/sdk/tables"
|
|
2166
|
+
},
|
|
2167
|
+
// e.g. /trigger-inbox -> https://sdkapi.zapier.com/api/v0/sdk/trigger-inbox/...
|
|
2168
|
+
"/trigger-inbox": {
|
|
2169
|
+
authHeader: "Authorization",
|
|
2170
|
+
pathPrefix: "/api/v0/sdk/trigger-inbox"
|
|
2171
|
+
},
|
|
2172
|
+
// e.g. /sdkdurableapi -> https://sdkapi.zapier.com/api/v0/sdk/sdkdurableapi/...
|
|
2173
|
+
// sdkapi proxies to the sdkdurableapi backend.
|
|
2174
|
+
"/sdkdurableapi": {
|
|
2175
|
+
authHeader: "Authorization",
|
|
2176
|
+
pathPrefix: "/api/v0/sdk/sdkdurableapi"
|
|
2177
|
+
},
|
|
2178
|
+
// e.g. /durableworkflowzaps -> https://sdkapi.zapier.com/api/v0/sdk/durableworkflowzaps/...
|
|
2179
|
+
// sdkapi proxies to the durableworkflowzaps backend.
|
|
2180
|
+
"/durableworkflowzaps": {
|
|
2181
|
+
authHeader: "Authorization",
|
|
2182
|
+
pathPrefix: "/api/v0/sdk/durableworkflowzaps"
|
|
2183
|
+
},
|
|
2184
|
+
// e.g. /code-substrate-runner -> https://sdkapi.zapier.com/api/v0/sdk/code-substrate-runner/...
|
|
2185
|
+
// sdkapi proxies to the code-substrate-runner backend.
|
|
2186
|
+
"/code-substrate-runner": {
|
|
2187
|
+
authHeader: "Authorization",
|
|
2188
|
+
pathPrefix: "/api/v0/sdk/code-substrate-runner"
|
|
2189
|
+
},
|
|
2190
|
+
// e.g. /code-substrate-workflows -> https://sdkapi.zapier.com/api/v0/sdk/code-substrate-workflows/...
|
|
2191
|
+
// sdkapi proxies to the code-substrate-workflows backend.
|
|
2192
|
+
"/code-substrate-workflows": {
|
|
2193
|
+
authHeader: "Authorization",
|
|
2194
|
+
pathPrefix: "/api/v0/sdk/code-substrate-workflows"
|
|
2195
|
+
},
|
|
2196
|
+
// e.g. /code-substrate-analyzer/validations ->
|
|
2197
|
+
// https://api.zapier.com/code-substrate-analyzer/v0/validations
|
|
2198
|
+
"/code-substrate-analyzer": {
|
|
2199
|
+
authHeader: "Authorization",
|
|
2200
|
+
pathPrefix: "/code-substrate-analyzer/v0",
|
|
2201
|
+
subdomain: "api",
|
|
2202
|
+
override: { pathPrefixMode: "preserve" }
|
|
2203
|
+
},
|
|
2204
|
+
// e.g. /forms/v0/forms -> https://api.zapier.com/forms/v0/forms
|
|
2205
|
+
// The Forms API is registered on the Public API Gateway and has no sdkapi
|
|
2206
|
+
// proxy route, so it goes straight to the gateway. Its governance metadata
|
|
2207
|
+
// rewrites /forms/v0/... to the backend's /api/forms/v0/..., which is why no
|
|
2208
|
+
// pathPrefix is applied here.
|
|
2209
|
+
"/forms": {
|
|
2210
|
+
authHeader: "Authorization",
|
|
2211
|
+
subdomain: "api"
|
|
2212
|
+
}
|
|
2213
|
+
};
|
|
2214
|
+
|
|
2215
|
+
// src/api/routing/default.ts
|
|
2216
|
+
function resolveDefaultRoute({
|
|
2217
|
+
path,
|
|
2218
|
+
baseUrl
|
|
2219
|
+
}) {
|
|
2220
|
+
const matchingPathEntries = findPathConfigEntries({ path });
|
|
2221
|
+
const routingMatch = matchingPathEntries[0];
|
|
2222
|
+
let finalPath = path;
|
|
2223
|
+
if (routingMatch?.config.pathPrefix) {
|
|
2224
|
+
const pathWithoutPrefix = path.slice(routingMatch.configPath.length) || "/";
|
|
2225
|
+
finalPath = `${routingMatch.config.pathPrefix}${pathWithoutPrefix}`;
|
|
2226
|
+
}
|
|
2227
|
+
const zapierBaseUrl = getZapierBaseUrl(baseUrl);
|
|
2228
|
+
if (zapierBaseUrl === baseUrl.replace(/\/$/, "")) {
|
|
2229
|
+
const originalBaseUrl = new URL(baseUrl);
|
|
2230
|
+
const subdomain = routingMatch?.config.subdomain ?? "sdkapi";
|
|
2231
|
+
const finalBaseUrl = `https://${subdomain}.${originalBaseUrl.hostname}`;
|
|
2232
|
+
return buildRouteResult({
|
|
2233
|
+
url: new URL(finalPath, finalBaseUrl),
|
|
2234
|
+
matchingPathEntries,
|
|
2235
|
+
routingMatch
|
|
2236
|
+
});
|
|
2237
|
+
}
|
|
2238
|
+
const parsedBaseUrl = new URL(baseUrl);
|
|
2239
|
+
const basePath = parsedBaseUrl.pathname.replace(/\/$/, "");
|
|
2240
|
+
return buildRouteResult({
|
|
2241
|
+
url: new URL(basePath + finalPath, parsedBaseUrl.origin),
|
|
2242
|
+
matchingPathEntries,
|
|
2243
|
+
routingMatch
|
|
2244
|
+
});
|
|
2245
|
+
}
|
|
2246
|
+
function buildRouteResult({
|
|
2247
|
+
url,
|
|
2248
|
+
matchingPathEntries,
|
|
2249
|
+
routingMatch
|
|
2250
|
+
}) {
|
|
2251
|
+
const resolvedPathEntries = findPathConfigEntries({
|
|
2252
|
+
path: url.pathname,
|
|
2253
|
+
matchResolvedGatewayPath: true
|
|
2254
|
+
});
|
|
2255
|
+
const deprecationPathMatches = [
|
|
2256
|
+
...matchingPathEntries,
|
|
2257
|
+
...resolvedPathEntries
|
|
2258
|
+
];
|
|
2259
|
+
const canSendDeprecationMessaging = deprecationPathMatches.length > 0 && deprecationPathMatches.every(
|
|
2260
|
+
({ config }) => config.omitDeprecationMessaging !== true
|
|
2261
|
+
);
|
|
2262
|
+
return {
|
|
2263
|
+
url,
|
|
2264
|
+
pathConfig: routingMatch?.config,
|
|
2265
|
+
canSendDeprecationMessaging
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
function findPathConfigEntries({
|
|
2269
|
+
path,
|
|
2270
|
+
matchResolvedGatewayPath = false
|
|
2271
|
+
}) {
|
|
2272
|
+
const pathSegments = path.split("/").filter(Boolean);
|
|
2273
|
+
return Object.entries(pathConfig).filter(([configPath, config]) => {
|
|
2274
|
+
if (!matchResolvedGatewayPath) {
|
|
2275
|
+
return path === configPath || path.startsWith(`${configPath}/`);
|
|
2276
|
+
}
|
|
2277
|
+
const prefixSegments = (config.pathPrefix ?? configPath).split("/").filter(Boolean);
|
|
2278
|
+
return pathSegments.some(
|
|
2279
|
+
(_, startIndex) => prefixSegments.every(
|
|
2280
|
+
(segment, offset) => pathSegments[startIndex + offset] === segment
|
|
2281
|
+
)
|
|
2282
|
+
);
|
|
2283
|
+
}).map(([configPath, config]) => ({ configPath, config }));
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2286
|
+
// src/api/routing/overrides.ts
|
|
2287
|
+
var ROUTE_ORIGIN_ENV_PREFIX = "ZAPIER_ROUTE_ORIGIN_";
|
|
2288
|
+
function createRoutingConfig({
|
|
2289
|
+
pathConfig: pathConfig2
|
|
2290
|
+
}) {
|
|
2291
|
+
const routeByEnvName = new Map(
|
|
2292
|
+
Object.entries(pathConfig2).filter(([, routeConfig]) => isRouteOverrideEnabled({ routeConfig })).map(([route]) => [encodeRouteOriginEnvName({ route }), route])
|
|
2293
|
+
);
|
|
2294
|
+
return { pathConfig: pathConfig2, routeByEnvName };
|
|
2295
|
+
}
|
|
2296
|
+
function encodeRouteOriginEnvName({ route }) {
|
|
2297
|
+
return `${ROUTE_ORIGIN_ENV_PREFIX}${route.slice(1).split("/").map((segment) => segment.replace(/-/g, "_").toUpperCase()).join("__")}`;
|
|
2298
|
+
}
|
|
2299
|
+
function createRouteOverrideEntry({
|
|
2300
|
+
route,
|
|
2301
|
+
source,
|
|
2302
|
+
sourceReference,
|
|
2303
|
+
origin
|
|
2304
|
+
}) {
|
|
2305
|
+
return {
|
|
2306
|
+
route,
|
|
2307
|
+
source,
|
|
2308
|
+
sourceReference,
|
|
2309
|
+
origin: parseRouteOverrideOrigin({
|
|
2310
|
+
origin,
|
|
2311
|
+
sourceLabel: describeRouteOverrideSource({ source, sourceReference })
|
|
2312
|
+
})
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
function describeRouteOverrideSource({
|
|
2316
|
+
source,
|
|
2317
|
+
sourceReference
|
|
2318
|
+
}) {
|
|
2319
|
+
return source === "environment-variable" ? `environment variable ${sourceReference}` : `routeOverrides[${JSON.stringify(sourceReference)}]`;
|
|
2320
|
+
}
|
|
2321
|
+
function readOptionRouteOverrideEntries({
|
|
2322
|
+
routeOverrides,
|
|
2323
|
+
routingConfig: routingConfig2
|
|
2324
|
+
}) {
|
|
2325
|
+
const entries = [];
|
|
2326
|
+
if (!routeOverrides) {
|
|
2327
|
+
return entries;
|
|
2328
|
+
}
|
|
2329
|
+
for (const [route, origin] of Object.entries(routeOverrides)) {
|
|
2330
|
+
assertSupportedRouteOverride({ route, routingConfig: routingConfig2 });
|
|
2331
|
+
entries.push(
|
|
2332
|
+
createRouteOverrideEntry({
|
|
2333
|
+
route,
|
|
2334
|
+
source: "sdk-option",
|
|
2335
|
+
sourceReference: route,
|
|
2336
|
+
origin
|
|
2337
|
+
})
|
|
2338
|
+
);
|
|
2339
|
+
}
|
|
2340
|
+
return entries;
|
|
2341
|
+
}
|
|
2342
|
+
function buildRouteOverrideMap({
|
|
2343
|
+
environmentEntries,
|
|
2344
|
+
optionEntries
|
|
2345
|
+
}) {
|
|
2346
|
+
const routeOverrideMap = /* @__PURE__ */ new Map();
|
|
2347
|
+
for (const entry of environmentEntries) {
|
|
2348
|
+
routeOverrideMap.set(entry.route, entry);
|
|
2349
|
+
}
|
|
2350
|
+
for (const entry of optionEntries) {
|
|
2351
|
+
routeOverrideMap.set(entry.route, entry);
|
|
2352
|
+
}
|
|
2353
|
+
return routeOverrideMap;
|
|
2354
|
+
}
|
|
2355
|
+
function collectRouteOverrideSources({
|
|
2356
|
+
routingOptions,
|
|
2357
|
+
environment,
|
|
2358
|
+
routingConfig: routingConfig2
|
|
2359
|
+
}) {
|
|
2360
|
+
try {
|
|
2361
|
+
const optionEntries = routingOptions?.routeOverrideEntries ?? [];
|
|
2362
|
+
const environmentEntries = readEnvironmentRouteOverrideEntries({
|
|
2363
|
+
environment,
|
|
2364
|
+
routingConfig: routingConfig2
|
|
2365
|
+
});
|
|
2366
|
+
if (optionEntries.length === 0 && environmentEntries.length === 0) {
|
|
2367
|
+
return void 0;
|
|
2368
|
+
}
|
|
2369
|
+
return { optionEntries, environmentEntries };
|
|
2370
|
+
} catch (error) {
|
|
2371
|
+
if (isZapierError(error) && error.code === "ZAPIER_CONFIGURATION_ERROR") {
|
|
2372
|
+
throw error;
|
|
2373
|
+
}
|
|
2374
|
+
return void 0;
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
function findRouteOverrideMatch({
|
|
2378
|
+
path,
|
|
2379
|
+
routeOverrideMap,
|
|
2380
|
+
routingConfig: routingConfig2
|
|
2381
|
+
}) {
|
|
2382
|
+
let bestMatch;
|
|
2383
|
+
const { pathname } = splitPathReference({ path });
|
|
2384
|
+
for (const override of routeOverrideMap.values()) {
|
|
2385
|
+
const { route } = override;
|
|
2386
|
+
for (const candidate of getRouteCandidates({
|
|
2387
|
+
route,
|
|
2388
|
+
override,
|
|
2389
|
+
routingConfig: routingConfig2
|
|
2390
|
+
})) {
|
|
2391
|
+
if (!pathnameMatchesPrefix({
|
|
2392
|
+
pathname,
|
|
2393
|
+
prefix: candidate.matchedPrefix
|
|
2394
|
+
})) {
|
|
2395
|
+
continue;
|
|
2396
|
+
}
|
|
2397
|
+
if (!bestMatch || compareRouteOverrideMatches(candidate, bestMatch) < 0) {
|
|
2398
|
+
bestMatch = candidate;
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
return bestMatch;
|
|
2403
|
+
}
|
|
2404
|
+
function resolveOverrideRoute({
|
|
2405
|
+
overrideMatch,
|
|
2406
|
+
path
|
|
2407
|
+
}) {
|
|
2408
|
+
const { matchedPrefix, routeConfig, override } = overrideMatch;
|
|
2409
|
+
const directPath = deriveDirectPath({ path, matchedPrefix, routeConfig });
|
|
2410
|
+
return {
|
|
2411
|
+
url: buildRouteOverrideUrl({ origin: override.origin, path: directPath }),
|
|
2412
|
+
pathConfig: routeConfig,
|
|
2413
|
+
canSendDeprecationMessaging: false
|
|
2414
|
+
};
|
|
2415
|
+
}
|
|
2416
|
+
function deriveDirectPath({
|
|
2417
|
+
path,
|
|
2418
|
+
matchedPrefix,
|
|
2419
|
+
routeConfig
|
|
2420
|
+
}) {
|
|
2421
|
+
const { pathPrefix } = routeConfig;
|
|
2422
|
+
if (!pathPrefix) {
|
|
2423
|
+
return path;
|
|
2424
|
+
}
|
|
2425
|
+
const remainingPath = path.slice(matchedPrefix.length) || "/";
|
|
2426
|
+
const override = routeConfig.override;
|
|
2427
|
+
const pathPrefixMode = override?.enabled === false ? "strip" : override?.pathPrefixMode ?? "strip";
|
|
2428
|
+
return pathPrefixMode === "preserve" ? `${pathPrefix}${remainingPath}` : remainingPath;
|
|
2429
|
+
}
|
|
2430
|
+
function readEnvironmentRouteOverrideEntries({
|
|
2431
|
+
environment,
|
|
2432
|
+
routingConfig: routingConfig2
|
|
2433
|
+
}) {
|
|
2434
|
+
const entries = [];
|
|
2435
|
+
if (!environment) {
|
|
2436
|
+
return entries;
|
|
2437
|
+
}
|
|
2438
|
+
for (const [envName, route] of routingConfig2.routeByEnvName) {
|
|
2439
|
+
let value;
|
|
2440
|
+
try {
|
|
2441
|
+
if (!Object.prototype.hasOwnProperty.call(environment, envName)) {
|
|
2442
|
+
continue;
|
|
2443
|
+
}
|
|
2444
|
+
value = environment[envName];
|
|
2445
|
+
} catch {
|
|
2446
|
+
continue;
|
|
2447
|
+
}
|
|
2448
|
+
if (isUnsetEnvironmentValue(value)) {
|
|
2449
|
+
continue;
|
|
2450
|
+
}
|
|
2451
|
+
entries.push(
|
|
2452
|
+
createRouteOverrideEntry({
|
|
2453
|
+
route,
|
|
2454
|
+
source: "environment-variable",
|
|
2455
|
+
sourceReference: envName,
|
|
2456
|
+
origin: value
|
|
2457
|
+
})
|
|
2458
|
+
);
|
|
2459
|
+
}
|
|
2460
|
+
return entries;
|
|
2461
|
+
}
|
|
2462
|
+
function isUnsetEnvironmentValue(value) {
|
|
2463
|
+
if (value === void 0 || value === null) {
|
|
2464
|
+
return true;
|
|
2465
|
+
}
|
|
2466
|
+
return typeof value === "string" && value.trim() === "";
|
|
2467
|
+
}
|
|
2468
|
+
function assertSupportedRouteOverride({
|
|
2469
|
+
route,
|
|
2470
|
+
routingConfig: routingConfig2
|
|
2471
|
+
}) {
|
|
2472
|
+
if (!Object.prototype.hasOwnProperty.call(routingConfig2.pathConfig, route)) {
|
|
2473
|
+
throw new ZapierConfigurationError(
|
|
2474
|
+
`Route override is not supported for ${route}`,
|
|
2475
|
+
{ configType: "routeOverrides" }
|
|
2476
|
+
);
|
|
2477
|
+
}
|
|
2478
|
+
const routeConfig = routingConfig2.pathConfig[route];
|
|
2479
|
+
if (!isRouteOverrideEnabled({ routeConfig })) {
|
|
2480
|
+
throw new ZapierConfigurationError(
|
|
2481
|
+
`Route override is disabled for ${route}`,
|
|
2482
|
+
{ configType: "routeOverrides" }
|
|
2483
|
+
);
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
function parseRouteOverrideOrigin({
|
|
2487
|
+
origin,
|
|
2488
|
+
sourceLabel
|
|
2489
|
+
}) {
|
|
2490
|
+
if (typeof origin !== "string") {
|
|
2491
|
+
throw new ZapierConfigurationError(
|
|
2492
|
+
`Invalid route override origin for ${sourceLabel}`,
|
|
2493
|
+
{ configType: "routeOverrides" }
|
|
2494
|
+
);
|
|
2495
|
+
}
|
|
2496
|
+
let url;
|
|
2497
|
+
try {
|
|
2498
|
+
url = new URL(origin);
|
|
2499
|
+
} catch {
|
|
2500
|
+
throw new ZapierConfigurationError(
|
|
2501
|
+
`Invalid route override origin for ${sourceLabel}`,
|
|
2502
|
+
{ configType: "routeOverrides" }
|
|
2503
|
+
);
|
|
2504
|
+
}
|
|
2505
|
+
const includesOnlyOrigin = url.username === "" && url.password === "" && url.pathname === "/" && url.search === "" && url.hash === "";
|
|
2506
|
+
if (!includesOnlyOrigin) {
|
|
2507
|
+
throw new ZapierConfigurationError(
|
|
2508
|
+
`Invalid route override origin for ${sourceLabel}`,
|
|
2509
|
+
{ configType: "routeOverrides" }
|
|
2510
|
+
);
|
|
2511
|
+
}
|
|
2512
|
+
if (url.protocol === "https:") {
|
|
2513
|
+
return url.origin;
|
|
2514
|
+
}
|
|
2515
|
+
if (url.protocol === "http:" && isLoopbackHost(url.hostname)) {
|
|
2516
|
+
return url.origin;
|
|
2517
|
+
}
|
|
2518
|
+
throw new ZapierConfigurationError(
|
|
2519
|
+
`Invalid route override origin for ${sourceLabel}: expected https, or http on a loopback host`,
|
|
2520
|
+
{ configType: "routeOverrides" }
|
|
2521
|
+
);
|
|
2522
|
+
}
|
|
2523
|
+
function isLoopbackHost(hostname) {
|
|
2524
|
+
return hostname === "localhost" || hostname === "[::1]" || // pii:allow
|
|
2525
|
+
// RFC 6761 reserves .localhost names for loopback.
|
|
2526
|
+
hostname.endsWith(".localhost") || /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(hostname);
|
|
2527
|
+
}
|
|
2528
|
+
function compareRouteOverrideMatches(a, b) {
|
|
2529
|
+
return b.matchedPrefix.length - a.matchedPrefix.length || Number(b.isExactRouteSpelling) - Number(a.isExactRouteSpelling);
|
|
2530
|
+
}
|
|
2531
|
+
function getRouteCandidates({
|
|
2532
|
+
route,
|
|
2533
|
+
override,
|
|
2534
|
+
routingConfig: routingConfig2
|
|
2535
|
+
}) {
|
|
2536
|
+
const routeConfig = routingConfig2.pathConfig[route];
|
|
2537
|
+
if (!routeConfig || !isRouteOverrideEnabled({ routeConfig })) {
|
|
2538
|
+
return [];
|
|
2539
|
+
}
|
|
2540
|
+
const candidates = [
|
|
2541
|
+
{
|
|
2542
|
+
route,
|
|
2543
|
+
matchedPrefix: route,
|
|
2544
|
+
isExactRouteSpelling: true,
|
|
2545
|
+
routeConfig,
|
|
2546
|
+
override
|
|
2547
|
+
}
|
|
2548
|
+
];
|
|
2549
|
+
if (routeConfig.pathPrefix && routeConfig.pathPrefix !== route) {
|
|
2550
|
+
candidates.push({
|
|
2551
|
+
route,
|
|
2552
|
+
matchedPrefix: routeConfig.pathPrefix,
|
|
2553
|
+
isExactRouteSpelling: false,
|
|
2554
|
+
routeConfig,
|
|
2555
|
+
override
|
|
2556
|
+
});
|
|
2557
|
+
}
|
|
2558
|
+
return candidates;
|
|
2559
|
+
}
|
|
2560
|
+
function buildRouteOverrideUrl({
|
|
2561
|
+
origin,
|
|
2562
|
+
path
|
|
2563
|
+
}) {
|
|
2564
|
+
const url = new URL(origin);
|
|
2565
|
+
const { pathname, search, hash } = splitPathReference({ path });
|
|
2566
|
+
url.pathname = pathname;
|
|
2567
|
+
url.search = search;
|
|
2568
|
+
url.hash = hash;
|
|
2569
|
+
return url;
|
|
2570
|
+
}
|
|
2571
|
+
function splitPathReference({ path }) {
|
|
2572
|
+
const hashStart = path.indexOf("#");
|
|
2573
|
+
const pathWithoutHash = hashStart === -1 ? path : path.slice(0, hashStart);
|
|
2574
|
+
const searchStart = pathWithoutHash.indexOf("?");
|
|
2575
|
+
return {
|
|
2576
|
+
pathname: searchStart === -1 ? pathWithoutHash : pathWithoutHash.slice(0, searchStart),
|
|
2577
|
+
search: searchStart === -1 ? "" : pathWithoutHash.slice(searchStart),
|
|
2578
|
+
hash: hashStart === -1 ? "" : path.slice(hashStart)
|
|
2579
|
+
};
|
|
2580
|
+
}
|
|
2581
|
+
function pathnameMatchesPrefix({
|
|
2582
|
+
pathname,
|
|
2583
|
+
prefix
|
|
2584
|
+
}) {
|
|
2585
|
+
return pathname === prefix || pathname.startsWith(`${prefix}/`);
|
|
2586
|
+
}
|
|
2587
|
+
function isRouteOverrideEnabled({
|
|
2588
|
+
routeConfig
|
|
2589
|
+
}) {
|
|
2590
|
+
return routeConfig.override?.enabled !== false;
|
|
2591
|
+
}
|
|
2592
|
+
|
|
2593
|
+
// src/api/routing/index.ts
|
|
2594
|
+
var routingConfig = createRoutingConfig({ pathConfig });
|
|
2595
|
+
function parseRoutingOptions({
|
|
2596
|
+
options
|
|
2597
|
+
}) {
|
|
2598
|
+
try {
|
|
2599
|
+
return {
|
|
2600
|
+
routeOverrideEntries: readOptionRouteOverrideEntries({
|
|
2601
|
+
routeOverrides: options.routeOverrides,
|
|
2602
|
+
routingConfig
|
|
2603
|
+
})
|
|
2604
|
+
};
|
|
2605
|
+
} catch (error) {
|
|
2606
|
+
if (isZapierError(error) && error.code === "ZAPIER_CONFIGURATION_ERROR") {
|
|
2607
|
+
throw error;
|
|
2608
|
+
}
|
|
2609
|
+
throw new ZapierConfigurationError("Failed to read SDK routing options", {
|
|
2610
|
+
configType: "routeOverrides",
|
|
2611
|
+
cause: error
|
|
2612
|
+
});
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
function resolveRoute({
|
|
2616
|
+
path,
|
|
2617
|
+
baseUrl,
|
|
2618
|
+
routingOptions = { routeOverrideEntries: [] },
|
|
2619
|
+
environment,
|
|
2620
|
+
debugLog
|
|
2621
|
+
}) {
|
|
2622
|
+
const overrideSources = collectRouteOverrideSources({
|
|
2623
|
+
routingOptions,
|
|
2624
|
+
environment,
|
|
2625
|
+
routingConfig
|
|
2626
|
+
});
|
|
2627
|
+
if (!overrideSources) {
|
|
2628
|
+
return resolveDefaultRoute({ path, baseUrl });
|
|
2629
|
+
}
|
|
2630
|
+
const routeOverrideMap = buildRouteOverrideMap(overrideSources);
|
|
2631
|
+
const overrideMatch = findRouteOverrideMatch({
|
|
2632
|
+
path,
|
|
2633
|
+
routeOverrideMap,
|
|
2634
|
+
routingConfig
|
|
2635
|
+
});
|
|
2636
|
+
if (overrideMatch) {
|
|
2637
|
+
const resolved = resolveOverrideRoute({ overrideMatch, path });
|
|
2638
|
+
logRouteOverride({ path, resolved, overrideMatch, debugLog });
|
|
2639
|
+
return resolved;
|
|
2640
|
+
}
|
|
2641
|
+
return resolveDefaultRoute({ path, baseUrl });
|
|
2642
|
+
}
|
|
2643
|
+
function logRouteOverride({
|
|
2644
|
+
path,
|
|
2645
|
+
resolved,
|
|
2646
|
+
overrideMatch,
|
|
2647
|
+
debugLog
|
|
2648
|
+
}) {
|
|
2649
|
+
if (!debugLog) {
|
|
2650
|
+
return;
|
|
2651
|
+
}
|
|
2652
|
+
const { route, override } = overrideMatch;
|
|
2653
|
+
const source = describeRouteOverrideSource(override);
|
|
2654
|
+
debugLog(
|
|
2655
|
+
`Route override: ${path} -> ${resolved.url.toString()} (route ${route} via ${source})`
|
|
2656
|
+
);
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2034
2659
|
// src/sdk-version.ts
|
|
2035
|
-
var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.
|
|
2660
|
+
var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.104.0" : void 0) || "unknown";
|
|
2036
2661
|
|
|
2037
2662
|
// src/utils/open-url.ts
|
|
2038
2663
|
var nodePrefix = "node:";
|
|
@@ -2148,7 +2773,6 @@ var PollApprovalResponseSchema = z.object({
|
|
|
2148
2773
|
approval_url: z.string().optional()
|
|
2149
2774
|
});
|
|
2150
2775
|
var APPROVAL_MAX_POLLING_INTERVAL_MILLISECONDS = 5e3;
|
|
2151
|
-
var EPOCH_THRESHOLD_SECONDS = 1e9;
|
|
2152
2776
|
function validateSdkPath(path) {
|
|
2153
2777
|
if (!path.startsWith("/") || path.startsWith("//")) {
|
|
2154
2778
|
throw new ZapierValidationError(
|
|
@@ -2156,146 +2780,17 @@ function validateSdkPath(path) {
|
|
|
2156
2780
|
);
|
|
2157
2781
|
}
|
|
2158
2782
|
}
|
|
2159
|
-
function findPathConfigEntries({
|
|
2160
|
-
path,
|
|
2161
|
-
matchResolvedGatewayPath = false
|
|
2162
|
-
}) {
|
|
2163
|
-
const pathSegments = path.split("/").filter(Boolean);
|
|
2164
|
-
return Object.entries(pathConfig).filter(([configPath, config]) => {
|
|
2165
|
-
if (!matchResolvedGatewayPath) {
|
|
2166
|
-
return path === configPath || path.startsWith(`${configPath}/`);
|
|
2167
|
-
}
|
|
2168
|
-
const prefixSegments = (config.pathPrefix ?? configPath).split("/").filter(Boolean);
|
|
2169
|
-
return pathSegments.some(
|
|
2170
|
-
(_, startIndex) => prefixSegments.every(
|
|
2171
|
-
(segment, offset) => pathSegments[startIndex + offset] === segment
|
|
2172
|
-
)
|
|
2173
|
-
);
|
|
2174
|
-
}).map(([configPath, config]) => ({ configPath, config }));
|
|
2175
|
-
}
|
|
2176
|
-
function parseRateLimitHeaders(response) {
|
|
2177
|
-
const info = {};
|
|
2178
|
-
const retryAfter = response.headers.get("retry-after");
|
|
2179
|
-
if (retryAfter) {
|
|
2180
|
-
const seconds = parseInt(retryAfter, 10);
|
|
2181
|
-
if (!isNaN(seconds)) {
|
|
2182
|
-
info.retryAfterMs = seconds * 1e3;
|
|
2183
|
-
} else {
|
|
2184
|
-
const date = Date.parse(retryAfter);
|
|
2185
|
-
if (!isNaN(date)) {
|
|
2186
|
-
info.retryAfterMs = Math.max(0, date - Date.now());
|
|
2187
|
-
}
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2190
|
-
const reset = response.headers.get("x-ratelimit-reset");
|
|
2191
|
-
if (reset) {
|
|
2192
|
-
const resetValue = parseInt(reset, 10);
|
|
2193
|
-
if (!isNaN(resetValue)) {
|
|
2194
|
-
const isEpoch = resetValue >= EPOCH_THRESHOLD_SECONDS;
|
|
2195
|
-
info.resetMs = isEpoch ? resetValue * 1e3 : Date.now() + resetValue * 1e3;
|
|
2196
|
-
if (info.retryAfterMs === void 0) {
|
|
2197
|
-
info.retryAfterMs = isEpoch ? Math.max(0, info.resetMs - Date.now()) : Math.max(0, resetValue * 1e3);
|
|
2198
|
-
}
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
2201
|
-
const limit = response.headers.get("x-ratelimit-limit");
|
|
2202
|
-
if (limit) {
|
|
2203
|
-
const limitNum = parseInt(limit, 10);
|
|
2204
|
-
if (!isNaN(limitNum)) {
|
|
2205
|
-
info.limit = limitNum;
|
|
2206
|
-
}
|
|
2207
|
-
}
|
|
2208
|
-
const remaining = response.headers.get("x-ratelimit-remaining");
|
|
2209
|
-
if (remaining) {
|
|
2210
|
-
const remainingNum = parseInt(remaining, 10);
|
|
2211
|
-
if (!isNaN(remainingNum)) {
|
|
2212
|
-
info.remaining = remainingNum;
|
|
2213
|
-
}
|
|
2214
|
-
}
|
|
2215
|
-
return info;
|
|
2216
|
-
}
|
|
2217
|
-
var pathConfig = {
|
|
2218
|
-
// e.g. /relay -> https://sdkapi.zapier.com/api/v0/sdk/relay/...
|
|
2219
|
-
"/relay": {
|
|
2220
|
-
authHeader: "X-Relay-Authorization",
|
|
2221
|
-
pathPrefix: "/api/v0/sdk/relay",
|
|
2222
|
-
omitDeprecationMessaging: true
|
|
2223
|
-
},
|
|
2224
|
-
// The concrete gateway form of the relay route. Callers that pass the
|
|
2225
|
-
// already-prefixed path reach the same third-party upstreams, so it must
|
|
2226
|
-
// classify as relay too; without this entry it would match nothing and
|
|
2227
|
-
// sniff deprecation headers off a relay response.
|
|
2228
|
-
"/api/v0/sdk/relay": {
|
|
2229
|
-
omitDeprecationMessaging: true
|
|
2230
|
-
},
|
|
2231
|
-
// Concrete sdkapi routes that do not live behind /api/v0/sdk/<service>.
|
|
2232
|
-
"/api/v0": {},
|
|
2233
|
-
// e.g. /zapier -> https://sdkapi.zapier.com/api/v0/sdk/zapier/...
|
|
2234
|
-
"/zapier": {
|
|
2235
|
-
authHeader: "Authorization",
|
|
2236
|
-
pathPrefix: "/api/v0/sdk/zapier"
|
|
2237
|
-
},
|
|
2238
|
-
// e.g. /tables -> https://sdkapi.zapier.com/api/v0/sdk/tables/...
|
|
2239
|
-
"/tables": {
|
|
2240
|
-
authHeader: "Authorization",
|
|
2241
|
-
pathPrefix: "/api/v0/sdk/tables"
|
|
2242
|
-
},
|
|
2243
|
-
// e.g. /trigger-inbox -> https://sdkapi.zapier.com/api/v0/sdk/trigger-inbox/...
|
|
2244
|
-
"/trigger-inbox": {
|
|
2245
|
-
authHeader: "Authorization",
|
|
2246
|
-
pathPrefix: "/api/v0/sdk/trigger-inbox"
|
|
2247
|
-
},
|
|
2248
|
-
// e.g. /sdkdurableapi -> https://sdkapi.zapier.com/api/v0/sdk/sdkdurableapi/...
|
|
2249
|
-
// sdkapi proxies to the sdkdurableapi backend.
|
|
2250
|
-
"/sdkdurableapi": {
|
|
2251
|
-
authHeader: "Authorization",
|
|
2252
|
-
pathPrefix: "/api/v0/sdk/sdkdurableapi"
|
|
2253
|
-
},
|
|
2254
|
-
// e.g. /durableworkflowzaps -> https://sdkapi.zapier.com/api/v0/sdk/durableworkflowzaps/...
|
|
2255
|
-
// sdkapi proxies to the durableworkflowzaps backend.
|
|
2256
|
-
"/durableworkflowzaps": {
|
|
2257
|
-
authHeader: "Authorization",
|
|
2258
|
-
pathPrefix: "/api/v0/sdk/durableworkflowzaps"
|
|
2259
|
-
},
|
|
2260
|
-
// e.g. /code-substrate-runner -> https://sdkapi.zapier.com/api/v0/sdk/code-substrate-runner/...
|
|
2261
|
-
// sdkapi proxies to the code-substrate-runner backend.
|
|
2262
|
-
"/code-substrate-runner": {
|
|
2263
|
-
authHeader: "Authorization",
|
|
2264
|
-
pathPrefix: "/api/v0/sdk/code-substrate-runner"
|
|
2265
|
-
},
|
|
2266
|
-
// e.g. /code-substrate-workflows -> https://sdkapi.zapier.com/api/v0/sdk/code-substrate-workflows/...
|
|
2267
|
-
// sdkapi proxies to the code-substrate-workflows backend.
|
|
2268
|
-
"/code-substrate-workflows": {
|
|
2269
|
-
authHeader: "Authorization",
|
|
2270
|
-
pathPrefix: "/api/v0/sdk/code-substrate-workflows"
|
|
2271
|
-
},
|
|
2272
|
-
// e.g. /code-substrate-analyzer/validations ->
|
|
2273
|
-
// https://api.zapier.com/code-substrate-analyzer/v0/validations
|
|
2274
|
-
"/code-substrate-analyzer": {
|
|
2275
|
-
authHeader: "Authorization",
|
|
2276
|
-
pathPrefix: "/code-substrate-analyzer/v0",
|
|
2277
|
-
subdomain: "api"
|
|
2278
|
-
},
|
|
2279
|
-
// e.g. /forms/v0/forms -> https://api.zapier.com/forms/v0/forms
|
|
2280
|
-
// The Forms API is registered on the Public API Gateway and has no sdkapi
|
|
2281
|
-
// proxy route, so it goes straight to the gateway. Its governance metadata
|
|
2282
|
-
// rewrites /forms/v0/... to the backend's /api/forms/v0/..., which is why no
|
|
2283
|
-
// pathPrefix is applied here.
|
|
2284
|
-
"/forms": {
|
|
2285
|
-
authHeader: "Authorization",
|
|
2286
|
-
subdomain: "api"
|
|
2287
|
-
}
|
|
2288
|
-
};
|
|
2289
2783
|
var ZapierApiClient = class {
|
|
2290
2784
|
constructor(options) {
|
|
2291
2785
|
this.options = options;
|
|
2292
2786
|
/**
|
|
2293
2787
|
* Perform a request against an already-resolved URL.
|
|
2294
2788
|
*
|
|
2295
|
-
* Does auth
|
|
2296
|
-
*
|
|
2297
|
-
*
|
|
2298
|
-
* path
|
|
2789
|
+
* Does auth and header merging, and converts a terminal 429 into
|
|
2790
|
+
* `ZapierRateLimitError` — the cross-cutting concerns that every
|
|
2791
|
+
* Zapier-bound HTTP call needs and that the transport does not own. Callers
|
|
2792
|
+
* that have a path (e.g. `/relay/...`) should use `rawFetch` instead, which
|
|
2793
|
+
* does path → URL resolution and delegates here.
|
|
2299
2794
|
*
|
|
2300
2795
|
* Exposed as a separate helper so call sites with a server-supplied
|
|
2301
2796
|
* absolute URL (e.g. an approval poll URL) can still share the same
|
|
@@ -2329,47 +2824,30 @@ var ZapierApiClient = class {
|
|
|
2329
2824
|
resource: _resource,
|
|
2330
2825
|
...wireInit
|
|
2331
2826
|
} = fetchInit;
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
});
|
|
2341
|
-
if (response.status !== 429) {
|
|
2342
|
-
return response;
|
|
2343
|
-
}
|
|
2344
|
-
const rateLimitInfo = parseRateLimitHeaders(response);
|
|
2345
|
-
const delayMs = rateLimitInfo.retryAfterMs ?? calculateExponentialBackoffMs(retries + 1);
|
|
2346
|
-
if (delayMs > this.maxNetworkRetryDelayMilliseconds || retries >= this.maxNetworkRetries) {
|
|
2347
|
-
throw new ZapierRateLimitError(
|
|
2348
|
-
await this.readRateLimitErrorMessage(response),
|
|
2349
|
-
{
|
|
2350
|
-
statusCode: 429,
|
|
2351
|
-
rateLimit: rateLimitInfo,
|
|
2352
|
-
retries
|
|
2353
|
-
}
|
|
2354
|
-
);
|
|
2355
|
-
}
|
|
2356
|
-
retries++;
|
|
2357
|
-
this.emitEvent("api:rate_limit_retry", {
|
|
2358
|
-
retry: retries,
|
|
2359
|
-
maxNetworkRetries: this.maxNetworkRetries,
|
|
2360
|
-
delayMs,
|
|
2361
|
-
path: url,
|
|
2362
|
-
method: init?.method ?? "GET",
|
|
2363
|
-
rateLimit: rateLimitInfo
|
|
2364
|
-
});
|
|
2365
|
-
await sleep(delayMs, init?.signal ?? void 0);
|
|
2827
|
+
const request = {
|
|
2828
|
+
...wireInit,
|
|
2829
|
+
url,
|
|
2830
|
+
headers: Object.fromEntries(mergedHeaders)
|
|
2831
|
+
};
|
|
2832
|
+
const response = await this.options.sendHttpRequest(request);
|
|
2833
|
+
if (response.status !== 429) {
|
|
2834
|
+
return response;
|
|
2366
2835
|
}
|
|
2836
|
+
throw new ZapierRateLimitError(
|
|
2837
|
+
await this.readRateLimitErrorMessage(response),
|
|
2838
|
+
{
|
|
2839
|
+
statusCode: 429,
|
|
2840
|
+
rateLimit: parseRateLimitHeaders(response),
|
|
2841
|
+
retries: retriesFor(request)
|
|
2842
|
+
}
|
|
2843
|
+
);
|
|
2367
2844
|
};
|
|
2368
2845
|
/**
|
|
2369
2846
|
* Wrap an outbound HTTP call with the concurrency semaphore. Used by both
|
|
2370
2847
|
* `rawFetch` (path-based) and the approval-poll path (absolute URL); each
|
|
2371
|
-
* caller acquires per
|
|
2372
|
-
*
|
|
2848
|
+
* caller acquires per request, so the transport's retry sleeps are held
|
|
2849
|
+
* inside the permit but the gap between approval polls and the
|
|
2850
|
+
* human-approval wait are not.
|
|
2373
2851
|
*
|
|
2374
2852
|
* The release is registered in a finally that wraps the entire post-
|
|
2375
2853
|
* acquire flow — including the `wait_end` event emission — so a throwing
|
|
@@ -2619,8 +3097,6 @@ var ZapierApiClient = class {
|
|
|
2619
3097
|
signal: options.signal
|
|
2620
3098
|
});
|
|
2621
3099
|
};
|
|
2622
|
-
this.maxNetworkRetries = options.maxNetworkRetries ?? ZAPIER_MAX_NETWORK_RETRIES;
|
|
2623
|
-
this.maxNetworkRetryDelayMilliseconds = options.maxNetworkRetryDelayMilliseconds ?? options.maxNetworkRetryDelayMs ?? ZAPIER_MAX_NETWORK_RETRY_DELAY_MILLISECONDS;
|
|
2624
3100
|
const requested = options.maxConcurrentRequests;
|
|
2625
3101
|
const limit = requested === void 0 || Number.isNaN(requested) ? ZAPIER_MAX_CONCURRENT_REQUESTS : requested;
|
|
2626
3102
|
if (limit !== Infinity && (!Number.isInteger(limit) || limit < 1 || limit > MAX_CONCURRENCY_LIMIT)) {
|
|
@@ -2830,43 +3306,13 @@ var ZapierApiClient = class {
|
|
|
2830
3306
|
}
|
|
2831
3307
|
// Apply any special routing logic for configured paths.
|
|
2832
3308
|
applyPathConfiguration(path) {
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
const deprecationPathMatches = [
|
|
2841
|
-
...matchingPathEntries,
|
|
2842
|
-
...resolvedPathEntries
|
|
2843
|
-
];
|
|
2844
|
-
const canSendDeprecationMessaging = deprecationPathMatches.length > 0 && deprecationPathMatches.every(
|
|
2845
|
-
({ config }) => config.omitDeprecationMessaging !== true
|
|
2846
|
-
);
|
|
2847
|
-
return {
|
|
2848
|
-
url: url2,
|
|
2849
|
-
pathConfig: routingMatch?.config,
|
|
2850
|
-
canSendDeprecationMessaging
|
|
2851
|
-
};
|
|
2852
|
-
};
|
|
2853
|
-
let finalPath = path;
|
|
2854
|
-
if (routingMatch?.config.pathPrefix) {
|
|
2855
|
-
const pathWithoutPrefix = path.slice(routingMatch.configPath.length) || "/";
|
|
2856
|
-
finalPath = `${routingMatch.config.pathPrefix}${pathWithoutPrefix}`;
|
|
2857
|
-
}
|
|
2858
|
-
const zapierBaseUrl = getZapierBaseUrl(this.options.baseUrl);
|
|
2859
|
-
if (zapierBaseUrl === this.options.baseUrl.replace(/\/$/, "")) {
|
|
2860
|
-
const originalBaseUrl = new URL(this.options.baseUrl);
|
|
2861
|
-
const subdomain = routingMatch?.config.subdomain ?? "sdkapi";
|
|
2862
|
-
const finalBaseUrl = `https://${subdomain}.${originalBaseUrl.hostname}`;
|
|
2863
|
-
const url2 = new URL(finalPath, finalBaseUrl);
|
|
2864
|
-
return buildResult(url2);
|
|
2865
|
-
}
|
|
2866
|
-
const baseUrl = new URL(this.options.baseUrl);
|
|
2867
|
-
const basePath = baseUrl.pathname.replace(/\/$/, "");
|
|
2868
|
-
const url = new URL(basePath + finalPath, baseUrl.origin);
|
|
2869
|
-
return buildResult(url);
|
|
3309
|
+
return resolveRoute({
|
|
3310
|
+
path,
|
|
3311
|
+
baseUrl: this.options.baseUrl,
|
|
3312
|
+
routingOptions: this.options.routingOptions,
|
|
3313
|
+
environment: globalThis.process?.env,
|
|
3314
|
+
debugLog: this.options.debugLog
|
|
3315
|
+
});
|
|
2870
3316
|
}
|
|
2871
3317
|
// Helper to build full URLs and return routing info
|
|
2872
3318
|
buildUrl(path, searchParams) {
|
|
@@ -3395,6 +3841,7 @@ var ZapierApiClient = class {
|
|
|
3395
3841
|
};
|
|
3396
3842
|
var createZapierApi = (options) => {
|
|
3397
3843
|
const { debug = false, fetch: originalFetch = globalThis.fetch } = options;
|
|
3844
|
+
const routingOptions = parseRoutingOptions({ options });
|
|
3398
3845
|
const debugLog = createDebugLogger(debug);
|
|
3399
3846
|
const debugFetch = createDebugFetch({ originalFetch, debugLog });
|
|
3400
3847
|
return new ZapierApiClient({
|
|
@@ -3405,7 +3852,15 @@ var createZapierApi = (options) => {
|
|
|
3405
3852
|
fetch: debugFetch,
|
|
3406
3853
|
// Built from the caller's own `fetch`, not `debugFetch`: the pipeline wraps
|
|
3407
3854
|
// for debug itself, and passing the wrapped one would log twice.
|
|
3408
|
-
sendHttpRequest: options.sendHttpRequest ?? createZapierSendHttpRequest({
|
|
3855
|
+
sendHttpRequest: options.sendHttpRequest ?? createZapierSendHttpRequest({
|
|
3856
|
+
fetch: options.fetch,
|
|
3857
|
+
debug,
|
|
3858
|
+
onEvent: options.onEvent,
|
|
3859
|
+
maxNetworkRetries: options.maxNetworkRetries,
|
|
3860
|
+
maxNetworkRetryDelayMilliseconds: options.maxNetworkRetryDelayMilliseconds ?? options.maxNetworkRetryDelayMs
|
|
3861
|
+
}),
|
|
3862
|
+
debugLog,
|
|
3863
|
+
routingOptions
|
|
3409
3864
|
});
|
|
3410
3865
|
};
|
|
3411
3866
|
|
|
@@ -3442,10 +3897,30 @@ function getOrCreateApiClient(config) {
|
|
|
3442
3897
|
callerPackage
|
|
3443
3898
|
});
|
|
3444
3899
|
}
|
|
3900
|
+
var retryHttpRequestOptionsPlugin = defineProperty({
|
|
3901
|
+
namespace: "kitcore",
|
|
3902
|
+
name: "retryHttpRequestOptions",
|
|
3903
|
+
imports: [sdkOptionsPluginRef],
|
|
3904
|
+
setup: ({ imports }) => resolveRetryHttpRequestOptions({
|
|
3905
|
+
maxNetworkRetries: imports.sdkOptions?.maxNetworkRetries,
|
|
3906
|
+
maxNetworkRetryDelayMilliseconds: resolveNetworkRetryDelayMilliseconds(
|
|
3907
|
+
imports.sdkOptions ?? {}
|
|
3908
|
+
),
|
|
3909
|
+
onEvent: imports.sdkOptions?.onEvent
|
|
3910
|
+
}),
|
|
3911
|
+
get: ({ state }) => state
|
|
3912
|
+
});
|
|
3913
|
+
|
|
3914
|
+
// src/plugins/transport/index.ts
|
|
3445
3915
|
var zapierHttpTransportPlugin = definePlugin({
|
|
3446
3916
|
namespace: "zapier",
|
|
3447
3917
|
name: "httpTransport",
|
|
3448
|
-
imports: [
|
|
3918
|
+
imports: [
|
|
3919
|
+
sendHttpRequestPlugin,
|
|
3920
|
+
retryHttpRequestPlugin,
|
|
3921
|
+
retryHttpRequestOptionsPlugin,
|
|
3922
|
+
httpFetchPlugin
|
|
3923
|
+
],
|
|
3449
3924
|
exports: [sendHttpRequestPlugin]
|
|
3450
3925
|
});
|
|
3451
3926
|
|
|
@@ -3494,7 +3969,8 @@ var apiPlugin = defineProperty({
|
|
|
3494
3969
|
maxApprovalRetries,
|
|
3495
3970
|
approvalMode,
|
|
3496
3971
|
openAutoModeApprovalsInBrowser,
|
|
3497
|
-
callerPackage
|
|
3972
|
+
callerPackage,
|
|
3973
|
+
routeOverrides
|
|
3498
3974
|
} = imports.sdkOptions ?? {};
|
|
3499
3975
|
return createZapierApi({
|
|
3500
3976
|
baseUrl,
|
|
@@ -3504,13 +3980,17 @@ var apiPlugin = defineProperty({
|
|
|
3504
3980
|
fetch: customFetch,
|
|
3505
3981
|
onEvent,
|
|
3506
3982
|
maxNetworkRetries,
|
|
3507
|
-
maxNetworkRetryDelayMilliseconds: (
|
|
3983
|
+
maxNetworkRetryDelayMilliseconds: resolveNetworkRetryDelayMilliseconds({
|
|
3984
|
+
maxNetworkRetryDelaySeconds,
|
|
3985
|
+
maxNetworkRetryDelayMs
|
|
3986
|
+
}) ?? ZAPIER_MAX_NETWORK_RETRY_DELAY_MILLISECONDS,
|
|
3508
3987
|
maxConcurrentRequests,
|
|
3509
3988
|
approvalTimeoutMilliseconds: approvalTimeoutSeconds != null ? approvalTimeoutSeconds * 1e3 : approvalTimeoutMs,
|
|
3510
3989
|
maxApprovalRetries,
|
|
3511
3990
|
approvalMode,
|
|
3512
3991
|
openAutoModeApprovalsInBrowser,
|
|
3513
3992
|
callerPackage,
|
|
3993
|
+
routeOverrides,
|
|
3514
3994
|
// Inject the graph-composed transport so host `dispatchHttpRequest` wraps
|
|
3515
3995
|
// apply.
|
|
3516
3996
|
sendHttpRequest: imports.sendHttpRequest
|
|
@@ -11905,19 +12385,23 @@ var BaseSdkOptionsSchema = z.object({
|
|
|
11905
12385
|
),
|
|
11906
12386
|
debug: z.boolean().optional().describe("Enable debug logging."),
|
|
11907
12387
|
baseUrl: z.string().optional().describe("Base URL for Zapier API endpoints.").meta({ valueHint: "url" }),
|
|
12388
|
+
routeOverrides: z.record(z.string(), z.string()).optional().describe("Maps SDK route prefixes to direct origins.").meta({ internal: true }),
|
|
11908
12389
|
trackingBaseUrl: z.string().optional().describe("Base URL for Zapier tracking endpoints.").meta({ valueHint: "url" }),
|
|
11909
12390
|
/**
|
|
11910
|
-
* Maximum number of retries for rate-limited requests (429 responses)
|
|
12391
|
+
* Maximum number of retries for rate-limited requests (429 responses) and,
|
|
12392
|
+
* on idempotent methods, retryable server errors (500, 502, 503, 504).
|
|
11911
12393
|
* Set to 0 to disable retries. Default is 3.
|
|
11912
12394
|
*/
|
|
11913
|
-
maxNetworkRetries: z.number().optional().describe(
|
|
12395
|
+
maxNetworkRetries: z.number().optional().describe(
|
|
12396
|
+
"Max retries for rate-limited and server-error responses (default: 3)."
|
|
12397
|
+
).meta({ valueHint: "count" }),
|
|
11914
12398
|
/**
|
|
11915
|
-
* Maximum delay in seconds to wait
|
|
12399
|
+
* Maximum delay in seconds to wait between network retries.
|
|
11916
12400
|
* If the server requests a longer delay, the request fails immediately.
|
|
11917
12401
|
* Default is 60 (60 seconds).
|
|
11918
12402
|
*/
|
|
11919
12403
|
maxNetworkRetryDelaySeconds: z.number().optional().describe(
|
|
11920
|
-
"Max delay in seconds to wait
|
|
12404
|
+
"Max delay in seconds to wait between network retries (default: 60)."
|
|
11921
12405
|
).meta({ valueHint: "seconds" }),
|
|
11922
12406
|
/** @deprecated Use `maxNetworkRetryDelaySeconds` instead. */
|
|
11923
12407
|
maxNetworkRetryDelayMs: z.number().optional().describe("Max delay in ms to wait for retry (default: 60000).").meta({ valueHint: "ms", deprecated: true }),
|