@zapier/zapier-sdk 0.13.7 → 0.13.9
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 +15 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +5 -5
- package/dist/api/client.test.d.ts +2 -0
- package/dist/api/client.test.d.ts.map +1 -0
- package/dist/api/client.test.js +80 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +3 -1
- package/dist/api/polling.d.ts.map +1 -1
- package/dist/api/polling.js +1 -11
- package/dist/api/schemas.d.ts +20 -20
- package/dist/api/types.d.ts +2 -0
- package/dist/api/types.d.ts.map +1 -1
- package/dist/auth.d.ts +3 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.test.d.ts +2 -0
- package/dist/auth.test.d.ts.map +1 -0
- package/dist/auth.test.js +102 -0
- package/dist/constants.d.ts +4 -4
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +4 -4
- package/dist/index.cjs +194 -33
- package/dist/index.d.mts +93 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.mjs +192 -34
- package/dist/plugins/api/index.d.ts.map +1 -1
- package/dist/plugins/api/index.js +4 -1
- package/dist/plugins/eventEmission/index.d.ts +2 -0
- package/dist/plugins/eventEmission/index.d.ts.map +1 -1
- package/dist/plugins/eventEmission/index.js +35 -9
- package/dist/plugins/eventEmission/index.test.js +100 -0
- package/dist/schemas/Action.d.ts +2 -2
- package/dist/schemas/Auth.d.ts +4 -4
- package/dist/schemas/Field.d.ts +10 -10
- package/dist/sdk.test.js +121 -1
- package/dist/types/sdk.d.ts +3 -0
- package/dist/types/sdk.d.ts.map +1 -1
- package/dist/utils/batch-utils.d.ts +72 -0
- package/dist/utils/batch-utils.d.ts.map +1 -0
- package/dist/utils/batch-utils.js +162 -0
- package/dist/utils/batch-utils.test.d.ts +2 -0
- package/dist/utils/batch-utils.test.d.ts.map +1 -0
- package/dist/utils/batch-utils.test.js +476 -0
- package/dist/utils/retry-utils.d.ts +45 -0
- package/dist/utils/retry-utils.d.ts.map +1 -0
- package/dist/utils/retry-utils.js +51 -0
- package/dist/utils/retry-utils.test.d.ts +2 -0
- package/dist/utils/retry-utils.test.d.ts.map +1 -0
- package/dist/utils/retry-utils.test.js +90 -0
- package/dist/utils/url-utils.d.ts +19 -0
- package/dist/utils/url-utils.d.ts.map +1 -0
- package/dist/utils/url-utils.js +62 -0
- package/dist/utils/url-utils.test.d.ts +2 -0
- package/dist/utils/url-utils.test.d.ts.map +1 -0
- package/dist/utils/url-utils.test.js +103 -0
- package/package.json +2 -2
package/dist/schemas/Field.d.ts
CHANGED
|
@@ -3,11 +3,11 @@ export declare const BaseFieldItemSchema: z.ZodObject<{
|
|
|
3
3
|
type: z.ZodString;
|
|
4
4
|
key: z.ZodString;
|
|
5
5
|
}, "strip", z.ZodTypeAny, {
|
|
6
|
-
type: string;
|
|
7
6
|
key: string;
|
|
8
|
-
}, {
|
|
9
7
|
type: string;
|
|
8
|
+
}, {
|
|
10
9
|
key: string;
|
|
10
|
+
type: string;
|
|
11
11
|
}>;
|
|
12
12
|
export declare const InputFieldItemSchema: z.ZodObject<{
|
|
13
13
|
key: z.ZodString;
|
|
@@ -30,8 +30,8 @@ export declare const InputFieldItemSchema: z.ZodObject<{
|
|
|
30
30
|
type: string;
|
|
31
31
|
}>>;
|
|
32
32
|
}, "strip", z.ZodTypeAny, {
|
|
33
|
-
type: "input_field";
|
|
34
33
|
key: string;
|
|
34
|
+
type: "input_field";
|
|
35
35
|
depends_on: string[];
|
|
36
36
|
placeholder: string;
|
|
37
37
|
description: string;
|
|
@@ -45,8 +45,8 @@ export declare const InputFieldItemSchema: z.ZodObject<{
|
|
|
45
45
|
type: string;
|
|
46
46
|
} | undefined;
|
|
47
47
|
}, {
|
|
48
|
-
type: "input_field";
|
|
49
48
|
key: string;
|
|
49
|
+
type: "input_field";
|
|
50
50
|
depends_on: string[];
|
|
51
51
|
placeholder: string;
|
|
52
52
|
description: string;
|
|
@@ -67,13 +67,13 @@ export declare const InfoFieldItemSchema: z.ZodObject<{
|
|
|
67
67
|
description: z.ZodString;
|
|
68
68
|
title: z.ZodOptional<z.ZodString>;
|
|
69
69
|
}, "strip", z.ZodTypeAny, {
|
|
70
|
-
type: "info_field";
|
|
71
70
|
key: string;
|
|
71
|
+
type: "info_field";
|
|
72
72
|
description: string;
|
|
73
73
|
title?: string | undefined;
|
|
74
74
|
}, {
|
|
75
|
-
type: "info_field";
|
|
76
75
|
key: string;
|
|
76
|
+
type: "info_field";
|
|
77
77
|
description: string;
|
|
78
78
|
title?: string | undefined;
|
|
79
79
|
}>;
|
|
@@ -106,8 +106,8 @@ export declare const RootFieldItemSchema: z.ZodUnion<[z.ZodObject<{
|
|
|
106
106
|
type: string;
|
|
107
107
|
}>>;
|
|
108
108
|
}, "strip", z.ZodTypeAny, {
|
|
109
|
-
type: "input_field";
|
|
110
109
|
key: string;
|
|
110
|
+
type: "input_field";
|
|
111
111
|
depends_on: string[];
|
|
112
112
|
placeholder: string;
|
|
113
113
|
description: string;
|
|
@@ -121,8 +121,8 @@ export declare const RootFieldItemSchema: z.ZodUnion<[z.ZodObject<{
|
|
|
121
121
|
type: string;
|
|
122
122
|
} | undefined;
|
|
123
123
|
}, {
|
|
124
|
-
type: "input_field";
|
|
125
124
|
key: string;
|
|
125
|
+
type: "input_field";
|
|
126
126
|
depends_on: string[];
|
|
127
127
|
placeholder: string;
|
|
128
128
|
description: string;
|
|
@@ -142,13 +142,13 @@ export declare const RootFieldItemSchema: z.ZodUnion<[z.ZodObject<{
|
|
|
142
142
|
description: z.ZodString;
|
|
143
143
|
title: z.ZodOptional<z.ZodString>;
|
|
144
144
|
}, "strip", z.ZodTypeAny, {
|
|
145
|
-
type: "info_field";
|
|
146
145
|
key: string;
|
|
146
|
+
type: "info_field";
|
|
147
147
|
description: string;
|
|
148
148
|
title?: string | undefined;
|
|
149
149
|
}, {
|
|
150
|
-
type: "info_field";
|
|
151
150
|
key: string;
|
|
151
|
+
type: "info_field";
|
|
152
152
|
description: string;
|
|
153
153
|
title?: string | undefined;
|
|
154
154
|
}>, z.ZodType<FieldsetItem, z.ZodTypeDef, FieldsetItem>]>;
|
package/dist/sdk.test.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Test the flat plugin system
|
|
2
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
3
3
|
import { createZapierSdk, createSdk } from "./sdk";
|
|
4
4
|
describe("Flat Plugin System", () => {
|
|
5
5
|
it("should create SDK with all expected methods", () => {
|
|
@@ -133,3 +133,123 @@ describe("Flat Plugin System", () => {
|
|
|
133
133
|
expect(context.meta).not.toBeNull();
|
|
134
134
|
});
|
|
135
135
|
});
|
|
136
|
+
describe("Environment Variable Support", () => {
|
|
137
|
+
let originalEnv;
|
|
138
|
+
beforeEach(() => {
|
|
139
|
+
// Save original environment variable
|
|
140
|
+
originalEnv = process.env.ZAPIER_BASE_URL;
|
|
141
|
+
});
|
|
142
|
+
afterEach(() => {
|
|
143
|
+
// Restore original environment variable
|
|
144
|
+
if (originalEnv !== undefined) {
|
|
145
|
+
process.env.ZAPIER_BASE_URL = originalEnv;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
delete process.env.ZAPIER_BASE_URL;
|
|
149
|
+
}
|
|
150
|
+
// Clear module cache to ensure constants are re-evaluated
|
|
151
|
+
vi.resetModules();
|
|
152
|
+
});
|
|
153
|
+
it("should use custom base URL from ZAPIER_BASE_URL environment variable", async () => {
|
|
154
|
+
// Set custom base URL via environment variable
|
|
155
|
+
const customBaseUrl = "https://custom-zapier.example.com";
|
|
156
|
+
process.env.ZAPIER_BASE_URL = customBaseUrl;
|
|
157
|
+
// Clear module cache and re-import to get fresh constants
|
|
158
|
+
vi.resetModules();
|
|
159
|
+
const { createZapierSdk } = await import("./sdk");
|
|
160
|
+
// Create mock fetch function to capture requests
|
|
161
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
162
|
+
ok: true,
|
|
163
|
+
status: 200,
|
|
164
|
+
json: async () => ({
|
|
165
|
+
results: [],
|
|
166
|
+
meta: { next_cursor: null },
|
|
167
|
+
}),
|
|
168
|
+
headers: new Headers(),
|
|
169
|
+
});
|
|
170
|
+
// Create SDK instance with mock fetch
|
|
171
|
+
const sdk = createZapierSdk({
|
|
172
|
+
token: "test-token",
|
|
173
|
+
fetch: mockFetch,
|
|
174
|
+
});
|
|
175
|
+
// Make an API call that should use the custom base URL
|
|
176
|
+
await sdk.listApps();
|
|
177
|
+
// Verify that the request was made to the custom base URL
|
|
178
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
179
|
+
const [actualUrl] = mockFetch.mock.calls[0];
|
|
180
|
+
expect(actualUrl).toMatch(new RegExp(`^${customBaseUrl}`));
|
|
181
|
+
expect(actualUrl).toContain("/api/v4/");
|
|
182
|
+
});
|
|
183
|
+
it("should use default base URL when ZAPIER_BASE_URL is not set", async () => {
|
|
184
|
+
// Ensure environment variable is not set
|
|
185
|
+
delete process.env.ZAPIER_BASE_URL;
|
|
186
|
+
// Clear module cache and re-import to get fresh constants
|
|
187
|
+
vi.resetModules();
|
|
188
|
+
const { createZapierSdk } = await import("./sdk");
|
|
189
|
+
// Create mock fetch function to capture requests
|
|
190
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
191
|
+
ok: true,
|
|
192
|
+
status: 200,
|
|
193
|
+
json: async () => ({
|
|
194
|
+
results: [],
|
|
195
|
+
meta: { next_cursor: null },
|
|
196
|
+
}),
|
|
197
|
+
headers: new Headers(),
|
|
198
|
+
});
|
|
199
|
+
// Create SDK instance with mock fetch
|
|
200
|
+
const sdk = createZapierSdk({
|
|
201
|
+
token: "test-token",
|
|
202
|
+
fetch: mockFetch,
|
|
203
|
+
});
|
|
204
|
+
// Make an API call that should use the default base URL
|
|
205
|
+
await sdk.listApps();
|
|
206
|
+
// Verify that the request was made to the default base URL
|
|
207
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
208
|
+
const [actualUrl] = mockFetch.mock.calls[0];
|
|
209
|
+
expect(actualUrl).toMatch(/^https:\/\/zapier\.com/);
|
|
210
|
+
expect(actualUrl).toContain("/api/v4/");
|
|
211
|
+
});
|
|
212
|
+
it("should use explicit baseUrl option for SDK API requests", async () => {
|
|
213
|
+
// Clear environment variable to ensure we're testing the explicit option
|
|
214
|
+
delete process.env.ZAPIER_BASE_URL;
|
|
215
|
+
// Clear module cache and re-import to get fresh constants
|
|
216
|
+
vi.resetModules();
|
|
217
|
+
const { createZapierSdk } = await import("./sdk");
|
|
218
|
+
const customBaseUrl = "https://staging.zapier.com";
|
|
219
|
+
// Create mock fetch function to capture requests
|
|
220
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
221
|
+
ok: true,
|
|
222
|
+
status: 200,
|
|
223
|
+
json: async () => ({
|
|
224
|
+
results: [],
|
|
225
|
+
meta: { next_cursor: null },
|
|
226
|
+
}),
|
|
227
|
+
headers: new Headers(),
|
|
228
|
+
});
|
|
229
|
+
// Create SDK instance with explicit baseUrl option and mock fetch
|
|
230
|
+
const sdk = createZapierSdk({
|
|
231
|
+
baseUrl: customBaseUrl,
|
|
232
|
+
token: "test-token",
|
|
233
|
+
fetch: mockFetch,
|
|
234
|
+
});
|
|
235
|
+
// Make an API call that should use the custom base URL
|
|
236
|
+
await sdk.listApps();
|
|
237
|
+
// Verify that the request was made to the custom base URL
|
|
238
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
239
|
+
const [actualUrl] = mockFetch.mock.calls[0];
|
|
240
|
+
expect(actualUrl).toMatch(new RegExp(`^${customBaseUrl}`));
|
|
241
|
+
expect(actualUrl).toContain("/api/v4/");
|
|
242
|
+
});
|
|
243
|
+
it("should accept authClientId in SDK options", async () => {
|
|
244
|
+
delete process.env.ZAPIER_BASE_URL;
|
|
245
|
+
vi.resetModules();
|
|
246
|
+
const { createZapierSdk } = await import("./sdk");
|
|
247
|
+
const sdk = createZapierSdk({
|
|
248
|
+
authClientId: "test-client-id",
|
|
249
|
+
token: "test-token",
|
|
250
|
+
});
|
|
251
|
+
// Verify SDK was created successfully with authClientId option
|
|
252
|
+
expect(sdk).toBeDefined();
|
|
253
|
+
expect(sdk.listApps).toBeDefined();
|
|
254
|
+
});
|
|
255
|
+
});
|
package/dist/types/sdk.d.ts
CHANGED
package/dist/types/sdk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/types/sdk.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/types/sdk.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch Operation Utilities
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities for executing multiple async operations
|
|
5
|
+
* with concurrency control and retry logic.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Options for batch execution
|
|
9
|
+
*/
|
|
10
|
+
export interface BatchOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Maximum number of concurrent operations (default: 10)
|
|
13
|
+
* Lower values are more "polite" but slower
|
|
14
|
+
* Higher values are faster but risk rate limits
|
|
15
|
+
*/
|
|
16
|
+
concurrency?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Whether to retry failed operations (default: true)
|
|
19
|
+
* When enabled, each operation gets up to MAX_CONSECUTIVE_ERRORS retries
|
|
20
|
+
*/
|
|
21
|
+
retry?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Delay in milliseconds between starting batches (default: 100ms)
|
|
24
|
+
* Adds a small delay between concurrent batches to avoid burst patterns
|
|
25
|
+
*/
|
|
26
|
+
batchDelay?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Overall timeout for the entire batch operation in milliseconds (default: 180000ms / 3 minutes)
|
|
29
|
+
* When exceeded, throws ZapierTimeoutError and stops processing remaining tasks
|
|
30
|
+
*/
|
|
31
|
+
timeoutMs?: number;
|
|
32
|
+
/**
|
|
33
|
+
* Timeout for individual tasks in milliseconds (default: none)
|
|
34
|
+
* When set, each task will be cancelled if it exceeds this duration
|
|
35
|
+
* Tasks that timeout will be marked as rejected in the results
|
|
36
|
+
*/
|
|
37
|
+
taskTimeoutMs?: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Execute multiple async operations with concurrency limiting and retry logic
|
|
41
|
+
*
|
|
42
|
+
* This prevents overwhelming APIs by:
|
|
43
|
+
* 1. Limiting concurrent operations (worker pool pattern)
|
|
44
|
+
* 2. Adding small delays between batches to avoid burst detection
|
|
45
|
+
* 3. Retrying failed operations with exponential backoff
|
|
46
|
+
*
|
|
47
|
+
* Problem Solved:
|
|
48
|
+
* - Rate limit prevention: Steady stream instead of burst requests
|
|
49
|
+
* - Connection pool management: Stays within browser/Node limits (~6-8 per domain)
|
|
50
|
+
* - Resilience: Transient failures are retried automatically
|
|
51
|
+
* - Observability: Returns detailed success/failure info for each operation
|
|
52
|
+
*
|
|
53
|
+
* Example Usage:
|
|
54
|
+
* ```typescript
|
|
55
|
+
* // Instead of Promise.allSettled (fires all at once):
|
|
56
|
+
* const results = await Promise.allSettled(
|
|
57
|
+
* actions.map(a => sdk.listInputFields(a))
|
|
58
|
+
* );
|
|
59
|
+
*
|
|
60
|
+
* // Use batch (controlled concurrency):
|
|
61
|
+
* const results = await batch(
|
|
62
|
+
* actions.map(a => () => sdk.listInputFields(a)),
|
|
63
|
+
* { concurrency: 10, retry: true }
|
|
64
|
+
* );
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* @param tasks - Array of functions that return promises (NOT promises themselves!)
|
|
68
|
+
* @param options - Configuration for concurrency and retry behavior
|
|
69
|
+
* @returns Promise resolving to array of settled results (same as Promise.allSettled)
|
|
70
|
+
*/
|
|
71
|
+
export declare function batch<T>(tasks: (() => Promise<T>)[], options?: BatchOptions): Promise<PromiseSettledResult<T>[]>;
|
|
72
|
+
//# sourceMappingURL=batch-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-utils.d.ts","sourceRoot":"","sources":["../../src/utils/batch-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwBH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAWD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,KAAK,CAAC,CAAC,EAC3B,KAAK,EAAE,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAC3B,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAC,CAuIpC"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch Operation Utilities
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities for executing multiple async operations
|
|
5
|
+
* with concurrency control and retry logic.
|
|
6
|
+
*/
|
|
7
|
+
import { setTimeout } from "timers/promises";
|
|
8
|
+
import { calculateWaitTime, MAX_CONSECUTIVE_ERRORS } from "./retry-utils";
|
|
9
|
+
import { ZapierTimeoutError } from "../types/errors";
|
|
10
|
+
/**
|
|
11
|
+
* Default number of concurrent operations
|
|
12
|
+
* Chosen to be "polite" to APIs while still providing good throughput
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_CONCURRENCY = 10;
|
|
15
|
+
/**
|
|
16
|
+
* Delay between starting each batch of concurrent operations (milliseconds)
|
|
17
|
+
* This prevents burst patterns that might trigger rate limiting
|
|
18
|
+
*/
|
|
19
|
+
const BATCH_START_DELAY_MS = 25;
|
|
20
|
+
/**
|
|
21
|
+
* Default timeout for entire batch operation (milliseconds)
|
|
22
|
+
* Set to 3 minutes to match polling default timeout
|
|
23
|
+
*/
|
|
24
|
+
const DEFAULT_BATCH_TIMEOUT_MS = 180000;
|
|
25
|
+
/**
|
|
26
|
+
* Execute multiple async operations with concurrency limiting and retry logic
|
|
27
|
+
*
|
|
28
|
+
* This prevents overwhelming APIs by:
|
|
29
|
+
* 1. Limiting concurrent operations (worker pool pattern)
|
|
30
|
+
* 2. Adding small delays between batches to avoid burst detection
|
|
31
|
+
* 3. Retrying failed operations with exponential backoff
|
|
32
|
+
*
|
|
33
|
+
* Problem Solved:
|
|
34
|
+
* - Rate limit prevention: Steady stream instead of burst requests
|
|
35
|
+
* - Connection pool management: Stays within browser/Node limits (~6-8 per domain)
|
|
36
|
+
* - Resilience: Transient failures are retried automatically
|
|
37
|
+
* - Observability: Returns detailed success/failure info for each operation
|
|
38
|
+
*
|
|
39
|
+
* Example Usage:
|
|
40
|
+
* ```typescript
|
|
41
|
+
* // Instead of Promise.allSettled (fires all at once):
|
|
42
|
+
* const results = await Promise.allSettled(
|
|
43
|
+
* actions.map(a => sdk.listInputFields(a))
|
|
44
|
+
* );
|
|
45
|
+
*
|
|
46
|
+
* // Use batch (controlled concurrency):
|
|
47
|
+
* const results = await batch(
|
|
48
|
+
* actions.map(a => () => sdk.listInputFields(a)),
|
|
49
|
+
* { concurrency: 10, retry: true }
|
|
50
|
+
* );
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @param tasks - Array of functions that return promises (NOT promises themselves!)
|
|
54
|
+
* @param options - Configuration for concurrency and retry behavior
|
|
55
|
+
* @returns Promise resolving to array of settled results (same as Promise.allSettled)
|
|
56
|
+
*/
|
|
57
|
+
export async function batch(tasks, options = {}) {
|
|
58
|
+
const { concurrency = DEFAULT_CONCURRENCY, retry = true, batchDelay = BATCH_START_DELAY_MS, timeoutMs = DEFAULT_BATCH_TIMEOUT_MS, taskTimeoutMs, } = options;
|
|
59
|
+
// Validate inputs
|
|
60
|
+
if (concurrency <= 0) {
|
|
61
|
+
throw new Error("Concurrency must be greater than 0");
|
|
62
|
+
}
|
|
63
|
+
if (timeoutMs <= 0) {
|
|
64
|
+
throw new Error("Timeout must be greater than 0");
|
|
65
|
+
}
|
|
66
|
+
if (taskTimeoutMs !== undefined && taskTimeoutMs <= 0) {
|
|
67
|
+
throw new Error("Task timeout must be greater than 0");
|
|
68
|
+
}
|
|
69
|
+
if (tasks.length === 0) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
// Track overall batch timing
|
|
73
|
+
const startTime = Date.now();
|
|
74
|
+
// Pre-allocate results array to maintain input order
|
|
75
|
+
const results = new Array(tasks.length);
|
|
76
|
+
// Create task queue with retry state
|
|
77
|
+
const taskQueue = tasks.map((task, index) => ({
|
|
78
|
+
index,
|
|
79
|
+
task,
|
|
80
|
+
errorCount: 0,
|
|
81
|
+
}));
|
|
82
|
+
/**
|
|
83
|
+
* Execute a single task with retry logic and optional per-task timeout
|
|
84
|
+
*/
|
|
85
|
+
async function executeTask(taskState) {
|
|
86
|
+
const { index, task, errorCount } = taskState;
|
|
87
|
+
try {
|
|
88
|
+
let result;
|
|
89
|
+
// Apply per-task timeout if specified
|
|
90
|
+
if (taskTimeoutMs !== undefined) {
|
|
91
|
+
const timeoutPromise = setTimeout(taskTimeoutMs).then(() => {
|
|
92
|
+
throw new ZapierTimeoutError(`Task timed out after ${taskTimeoutMs}ms`);
|
|
93
|
+
});
|
|
94
|
+
result = await Promise.race([task(), timeoutPromise]);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
result = await task();
|
|
98
|
+
}
|
|
99
|
+
results[index] = { status: "fulfilled", value: result };
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
const newErrorCount = errorCount + 1;
|
|
103
|
+
// Don't retry timeout errors - they're unlikely to succeed on retry
|
|
104
|
+
const isTimeout = error instanceof ZapierTimeoutError;
|
|
105
|
+
// If retry is enabled and we haven't hit max errors and it's not a timeout, retry with backoff
|
|
106
|
+
if (retry && !isTimeout && newErrorCount < MAX_CONSECUTIVE_ERRORS) {
|
|
107
|
+
// Calculate backoff delay (base 1000ms with jitter and error scaling)
|
|
108
|
+
const waitTime = calculateWaitTime(1000, newErrorCount);
|
|
109
|
+
await setTimeout(waitTime);
|
|
110
|
+
// Re-queue the task with incremented error count
|
|
111
|
+
taskQueue.push({
|
|
112
|
+
index,
|
|
113
|
+
task,
|
|
114
|
+
errorCount: newErrorCount,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
// Max retries reached, retry disabled, or timeout error - mark as rejected
|
|
119
|
+
results[index] = { status: "rejected", reason: error };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Worker that continuously picks up and executes tasks from the queue
|
|
125
|
+
* Checks overall batch timeout before processing each task
|
|
126
|
+
*/
|
|
127
|
+
async function worker() {
|
|
128
|
+
while (taskQueue.length > 0) {
|
|
129
|
+
// Check overall batch timeout before processing next task
|
|
130
|
+
const elapsedTime = Date.now() - startTime;
|
|
131
|
+
if (elapsedTime >= timeoutMs) {
|
|
132
|
+
throw new ZapierTimeoutError(`Batch operation timed out after ${Math.floor(elapsedTime / 1000)}s. ${taskQueue.length} task(s) not completed.`);
|
|
133
|
+
}
|
|
134
|
+
const taskState = taskQueue.shift();
|
|
135
|
+
if (!taskState)
|
|
136
|
+
break;
|
|
137
|
+
await executeTask(taskState);
|
|
138
|
+
// Small delay to prevent burst patterns within a worker
|
|
139
|
+
// Only delay if there are more tasks to process
|
|
140
|
+
if (taskQueue.length > 0 && batchDelay > 0) {
|
|
141
|
+
await setTimeout(batchDelay);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Start workers in small batches to avoid initial burst
|
|
147
|
+
* This helps avoid rate limit triggers when starting many workers
|
|
148
|
+
*/
|
|
149
|
+
const workerCount = Math.min(concurrency, tasks.length);
|
|
150
|
+
const workers = [];
|
|
151
|
+
for (let i = 0; i < workerCount; i++) {
|
|
152
|
+
workers.push(worker());
|
|
153
|
+
// Add small delay between starting workers to stagger the initial requests
|
|
154
|
+
// Skip delay for last worker
|
|
155
|
+
if (i < workerCount - 1 && batchDelay > 0) {
|
|
156
|
+
await setTimeout(batchDelay / 10); // 10ms between worker starts
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Wait for all workers to complete
|
|
160
|
+
await Promise.all(workers);
|
|
161
|
+
return results;
|
|
162
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-utils.test.d.ts","sourceRoot":"","sources":["../../src/utils/batch-utils.test.ts"],"names":[],"mappings":""}
|