@zapier/zapier-sdk 0.50.0 → 0.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +2 -1
- package/dist/api/auth.d.ts +1 -6
- package/dist/api/auth.d.ts.map +1 -1
- package/dist/api/auth.js +34 -27
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +87 -9
- package/dist/api/concurrency.d.ts +28 -0
- package/dist/api/concurrency.d.ts.map +1 -0
- package/dist/api/concurrency.js +90 -0
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +1 -1
- package/dist/api/schemas.d.ts +3 -3
- package/dist/api/types.d.ts +6 -0
- package/dist/api/types.d.ts.map +1 -1
- package/dist/auth.d.ts +13 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +95 -11
- package/dist/constants.d.ts +16 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +29 -0
- package/dist/experimental.cjs +357 -34
- package/dist/experimental.d.mts +28 -28
- package/dist/experimental.d.ts +26 -26
- package/dist/experimental.mjs +353 -35
- package/dist/{index-BQ2ii0Bs.d.mts → index-DcdtPei-.d.mts} +132 -2
- package/dist/{index-BQ2ii0Bs.d.ts → index-DcdtPei-.d.ts} +132 -2
- package/dist/index.cjs +357 -34
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.mjs +353 -35
- package/dist/plugins/api/index.d.ts.map +1 -1
- package/dist/plugins/api/index.js +3 -2
- package/dist/plugins/apps/index.d.ts +2 -2
- package/dist/plugins/deprecated/inputFields.d.ts +18 -18
- package/dist/plugins/getAction/index.d.ts +6 -6
- package/dist/plugins/getAction/schemas.d.ts +4 -4
- package/dist/plugins/getActionInputFieldsSchema/index.d.ts +5 -5
- package/dist/plugins/getActionInputFieldsSchema/schemas.d.ts +4 -4
- package/dist/plugins/listActionInputFieldChoices/index.d.ts +5 -5
- package/dist/plugins/listActionInputFieldChoices/schemas.d.ts +4 -4
- package/dist/plugins/listActionInputFields/index.d.ts +5 -5
- package/dist/plugins/listActionInputFields/schemas.d.ts +4 -4
- package/dist/plugins/listActions/index.d.ts +3 -3
- package/dist/plugins/listActions/schemas.d.ts +4 -4
- package/dist/plugins/runAction/index.d.ts +5 -5
- package/dist/plugins/runAction/schemas.d.ts +4 -4
- package/dist/plugins/triggers/getTriggerInputFieldsSchema/index.d.ts +2 -2
- package/dist/plugins/triggers/listTriggerInputFieldChoices/index.d.ts +2 -2
- package/dist/plugins/triggers/listTriggerInputFields/index.d.ts +2 -2
- package/dist/schemas/Action.d.ts +1 -1
- package/dist/sdk.d.ts +52 -52
- package/dist/types/properties.d.ts +1 -1
- package/dist/types/sdk.d.ts +1 -0
- package/dist/types/sdk.d.ts.map +1 -1
- package/dist/types/sdk.js +25 -0
- package/dist/utils/telemetry.d.ts +11 -0
- package/dist/utils/telemetry.d.ts.map +1 -0
- package/dist/utils/telemetry.js +19 -0
- package/package.json +1 -1
package/dist/experimental.mjs
CHANGED
|
@@ -148,6 +148,21 @@ function parseIntEnvVar(name) {
|
|
|
148
148
|
}
|
|
149
149
|
var ZAPIER_MAX_NETWORK_RETRIES = parseIntEnvVar("ZAPIER_MAX_NETWORK_RETRIES") ?? 3;
|
|
150
150
|
var ZAPIER_MAX_NETWORK_RETRY_DELAY_MS = parseIntEnvVar("ZAPIER_MAX_NETWORK_RETRY_DELAY_MS") ?? 6e4;
|
|
151
|
+
var MAX_CONCURRENCY_LIMIT = 1e4;
|
|
152
|
+
function parseConcurrencyEnvVar(name) {
|
|
153
|
+
const value = globalThis.process?.env?.[name];
|
|
154
|
+
if (!value) return void 0;
|
|
155
|
+
if (value === "Infinity") return Infinity;
|
|
156
|
+
if (/^[1-9]\d*$/.test(value)) {
|
|
157
|
+
const parsed = parseInt(value, 10);
|
|
158
|
+
if (parsed <= MAX_CONCURRENCY_LIMIT) return parsed;
|
|
159
|
+
}
|
|
160
|
+
console.warn(
|
|
161
|
+
`[zapier-sdk] Invalid value for ${name}: "${value}" (expected positive integer 1-${MAX_CONCURRENCY_LIMIT} or "Infinity")`
|
|
162
|
+
);
|
|
163
|
+
return void 0;
|
|
164
|
+
}
|
|
165
|
+
var ZAPIER_MAX_CONCURRENT_REQUESTS = parseConcurrencyEnvVar("ZAPIER_MAX_CONCURRENT_REQUESTS") ?? 200;
|
|
151
166
|
function getZapierApprovalMode() {
|
|
152
167
|
const value = globalThis.process?.env?.ZAPIER_APPROVAL_MODE;
|
|
153
168
|
if (value === "disabled" || value === "poll" || value === "throw")
|
|
@@ -1834,33 +1849,40 @@ function getAuthorizationHeader(token) {
|
|
|
1834
1849
|
}
|
|
1835
1850
|
return `Bearer ${token}`;
|
|
1836
1851
|
}
|
|
1837
|
-
function
|
|
1852
|
+
function readJwtPayload(token) {
|
|
1838
1853
|
const parts = parseJwt(token);
|
|
1839
|
-
if (!parts)
|
|
1840
|
-
|
|
1841
|
-
}
|
|
1854
|
+
if (!parts) return null;
|
|
1855
|
+
let payload;
|
|
1842
1856
|
try {
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1857
|
+
payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf-8"));
|
|
1858
|
+
} catch {
|
|
1859
|
+
return null;
|
|
1860
|
+
}
|
|
1861
|
+
if (payload["sub_type"] === "service" && typeof payload["njwt"] === "string") {
|
|
1862
|
+
const nestedParts = parseJwt(payload["njwt"]);
|
|
1863
|
+
if (nestedParts) {
|
|
1864
|
+
try {
|
|
1865
|
+
return JSON.parse(
|
|
1851
1866
|
Buffer.from(nestedParts[1], "base64url").toString("utf-8")
|
|
1852
1867
|
);
|
|
1868
|
+
} catch {
|
|
1853
1869
|
}
|
|
1854
1870
|
}
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
} catch {
|
|
1871
|
+
}
|
|
1872
|
+
return payload;
|
|
1873
|
+
}
|
|
1874
|
+
function extractUserIdsFromJwt(token) {
|
|
1875
|
+
const payload = readJwtPayload(token);
|
|
1876
|
+
if (!payload) {
|
|
1862
1877
|
return { customuser_id: null, account_id: null };
|
|
1863
1878
|
}
|
|
1879
|
+
const accRaw = payload["zap:acc"];
|
|
1880
|
+
const accountId = accRaw != null ? parseInt(String(accRaw), 10) : null;
|
|
1881
|
+
const customUserId = payload["sub_type"] === "customuser" && payload["sub"] != null ? parseInt(String(payload["sub"]), 10) : null;
|
|
1882
|
+
return {
|
|
1883
|
+
customuser_id: customUserId !== null && !isNaN(customUserId) ? customUserId : null,
|
|
1884
|
+
account_id: accountId !== null && !isNaN(accountId) ? accountId : null
|
|
1885
|
+
};
|
|
1864
1886
|
}
|
|
1865
1887
|
|
|
1866
1888
|
// src/api/debug.ts
|
|
@@ -2168,6 +2190,83 @@ async function pollUntilComplete(options) {
|
|
|
2168
2190
|
}
|
|
2169
2191
|
}
|
|
2170
2192
|
}
|
|
2193
|
+
|
|
2194
|
+
// src/api/concurrency.ts
|
|
2195
|
+
var NO_OP_RELEASE = () => {
|
|
2196
|
+
};
|
|
2197
|
+
var NO_OP_SEMAPHORE = {
|
|
2198
|
+
acquire: async () => NO_OP_RELEASE,
|
|
2199
|
+
tryAcquire: () => NO_OP_RELEASE
|
|
2200
|
+
};
|
|
2201
|
+
function createSemaphore(maxPermits) {
|
|
2202
|
+
if (maxPermits === Infinity) {
|
|
2203
|
+
return NO_OP_SEMAPHORE;
|
|
2204
|
+
}
|
|
2205
|
+
if (!Number.isInteger(maxPermits) || maxPermits <= 0) {
|
|
2206
|
+
throw new Error(
|
|
2207
|
+
`maxPermits must be a positive integer or Infinity, got: ${maxPermits}`
|
|
2208
|
+
);
|
|
2209
|
+
}
|
|
2210
|
+
let permits = maxPermits;
|
|
2211
|
+
const waiters = [];
|
|
2212
|
+
const release = () => {
|
|
2213
|
+
const next = waiters.shift();
|
|
2214
|
+
if (next) {
|
|
2215
|
+
next.grant();
|
|
2216
|
+
} else {
|
|
2217
|
+
permits++;
|
|
2218
|
+
}
|
|
2219
|
+
};
|
|
2220
|
+
const makeReleaseOnce = () => {
|
|
2221
|
+
let released = false;
|
|
2222
|
+
return () => {
|
|
2223
|
+
if (released) return;
|
|
2224
|
+
released = true;
|
|
2225
|
+
release();
|
|
2226
|
+
};
|
|
2227
|
+
};
|
|
2228
|
+
return {
|
|
2229
|
+
tryAcquire() {
|
|
2230
|
+
if (permits > 0) {
|
|
2231
|
+
permits--;
|
|
2232
|
+
return makeReleaseOnce();
|
|
2233
|
+
}
|
|
2234
|
+
return null;
|
|
2235
|
+
},
|
|
2236
|
+
async acquire(signal) {
|
|
2237
|
+
if (signal?.aborted) {
|
|
2238
|
+
throw signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
2239
|
+
}
|
|
2240
|
+
if (permits > 0) {
|
|
2241
|
+
permits--;
|
|
2242
|
+
return makeReleaseOnce();
|
|
2243
|
+
}
|
|
2244
|
+
return new Promise((resolve2, reject) => {
|
|
2245
|
+
const onAbort = () => {
|
|
2246
|
+
const idx = waiters.indexOf(waiter);
|
|
2247
|
+
if (idx !== -1) {
|
|
2248
|
+
waiters.splice(idx, 1);
|
|
2249
|
+
waiter.cancel(
|
|
2250
|
+
signal?.reason ?? new DOMException("Aborted", "AbortError")
|
|
2251
|
+
);
|
|
2252
|
+
}
|
|
2253
|
+
};
|
|
2254
|
+
const waiter = {
|
|
2255
|
+
grant: () => {
|
|
2256
|
+
signal?.removeEventListener("abort", onAbort);
|
|
2257
|
+
resolve2(makeReleaseOnce());
|
|
2258
|
+
},
|
|
2259
|
+
cancel: (reason) => {
|
|
2260
|
+
signal?.removeEventListener("abort", onAbort);
|
|
2261
|
+
reject(reason);
|
|
2262
|
+
}
|
|
2263
|
+
};
|
|
2264
|
+
signal?.addEventListener("abort", onAbort);
|
|
2265
|
+
waiters.push(waiter);
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2268
|
+
};
|
|
2269
|
+
}
|
|
2171
2270
|
var ClientCredentialsObjectSchema = z.object({
|
|
2172
2271
|
type: z.enum(["client_credentials"]).optional().meta({ internal: true }),
|
|
2173
2272
|
clientId: z.string().describe("OAuth client ID for authentication.").meta({ valueHint: "id" }),
|
|
@@ -2209,6 +2308,19 @@ function isCredentialsFunction(credentials) {
|
|
|
2209
2308
|
return typeof credentials === "function";
|
|
2210
2309
|
}
|
|
2211
2310
|
|
|
2311
|
+
// src/utils/telemetry.ts
|
|
2312
|
+
var emittedOnce = /* @__PURE__ */ new WeakMap();
|
|
2313
|
+
function emitOnce(onEvent, event) {
|
|
2314
|
+
if (!emittedOnce.has(onEvent)) {
|
|
2315
|
+
emittedOnce.set(onEvent, /* @__PURE__ */ new Set());
|
|
2316
|
+
}
|
|
2317
|
+
const fired = emittedOnce.get(onEvent);
|
|
2318
|
+
if (!fired.has(event.type)) {
|
|
2319
|
+
fired.add(event.type);
|
|
2320
|
+
onEvent(event);
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2212
2324
|
// src/utils/url-utils.ts
|
|
2213
2325
|
function getZapierBaseUrl(baseUrl) {
|
|
2214
2326
|
if (!baseUrl) {
|
|
@@ -2431,8 +2543,10 @@ async function resolveCache(options) {
|
|
|
2431
2543
|
if (cliLogin?.createCache) {
|
|
2432
2544
|
try {
|
|
2433
2545
|
const cache = cliLogin.createCache();
|
|
2434
|
-
|
|
2435
|
-
|
|
2546
|
+
if (cache) {
|
|
2547
|
+
cachedDefaultCache = cache;
|
|
2548
|
+
return cache;
|
|
2549
|
+
}
|
|
2436
2550
|
} catch {
|
|
2437
2551
|
}
|
|
2438
2552
|
}
|
|
@@ -2444,6 +2558,11 @@ function entryIsValid(entry) {
|
|
|
2444
2558
|
if (entry.expiresAt === void 0) return true;
|
|
2445
2559
|
return entry.expiresAt > Date.now() + TOKEN_EXPIRATION_BUFFER_MS;
|
|
2446
2560
|
}
|
|
2561
|
+
async function readCachedToken(cacheKey, cache) {
|
|
2562
|
+
const cached = await cache.get(cacheKey);
|
|
2563
|
+
if (cached && entryIsValid(cached)) return cached.value;
|
|
2564
|
+
return void 0;
|
|
2565
|
+
}
|
|
2447
2566
|
async function invalidateCachedToken(options) {
|
|
2448
2567
|
const cacheKey = buildCacheKey(options);
|
|
2449
2568
|
pendingExchanges.delete(cacheKey);
|
|
@@ -2557,11 +2676,76 @@ function isCliLoginAvailable() {
|
|
|
2557
2676
|
if (cachedCliLogin === void 0) return void 0;
|
|
2558
2677
|
return cachedCliLogin !== false;
|
|
2559
2678
|
}
|
|
2679
|
+
function emitAuthResolved(onEvent, mechanism) {
|
|
2680
|
+
if (onEvent) {
|
|
2681
|
+
emitOnce(onEvent, {
|
|
2682
|
+
type: "auth_resolved",
|
|
2683
|
+
payload: { mechanism },
|
|
2684
|
+
timestamp: Date.now()
|
|
2685
|
+
});
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
async function getActiveCredentialsFromCli(baseUrl) {
|
|
2689
|
+
const cliLogin = await getCliLogin();
|
|
2690
|
+
return cliLogin?.getActiveCredentials?.({ baseUrl });
|
|
2691
|
+
}
|
|
2692
|
+
async function getStoredClientCredentialsFromCli(baseUrl) {
|
|
2693
|
+
const cliLogin = await getCliLogin();
|
|
2694
|
+
return cliLogin?.getStoredClientCredentials?.({ baseUrl });
|
|
2695
|
+
}
|
|
2560
2696
|
async function getTokenFromCliLogin(options) {
|
|
2561
2697
|
const cliLogin = await getCliLogin();
|
|
2562
2698
|
if (!cliLogin) return void 0;
|
|
2563
2699
|
return await cliLogin.getToken(options);
|
|
2564
2700
|
}
|
|
2701
|
+
async function tryStoredClientCredentialToken(options) {
|
|
2702
|
+
const activeCredential = await getActiveCredentialsFromCli(options.baseUrl);
|
|
2703
|
+
if (!activeCredential) return void 0;
|
|
2704
|
+
const resolvedBaseUrl = activeCredential.baseUrl || options.baseUrl || DEFAULT_AUTH_BASE_URL;
|
|
2705
|
+
const mergedScopes = mergeScopes(
|
|
2706
|
+
activeCredential.scopes.join(" "),
|
|
2707
|
+
options.requiredScopes
|
|
2708
|
+
);
|
|
2709
|
+
const cacheKey = buildCacheKey({
|
|
2710
|
+
clientId: activeCredential.clientId,
|
|
2711
|
+
scopes: mergedScopes,
|
|
2712
|
+
baseUrl: resolvedBaseUrl
|
|
2713
|
+
});
|
|
2714
|
+
const cache = await resolveCache(options);
|
|
2715
|
+
const pending = pendingExchanges.get(cacheKey);
|
|
2716
|
+
if (pending) return pending;
|
|
2717
|
+
const cached = await readCachedToken(cacheKey, cache);
|
|
2718
|
+
if (cached !== void 0) {
|
|
2719
|
+
if (options.debug)
|
|
2720
|
+
console.log(
|
|
2721
|
+
`[auth] Using cached token (clientId: ${activeCredential.clientId})`
|
|
2722
|
+
);
|
|
2723
|
+
emitAuthResolved(options.onEvent, "client_credentials");
|
|
2724
|
+
return cached;
|
|
2725
|
+
}
|
|
2726
|
+
const storedCredential = await getStoredClientCredentialsFromCli(resolvedBaseUrl);
|
|
2727
|
+
if (!storedCredential) {
|
|
2728
|
+
await invalidateCachedToken({
|
|
2729
|
+
clientId: activeCredential.clientId,
|
|
2730
|
+
scopes: activeCredential.scopes,
|
|
2731
|
+
baseUrl: resolvedBaseUrl,
|
|
2732
|
+
cache: options.cache
|
|
2733
|
+
});
|
|
2734
|
+
throw new ZapierAuthenticationError(
|
|
2735
|
+
`Stored client credential is missing its secret (clientId: ${activeCredential.clientId}). Run \`zapier-sdk login\` to recreate it.`
|
|
2736
|
+
);
|
|
2737
|
+
}
|
|
2738
|
+
if (options.debug)
|
|
2739
|
+
console.log(
|
|
2740
|
+
`[auth] Using stored client credential (clientId: ${storedCredential.clientId})`
|
|
2741
|
+
);
|
|
2742
|
+
const token = await resolveAuthTokenFromCredentials(
|
|
2743
|
+
storedCredential,
|
|
2744
|
+
options
|
|
2745
|
+
);
|
|
2746
|
+
emitAuthResolved(options.onEvent, "client_credentials");
|
|
2747
|
+
return token;
|
|
2748
|
+
}
|
|
2565
2749
|
async function resolveAuthToken(options = {}) {
|
|
2566
2750
|
const credentials = await resolveCredentials({
|
|
2567
2751
|
credentials: options.credentials,
|
|
@@ -2571,14 +2755,24 @@ async function resolveAuthToken(options = {}) {
|
|
|
2571
2755
|
if (credentials !== void 0) {
|
|
2572
2756
|
return resolveAuthTokenFromCredentials(credentials, options);
|
|
2573
2757
|
}
|
|
2574
|
-
|
|
2758
|
+
const storedToken = await tryStoredClientCredentialToken(options);
|
|
2759
|
+
if (storedToken !== void 0) return storedToken;
|
|
2760
|
+
if (options.debug) {
|
|
2761
|
+
console.log("[auth] Using JWT (no stored client credential found)");
|
|
2762
|
+
}
|
|
2763
|
+
const jwtToken = await getTokenFromCliLogin({
|
|
2575
2764
|
onEvent: options.onEvent,
|
|
2576
2765
|
fetch: options.fetch,
|
|
2577
2766
|
debug: options.debug
|
|
2578
2767
|
});
|
|
2768
|
+
if (jwtToken !== void 0) {
|
|
2769
|
+
emitAuthResolved(options.onEvent, "jwt");
|
|
2770
|
+
}
|
|
2771
|
+
return jwtToken;
|
|
2579
2772
|
}
|
|
2580
2773
|
async function resolveAuthTokenFromCredentials(credentials, options) {
|
|
2581
2774
|
if (typeof credentials === "string") {
|
|
2775
|
+
emitAuthResolved(options.onEvent, "token");
|
|
2582
2776
|
return credentials;
|
|
2583
2777
|
}
|
|
2584
2778
|
if (isClientCredentials(credentials)) {
|
|
@@ -2591,15 +2785,25 @@ async function resolveAuthTokenFromCredentials(credentials, options) {
|
|
|
2591
2785
|
baseUrl: resolvedBaseUrl
|
|
2592
2786
|
});
|
|
2593
2787
|
const cache = await resolveCache(options);
|
|
2594
|
-
const cached = await
|
|
2595
|
-
if (cached
|
|
2596
|
-
|
|
2788
|
+
const cached = await readCachedToken(cacheKey, cache);
|
|
2789
|
+
if (cached !== void 0) {
|
|
2790
|
+
if (options.debug) {
|
|
2791
|
+
console.log(`[auth] Using cached token (clientId: ${clientId})`);
|
|
2792
|
+
}
|
|
2793
|
+
return cached;
|
|
2597
2794
|
}
|
|
2598
2795
|
const pending = pendingExchanges.get(cacheKey);
|
|
2599
2796
|
if (pending) return pending;
|
|
2600
2797
|
const runLocked = async () => {
|
|
2601
|
-
const recheck = await
|
|
2602
|
-
if (recheck
|
|
2798
|
+
const recheck = await readCachedToken(cacheKey, cache);
|
|
2799
|
+
if (recheck !== void 0) {
|
|
2800
|
+
if (options.debug) {
|
|
2801
|
+
console.log(
|
|
2802
|
+
`[auth] Using cached token (clientId: ${clientId}, locked recheck)`
|
|
2803
|
+
);
|
|
2804
|
+
}
|
|
2805
|
+
return recheck;
|
|
2806
|
+
}
|
|
2603
2807
|
const { accessToken, expiresIn } = await exchangeClientCredentials({
|
|
2604
2808
|
clientId: credentials.clientId,
|
|
2605
2809
|
clientSecret: credentials.clientSecret,
|
|
@@ -2657,7 +2861,7 @@ async function invalidateCredentialsToken(options) {
|
|
|
2657
2861
|
}
|
|
2658
2862
|
|
|
2659
2863
|
// src/sdk-version.ts
|
|
2660
|
-
var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.
|
|
2864
|
+
var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.52.0" : void 0) || "unknown";
|
|
2661
2865
|
|
|
2662
2866
|
// src/utils/open-url.ts
|
|
2663
2867
|
var nodePrefix = "node:";
|
|
@@ -2867,9 +3071,61 @@ var ZapierApiClient = class {
|
|
|
2867
3071
|
await sleep(delayMs, init?.signal ?? void 0);
|
|
2868
3072
|
}
|
|
2869
3073
|
};
|
|
3074
|
+
/**
|
|
3075
|
+
* Wrap an outbound HTTP call with the concurrency semaphore. Used by both
|
|
3076
|
+
* `rawFetch` (path-based) and the approval-poll path (absolute URL); each
|
|
3077
|
+
* caller acquires per-attempt, so 429 retry sleep is held but the gap
|
|
3078
|
+
* between approval polls and the human-approval wait are not.
|
|
3079
|
+
*
|
|
3080
|
+
* The release is registered in a finally that wraps the entire post-
|
|
3081
|
+
* acquire flow — including the `wait_end` event emission — so a throwing
|
|
3082
|
+
* `onEvent` handler can never leak a permit.
|
|
3083
|
+
*
|
|
3084
|
+
* Slot lifetime is intentionally tied to "fetch resolves" (headers
|
|
3085
|
+
* received), NOT to "response body fully consumed". WHATWG `fetch()`
|
|
3086
|
+
* resolves once headers are in; the body is still streaming. We rely on
|
|
3087
|
+
* that boundary so streaming responses (SSE, long-running chunked reads)
|
|
3088
|
+
* don't pin a permit for the lifetime of the stream — a single SSE
|
|
3089
|
+
* consumer would otherwise hold one of N slots for as long as the
|
|
3090
|
+
* connection stays open. Do not move the release into a path that awaits
|
|
3091
|
+
* body consumption (e.g. `parseResult` / `response.text()`); doing so
|
|
3092
|
+
* would silently break streaming consumers without failing any of the
|
|
3093
|
+
* short-request tests.
|
|
3094
|
+
*/
|
|
3095
|
+
this.withSemaphore = async (context, fn) => {
|
|
3096
|
+
const fastRelease = this.semaphore.tryAcquire();
|
|
3097
|
+
let waitStart = null;
|
|
3098
|
+
let release = fastRelease;
|
|
3099
|
+
if (release === null) {
|
|
3100
|
+
waitStart = Date.now();
|
|
3101
|
+
this.emitEvent("api:concurrency_wait_start", {
|
|
3102
|
+
url: context.url,
|
|
3103
|
+
method: context.method
|
|
3104
|
+
});
|
|
3105
|
+
release = await this.semaphore.acquire(context.signal ?? void 0);
|
|
3106
|
+
}
|
|
3107
|
+
const acquiredRelease = release;
|
|
3108
|
+
try {
|
|
3109
|
+
if (waitStart !== null) {
|
|
3110
|
+
this.emitEvent("api:concurrency_wait_end", {
|
|
3111
|
+
url: context.url,
|
|
3112
|
+
method: context.method,
|
|
3113
|
+
waitedMs: Date.now() - waitStart
|
|
3114
|
+
});
|
|
3115
|
+
}
|
|
3116
|
+
return await fn();
|
|
3117
|
+
} finally {
|
|
3118
|
+
acquiredRelease();
|
|
3119
|
+
}
|
|
3120
|
+
};
|
|
2870
3121
|
/**
|
|
2871
3122
|
* Perform a request with auth, header merging, and rate-limit (429) retries.
|
|
2872
3123
|
* Does NOT handle 403 approval_required — that's routed by `fetch`.
|
|
3124
|
+
*
|
|
3125
|
+
* Concurrency: a semaphore slot is held across the entire call, including
|
|
3126
|
+
* the 429 retry sleep inside `rawFetchUrl`. That keeps backpressure
|
|
3127
|
+
* coherent — when the server is rate-limiting us, we don't dump more
|
|
3128
|
+
* parallelism into the queue.
|
|
2873
3129
|
*/
|
|
2874
3130
|
this.rawFetch = async (path, init) => {
|
|
2875
3131
|
if (!path.startsWith("/")) {
|
|
@@ -2878,7 +3134,10 @@ var ZapierApiClient = class {
|
|
|
2878
3134
|
);
|
|
2879
3135
|
}
|
|
2880
3136
|
const { url, pathConfig: pathConfig2 } = this.buildUrl(path, init?.searchParams);
|
|
2881
|
-
return this.
|
|
3137
|
+
return this.withSemaphore(
|
|
3138
|
+
{ url, method: init?.method ?? "GET", signal: init?.signal },
|
|
3139
|
+
() => this.rawFetchUrl(url, init, pathConfig2)
|
|
3140
|
+
);
|
|
2882
3141
|
};
|
|
2883
3142
|
/**
|
|
2884
3143
|
* Approval-aware HTTP fetch.
|
|
@@ -2986,6 +3245,15 @@ var ZapierApiClient = class {
|
|
|
2986
3245
|
};
|
|
2987
3246
|
this.maxNetworkRetries = options.maxNetworkRetries ?? ZAPIER_MAX_NETWORK_RETRIES;
|
|
2988
3247
|
this.maxNetworkRetryDelayMs = options.maxNetworkRetryDelayMs ?? ZAPIER_MAX_NETWORK_RETRY_DELAY_MS;
|
|
3248
|
+
const requested = options.maxConcurrentRequests;
|
|
3249
|
+
const limit = requested === void 0 || Number.isNaN(requested) ? ZAPIER_MAX_CONCURRENT_REQUESTS : requested;
|
|
3250
|
+
if (limit !== Infinity && (!Number.isInteger(limit) || limit < 1 || limit > MAX_CONCURRENCY_LIMIT)) {
|
|
3251
|
+
throw new ZapierConfigurationError(
|
|
3252
|
+
`Invalid maxConcurrentRequests: ${limit} (expected positive integer 1-${MAX_CONCURRENCY_LIMIT} or Infinity)`,
|
|
3253
|
+
{ configType: "maxConcurrentRequests" }
|
|
3254
|
+
);
|
|
3255
|
+
}
|
|
3256
|
+
this.semaphore = createSemaphore(limit);
|
|
2989
3257
|
}
|
|
2990
3258
|
// Emit an event if onEvent handler is configured
|
|
2991
3259
|
emitEvent(type, payload) {
|
|
@@ -3238,7 +3506,9 @@ var ZapierApiClient = class {
|
|
|
3238
3506
|
if (data && typeof data === "object") {
|
|
3239
3507
|
headers["Content-Type"] = "application/json";
|
|
3240
3508
|
}
|
|
3241
|
-
const wasMissingAuthToken = options.authRequired && await this.getAuthToken({
|
|
3509
|
+
const wasMissingAuthToken = options.authRequired && await this.getAuthToken({
|
|
3510
|
+
requiredScopes: options.requiredScopes
|
|
3511
|
+
}) == null;
|
|
3242
3512
|
const response = await this.fetch(path, {
|
|
3243
3513
|
...options,
|
|
3244
3514
|
method,
|
|
@@ -3361,10 +3631,16 @@ var ZapierApiClient = class {
|
|
|
3361
3631
|
// poll_url is an absolute URL supplied by the server, so we use
|
|
3362
3632
|
// rawFetchUrl directly (skipping path resolution) but still share
|
|
3363
3633
|
// auth + interactive-header + 429-retry with the rest of the SDK.
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3634
|
+
// Each individual poll request goes through the concurrency
|
|
3635
|
+
// semaphore — but we deliberately do not hold a slot across the
|
|
3636
|
+
// sleep between polls or across the human-approval wait.
|
|
3637
|
+
fetchPoll: () => this.withSemaphore(
|
|
3638
|
+
{ url: approval.poll_url, method: "GET" },
|
|
3639
|
+
() => this.rawFetchUrl(approval.poll_url, {
|
|
3640
|
+
method: "GET",
|
|
3641
|
+
headers: { Accept: "application/json" }
|
|
3642
|
+
})
|
|
3643
|
+
),
|
|
3368
3644
|
timeoutMs,
|
|
3369
3645
|
isPending: (body2) => {
|
|
3370
3646
|
const parsed = PollApprovalResponseSchema.safeParse(body2);
|
|
@@ -3432,6 +3708,28 @@ var createZapierApi = (options) => {
|
|
|
3432
3708
|
});
|
|
3433
3709
|
};
|
|
3434
3710
|
|
|
3711
|
+
// src/api/index.ts
|
|
3712
|
+
function getOrCreateApiClient(config) {
|
|
3713
|
+
const {
|
|
3714
|
+
baseUrl = ZAPIER_BASE_URL,
|
|
3715
|
+
credentials,
|
|
3716
|
+
token,
|
|
3717
|
+
api: providedApi,
|
|
3718
|
+
debug = false,
|
|
3719
|
+
fetch: customFetch
|
|
3720
|
+
} = config;
|
|
3721
|
+
if (providedApi) {
|
|
3722
|
+
return providedApi;
|
|
3723
|
+
}
|
|
3724
|
+
return createZapierApi({
|
|
3725
|
+
baseUrl,
|
|
3726
|
+
credentials,
|
|
3727
|
+
token,
|
|
3728
|
+
debug,
|
|
3729
|
+
fetch: customFetch
|
|
3730
|
+
});
|
|
3731
|
+
}
|
|
3732
|
+
|
|
3435
3733
|
// src/plugins/api/index.ts
|
|
3436
3734
|
var apiPlugin = definePlugin(
|
|
3437
3735
|
(sdk) => {
|
|
@@ -3444,6 +3742,7 @@ var apiPlugin = definePlugin(
|
|
|
3444
3742
|
debug = false,
|
|
3445
3743
|
maxNetworkRetries = ZAPIER_MAX_NETWORK_RETRIES,
|
|
3446
3744
|
maxNetworkRetryDelayMs = ZAPIER_MAX_NETWORK_RETRY_DELAY_MS,
|
|
3745
|
+
maxConcurrentRequests = ZAPIER_MAX_CONCURRENT_REQUESTS,
|
|
3447
3746
|
approvalTimeoutMs,
|
|
3448
3747
|
maxApprovalRetries,
|
|
3449
3748
|
approvalMode,
|
|
@@ -3458,6 +3757,7 @@ var apiPlugin = definePlugin(
|
|
|
3458
3757
|
onEvent,
|
|
3459
3758
|
maxNetworkRetries,
|
|
3460
3759
|
maxNetworkRetryDelayMs,
|
|
3760
|
+
maxConcurrentRequests,
|
|
3461
3761
|
approvalTimeoutMs,
|
|
3462
3762
|
maxApprovalRetries,
|
|
3463
3763
|
approvalMode,
|
|
@@ -10163,6 +10463,24 @@ var BaseSdkOptionsSchema = z.object({
|
|
|
10163
10463
|
* Default is 60000 (60 seconds).
|
|
10164
10464
|
*/
|
|
10165
10465
|
maxNetworkRetryDelayMs: z.number().optional().describe("Max delay in ms to wait for retry (default: 60000).").meta({ valueHint: "ms" }),
|
|
10466
|
+
/**
|
|
10467
|
+
* Maximum number of concurrent in-flight HTTP requests per client.
|
|
10468
|
+
* Requests beyond this limit queue in FIFO order until a slot frees.
|
|
10469
|
+
* Pass `Infinity` to disable. Default: 200.
|
|
10470
|
+
*
|
|
10471
|
+
* The description and meta are duplicated across the outer wrapper and
|
|
10472
|
+
* the inner numeric branch because the SDK and CLI doc generators walk
|
|
10473
|
+
* the schema differently — the SDK reader looks at wrappers only, while
|
|
10474
|
+
* the CLI reader recurses into union branches.
|
|
10475
|
+
*/
|
|
10476
|
+
maxConcurrentRequests: z.union([
|
|
10477
|
+
z.number().int().min(1).max(MAX_CONCURRENCY_LIMIT).describe(
|
|
10478
|
+
`Max concurrent in-flight HTTP requests (default: 200, max: ${MAX_CONCURRENCY_LIMIT}).`
|
|
10479
|
+
).meta({ valueHint: "count" }),
|
|
10480
|
+
z.literal(Infinity)
|
|
10481
|
+
]).optional().describe(
|
|
10482
|
+
`Max concurrent in-flight HTTP requests (default: 200, max: ${MAX_CONCURRENCY_LIMIT}).`
|
|
10483
|
+
).meta({ valueHint: "count" }),
|
|
10166
10484
|
approvalTimeoutMs: z.number().optional().describe("Timeout in ms for approval polling. Default: 600000 (10 min).").meta({ valueHint: "ms" }),
|
|
10167
10485
|
maxApprovalRetries: z.number().optional().describe(
|
|
10168
10486
|
"Maximum number of sequential approval rounds per request (one per gating policy) before giving up. Default: 2."
|
|
@@ -10199,4 +10517,4 @@ function createZapierSdk2(options = {}) {
|
|
|
10199
10517
|
return createSdk().addPlugin(createOptionsPlugin(options)).addPlugin(eventEmissionPlugin).addPlugin(apiPlugin).addPlugin(manifestPlugin).addPlugin(capabilitiesPlugin).addPlugin(connectionsPlugin).addPlugin(listAppsPlugin).addPlugin(getAppPlugin).addPlugin(listActionsPlugin).addPlugin(getActionPlugin).addPlugin(listActionInputFieldsPlugin).addPlugin(getActionInputFieldsSchemaPlugin).addPlugin(listActionInputFieldChoicesPlugin).addPlugin(listInputFieldsDeprecatedPlugin).addPlugin(getInputFieldsSchemaDeprecatedPlugin).addPlugin(listInputFieldChoicesDeprecatedPlugin).addPlugin(runActionPlugin).addPlugin(listConnectionsPlugin).addPlugin(getConnectionPlugin).addPlugin(findFirstConnectionPlugin).addPlugin(findUniqueConnectionPlugin).addPlugin(listAuthenticationsPlugin).addPlugin(getAuthenticationPlugin).addPlugin(findFirstAuthenticationPlugin).addPlugin(findUniqueAuthenticationPlugin).addPlugin(listClientCredentialsPlugin).addPlugin(createClientCredentialsPlugin).addPlugin(deleteClientCredentialsPlugin).addPlugin(fetchPlugin).addPlugin(requestPlugin).addPlugin(createTriggerInboxPlugin).addPlugin(ensureTriggerInboxPlugin).addPlugin(listTriggerInboxesPlugin).addPlugin(getTriggerInboxPlugin).addPlugin(updateTriggerInboxPlugin).addPlugin(deleteTriggerInboxPlugin).addPlugin(pauseTriggerInboxPlugin).addPlugin(resumeTriggerInboxPlugin).addPlugin(listTriggerInboxMessagesPlugin).addPlugin(leaseTriggerInboxMessagesPlugin).addPlugin(ackTriggerInboxMessagesPlugin).addPlugin(releaseTriggerInboxMessagesPlugin).addPlugin(drainTriggerInboxPlugin).addPlugin(watchTriggerInboxPlugin).addPlugin(listTriggerInputFieldsPlugin).addPlugin(listTriggerInputFieldChoicesPlugin).addPlugin(getTriggerInputFieldsSchemaPlugin).addPlugin(listTablesPlugin).addPlugin(getTablePlugin).addPlugin(deleteTablePlugin).addPlugin(createTablePlugin).addPlugin(listTableFieldsPlugin).addPlugin(createTableFieldsPlugin).addPlugin(deleteTableFieldsPlugin).addPlugin(getTableRecordPlugin).addPlugin(listTableRecordsPlugin).addPlugin(createTableRecordsPlugin).addPlugin(deleteTableRecordsPlugin).addPlugin(updateTableRecordsPlugin).addPlugin(appsPlugin).addPlugin(getProfilePlugin);
|
|
10200
10518
|
}
|
|
10201
10519
|
|
|
10202
|
-
export { ActionKeyPropertySchema, ActionPropertySchema, ActionTimeoutMsPropertySchema, ActionTypePropertySchema, AppKeyPropertySchema, AppPropertySchema, AppsPropertySchema, AuthenticationIdPropertySchema, BaseSdkOptionsSchema, CONTEXT_CACHE_MAX_SIZE, CONTEXT_CACHE_TTL_MS, ClientCredentialsObjectSchema, ConnectionEntrySchema, ConnectionIdPropertySchema, ConnectionPropertySchema, ConnectionsMapSchema, ConnectionsPropertySchema, CredentialsFunctionSchema, CredentialsObjectSchema, CredentialsSchema, DEFAULT_ACTION_TIMEOUT_MS, DEFAULT_APPROVAL_TIMEOUT_MS, DEFAULT_CONFIG_PATH, DEFAULT_MAX_APPROVAL_RETRIES, DEFAULT_PAGE_SIZE, DebugPropertySchema, FieldsPropertySchema, InputFieldPropertySchema, InputsPropertySchema, LeaseLimitPropertySchema, LeasePropertySchema, LeaseSecondsPropertySchema, LimitPropertySchema, MAX_PAGE_LIMIT, OffsetPropertySchema, OutputPropertySchema, ParamsPropertySchema, PkceCredentialsObjectSchema, RecordPropertySchema, RecordsPropertySchema, RelayFetchSchema, RelayRequestSchema, ResolvedCredentialsSchema, TablePropertySchema, TablesPropertySchema, TriggerInboxNamePropertySchema, TriggerInboxPropertySchema, ZAPIER_BASE_URL, ZAPIER_MAX_NETWORK_RETRIES, ZAPIER_MAX_NETWORK_RETRY_DELAY_MS, ZapierAbortDrainSignal, ZapierActionError, ZapierApiError, ZapierAppNotFoundError, ZapierApprovalError, ZapierAuthenticationError, ZapierBundleError, ZapierConfigurationError, ZapierConflictError, ZapierError, ZapierNotFoundError, ZapierRateLimitError, ZapierRelayError, ZapierReleaseTriggerMessageSignal, ZapierResourceNotFoundError, ZapierSignal, ZapierTimeoutError, ZapierUnknownError, ZapierValidationError, actionKeyResolver, actionTypeResolver, apiPlugin, appKeyResolver, appsPlugin, connectionIdGenericResolver as authenticationIdGenericResolver, connectionIdResolver as authenticationIdResolver, batch, buildApplicationLifecycleEvent, buildCapabilityMessage, buildErrorEvent, buildErrorEventWithContext, buildMethodCalledEvent, clearTokenCache, clientCredentialsNameResolver, clientIdResolver, composePlugins, connectionIdGenericResolver, connectionIdResolver, connectionsPlugin, createBaseEvent, createClientCredentialsPlugin, createFunction, createMemoryCache, createOptionsPlugin, createPaginatedPluginMethod, createPluginMethod, createSdk, createTableFieldsPlugin, createTablePlugin, createTableRecordsPlugin, createZapierSdk2 as createZapierSdk, createZapierSdkWithoutRegistry, definePlugin, deleteClientCredentialsPlugin, deleteTableFieldsPlugin, deleteTablePlugin, deleteTableRecordsPlugin, fetchPlugin, findFirstConnectionPlugin, findManifestEntry, findUniqueConnectionPlugin, formatErrorMessage, generateEventId, getActionInputFieldsSchemaPlugin, getActionPlugin, getAppPlugin, getBaseUrlFromCredentials, getCiPlatform, getClientIdFromCredentials, getConnectionPlugin, getCpuTime, getCurrentTimestamp, getMemoryUsage, getOsInfo, getPlatformVersions, getPreferredManifestEntryKey, getProfilePlugin, getReleaseId, getTablePlugin, getTableRecordPlugin, getTokenFromCliLogin, getZapierApprovalMode, getZapierSdkService, injectCliLogin, inputFieldKeyResolver, inputsAllOptionalResolver, inputsResolver, invalidateCachedToken, invalidateCredentialsToken, isCi, isCliLoginAvailable, isClientCredentials, isCredentialsFunction, isCredentialsObject, isPkceCredentials, isPositional, listActionInputFieldChoicesPlugin, listActionInputFieldsPlugin, listActionsPlugin, listAppsPlugin, listClientCredentialsPlugin, listConnectionsPlugin, listTableFieldsPlugin, listTableRecordsPlugin, listTablesPlugin, logDeprecation, manifestPlugin, readManifestFromFile, registryPlugin, requestPlugin, resetDeprecationWarnings, resolveAuthToken, resolveCredentials, resolveCredentialsFromEnv, runActionPlugin, runWithTelemetryContext, tableFieldIdsResolver, tableFieldsResolver, tableFiltersResolver, tableIdResolver, tableNameResolver, tableRecordIdResolver, tableRecordIdsResolver, tableRecordsResolver, tableSortResolver, tableUpdateRecordsResolver, toSnakeCase, toTitleCase, triggerInboxResolver, updateTableRecordsPlugin };
|
|
10520
|
+
export { ActionKeyPropertySchema, ActionPropertySchema, ActionTimeoutMsPropertySchema, ActionTypePropertySchema, AppKeyPropertySchema, AppPropertySchema, AppsPropertySchema, AuthenticationIdPropertySchema, BaseSdkOptionsSchema, CONTEXT_CACHE_MAX_SIZE, CONTEXT_CACHE_TTL_MS, ClientCredentialsObjectSchema, ConnectionEntrySchema, ConnectionIdPropertySchema, ConnectionPropertySchema, ConnectionsMapSchema, ConnectionsPropertySchema, CredentialsFunctionSchema, CredentialsObjectSchema, CredentialsSchema, DEFAULT_ACTION_TIMEOUT_MS, DEFAULT_APPROVAL_TIMEOUT_MS, DEFAULT_CONFIG_PATH, DEFAULT_MAX_APPROVAL_RETRIES, DEFAULT_PAGE_SIZE, DebugPropertySchema, FieldsPropertySchema, InputFieldPropertySchema, InputsPropertySchema, LeaseLimitPropertySchema, LeasePropertySchema, LeaseSecondsPropertySchema, LimitPropertySchema, MAX_CONCURRENCY_LIMIT, MAX_PAGE_LIMIT, OffsetPropertySchema, OutputPropertySchema, ParamsPropertySchema, PkceCredentialsObjectSchema, RecordPropertySchema, RecordsPropertySchema, RelayFetchSchema, RelayRequestSchema, ResolvedCredentialsSchema, TablePropertySchema, TablesPropertySchema, TriggerInboxNamePropertySchema, TriggerInboxPropertySchema, ZAPIER_BASE_URL, ZAPIER_MAX_CONCURRENT_REQUESTS, ZAPIER_MAX_NETWORK_RETRIES, ZAPIER_MAX_NETWORK_RETRY_DELAY_MS, ZapierAbortDrainSignal, ZapierActionError, ZapierApiError, ZapierAppNotFoundError, ZapierApprovalError, ZapierAuthenticationError, ZapierBundleError, ZapierConfigurationError, ZapierConflictError, ZapierError, ZapierNotFoundError, ZapierRateLimitError, ZapierRelayError, ZapierReleaseTriggerMessageSignal, ZapierResourceNotFoundError, ZapierSignal, ZapierTimeoutError, ZapierUnknownError, ZapierValidationError, actionKeyResolver, actionTypeResolver, apiPlugin, appKeyResolver, appsPlugin, connectionIdGenericResolver as authenticationIdGenericResolver, connectionIdResolver as authenticationIdResolver, batch, buildApplicationLifecycleEvent, buildCapabilityMessage, buildErrorEvent, buildErrorEventWithContext, buildMethodCalledEvent, clearTokenCache, clientCredentialsNameResolver, clientIdResolver, composePlugins, connectionIdGenericResolver, connectionIdResolver, connectionsPlugin, createBaseEvent, createClientCredentialsPlugin, createFunction, createMemoryCache, createOptionsPlugin, createPaginatedPluginMethod, createPluginMethod, createSdk, createTableFieldsPlugin, createTablePlugin, createTableRecordsPlugin, createZapierApi, createZapierSdk2 as createZapierSdk, createZapierSdkWithoutRegistry, definePlugin, deleteClientCredentialsPlugin, deleteTableFieldsPlugin, deleteTablePlugin, deleteTableRecordsPlugin, fetchPlugin, findFirstConnectionPlugin, findManifestEntry, findUniqueConnectionPlugin, formatErrorMessage, generateEventId, getActionInputFieldsSchemaPlugin, getActionPlugin, getAppPlugin, getBaseUrlFromCredentials, getCiPlatform, getClientIdFromCredentials, getConnectionPlugin, getCpuTime, getCurrentTimestamp, getMemoryUsage, getOrCreateApiClient, getOsInfo, getPlatformVersions, getPreferredManifestEntryKey, getProfilePlugin, getReleaseId, getTablePlugin, getTableRecordPlugin, getTokenFromCliLogin, getZapierApprovalMode, getZapierSdkService, injectCliLogin, inputFieldKeyResolver, inputsAllOptionalResolver, inputsResolver, invalidateCachedToken, invalidateCredentialsToken, isCi, isCliLoginAvailable, isClientCredentials, isCredentialsFunction, isCredentialsObject, isPkceCredentials, isPositional, listActionInputFieldChoicesPlugin, listActionInputFieldsPlugin, listActionsPlugin, listAppsPlugin, listClientCredentialsPlugin, listConnectionsPlugin, listTableFieldsPlugin, listTableRecordsPlugin, listTablesPlugin, logDeprecation, manifestPlugin, parseConcurrencyEnvVar, readManifestFromFile, registryPlugin, requestPlugin, resetDeprecationWarnings, resolveAuthToken, resolveCredentials, resolveCredentialsFromEnv, runActionPlugin, runWithTelemetryContext, tableFieldIdsResolver, tableFieldsResolver, tableFiltersResolver, tableIdResolver, tableNameResolver, tableRecordIdResolver, tableRecordIdsResolver, tableRecordsResolver, tableSortResolver, tableUpdateRecordsResolver, toSnakeCase, toTitleCase, triggerInboxResolver, updateTableRecordsPlugin };
|