@zapier/zapier-sdk 0.13.8 → 0.14.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.
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Retry and Backoff Utilities
3
+ *
4
+ * Shared utilities for implementing resilient retry logic with exponential backoff
5
+ * and jitter. Used by both polling and batch operations.
6
+ */
7
+ /**
8
+ * Maximum number of consecutive errors before giving up
9
+ * Prevents infinite retry loops when the API is consistently failing
10
+ */
11
+ export declare const MAX_CONSECUTIVE_ERRORS = 3;
12
+ /**
13
+ * Base delay for error backoff in milliseconds
14
+ * Each error adds this amount (with scaling) to the wait time
15
+ */
16
+ export declare const BASE_ERROR_BACKOFF_MS = 1000;
17
+ /**
18
+ * Jitter factor (0.0 to 1.0) for randomizing wait times
19
+ * Prevents thundering herd problem when many clients retry simultaneously
20
+ * A factor of 0.5 means we add 0-50% random variance to the base interval
21
+ */
22
+ export declare const JITTER_FACTOR = 0.5;
23
+ /**
24
+ * Calculate wait time with jitter and error backoff
25
+ *
26
+ * This implements two key reliability patterns:
27
+ * 1. Jitter - Adds randomness to prevent synchronized retries across clients
28
+ * 2. Error backoff - Increases wait time when errors occur, giving the API time to recover
29
+ *
30
+ * @param baseInterval - The base wait time in milliseconds
31
+ * @param errorCount - Number of consecutive errors (0 if no errors)
32
+ * @returns Wait time in milliseconds with jitter and error backoff applied
33
+ *
34
+ * @example
35
+ * // No errors: returns 1000-1500ms (1000 + 0-500ms jitter)
36
+ * calculateWaitTime(1000, 0);
37
+ *
38
+ * // 2 errors: returns 1000-1500ms base + up to 1000ms error backoff = 1000-2500ms
39
+ * calculateWaitTime(1000, 2);
40
+ *
41
+ * // 6 errors: returns 1000-1500ms base + 2000ms capped backoff = 3000-3500ms
42
+ * calculateWaitTime(1000, 6);
43
+ */
44
+ export declare function calculateWaitTime(baseInterval: number, errorCount: number): number;
45
+ //# sourceMappingURL=retry-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry-utils.d.ts","sourceRoot":"","sources":["../../src/utils/retry-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;;GAGG;AACH,eAAO,MAAM,qBAAqB,OAAQ,CAAC;AAE3C;;;;GAIG;AACH,eAAO,MAAM,aAAa,MAAM,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,MAAM,CAYR"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Retry and Backoff Utilities
3
+ *
4
+ * Shared utilities for implementing resilient retry logic with exponential backoff
5
+ * and jitter. Used by both polling and batch operations.
6
+ */
7
+ /**
8
+ * Maximum number of consecutive errors before giving up
9
+ * Prevents infinite retry loops when the API is consistently failing
10
+ */
11
+ export const MAX_CONSECUTIVE_ERRORS = 3;
12
+ /**
13
+ * Base delay for error backoff in milliseconds
14
+ * Each error adds this amount (with scaling) to the wait time
15
+ */
16
+ export const BASE_ERROR_BACKOFF_MS = 1000;
17
+ /**
18
+ * Jitter factor (0.0 to 1.0) for randomizing wait times
19
+ * Prevents thundering herd problem when many clients retry simultaneously
20
+ * A factor of 0.5 means we add 0-50% random variance to the base interval
21
+ */
22
+ export const JITTER_FACTOR = 0.5;
23
+ /**
24
+ * Calculate wait time with jitter and error backoff
25
+ *
26
+ * This implements two key reliability patterns:
27
+ * 1. Jitter - Adds randomness to prevent synchronized retries across clients
28
+ * 2. Error backoff - Increases wait time when errors occur, giving the API time to recover
29
+ *
30
+ * @param baseInterval - The base wait time in milliseconds
31
+ * @param errorCount - Number of consecutive errors (0 if no errors)
32
+ * @returns Wait time in milliseconds with jitter and error backoff applied
33
+ *
34
+ * @example
35
+ * // No errors: returns 1000-1500ms (1000 + 0-500ms jitter)
36
+ * calculateWaitTime(1000, 0);
37
+ *
38
+ * // 2 errors: returns 1000-1500ms base + up to 1000ms error backoff = 1000-2500ms
39
+ * calculateWaitTime(1000, 2);
40
+ *
41
+ * // 6 errors: returns 1000-1500ms base + 2000ms capped backoff = 3000-3500ms
42
+ * calculateWaitTime(1000, 6);
43
+ */
44
+ export function calculateWaitTime(baseInterval, errorCount) {
45
+ // Jitter to avoid thundering herd (multiple clients retrying at exact same time)
46
+ const jitter = Math.random() * JITTER_FACTOR * baseInterval;
47
+ // Exponential backoff scaled by error count, but capped at 2x base interval
48
+ // This prevents wait times from growing unboundedly
49
+ const errorBackoff = Math.min(BASE_ERROR_BACKOFF_MS * (errorCount / 2), baseInterval * 2);
50
+ return Math.floor(baseInterval + jitter + errorBackoff);
51
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=retry-utils.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry-utils.test.d.ts","sourceRoot":"","sources":["../../src/utils/retry-utils.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,90 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { calculateWaitTime, MAX_CONSECUTIVE_ERRORS, BASE_ERROR_BACKOFF_MS, JITTER_FACTOR, } from "./retry-utils";
3
+ describe("retry-utils", () => {
4
+ describe("calculateWaitTime", () => {
5
+ beforeEach(() => {
6
+ // Seed random for consistent testing
7
+ vi.spyOn(Math, "random");
8
+ });
9
+ afterEach(() => {
10
+ vi.restoreAllMocks();
11
+ });
12
+ it("should return base interval with jitter when no errors", () => {
13
+ vi.spyOn(Math, "random").mockReturnValue(0.5); // Middle of jitter range
14
+ const baseInterval = 1000;
15
+ const waitTime = calculateWaitTime(baseInterval, 0);
16
+ // With 0.5 random and JITTER_FACTOR 0.5:
17
+ // jitter = 0.5 * 0.5 * 1000 = 250ms
18
+ // errorBackoff = 0 (no errors)
19
+ // total = 1000 + 250 + 0 = 1250ms
20
+ expect(waitTime).toBe(1250);
21
+ });
22
+ it("should add error backoff for consecutive errors", () => {
23
+ vi.spyOn(Math, "random").mockReturnValue(0); // No jitter for simpler math
24
+ const baseInterval = 1000;
25
+ const errorCount = 2;
26
+ const waitTime = calculateWaitTime(baseInterval, errorCount);
27
+ // jitter = 0 (random is 0)
28
+ // errorBackoff = BASE_ERROR_BACKOFF_MS * (errorCount / 2) = 1000 * (2/2) = 1000ms
29
+ // total = 1000 + 0 + 1000 = 2000ms
30
+ expect(waitTime).toBe(2000);
31
+ });
32
+ it("should cap error backoff at 2x base interval", () => {
33
+ vi.spyOn(Math, "random").mockReturnValue(0); // No jitter
34
+ const baseInterval = 1000;
35
+ const errorCount = 10; // Large error count
36
+ const waitTime = calculateWaitTime(baseInterval, errorCount);
37
+ // errorBackoff would be 1000 * (10/2) = 5000ms
38
+ // but it's capped at 2x base = 2000ms
39
+ // total = 1000 + 0 + 2000 = 3000ms
40
+ expect(waitTime).toBe(3000);
41
+ });
42
+ it("should add random jitter to prevent thundering herd", () => {
43
+ const baseInterval = 1000;
44
+ const results = new Set();
45
+ // Run multiple times with real random to ensure jitter varies
46
+ vi.spyOn(Math, "random").mockRestore(); // Use real random
47
+ for (let i = 0; i < 10; i++) {
48
+ const waitTime = calculateWaitTime(baseInterval, 0);
49
+ results.add(waitTime);
50
+ }
51
+ // Should have multiple different values due to jitter
52
+ expect(results.size).toBeGreaterThan(1);
53
+ // All values should be in expected range
54
+ // baseInterval (1000) + jitter (0 to JITTER_FACTOR * baseInterval)
55
+ // = 1000 to 1500ms
56
+ for (const result of results) {
57
+ expect(result).toBeGreaterThanOrEqual(1000);
58
+ expect(result).toBeLessThanOrEqual(1500);
59
+ }
60
+ });
61
+ it("should combine jitter and error backoff", () => {
62
+ vi.spyOn(Math, "random").mockReturnValue(0.5);
63
+ const baseInterval = 1000;
64
+ const errorCount = 2;
65
+ const waitTime = calculateWaitTime(baseInterval, errorCount);
66
+ // jitter = 0.5 * 0.5 * 1000 = 250ms
67
+ // errorBackoff = 1000 * (2/2) = 1000ms
68
+ // total = 1000 + 250 + 1000 = 2250ms
69
+ expect(waitTime).toBe(2250);
70
+ });
71
+ it("should return integer wait time", () => {
72
+ vi.spyOn(Math, "random").mockReturnValue(0.333);
73
+ const baseInterval = 1000;
74
+ const waitTime = calculateWaitTime(baseInterval, 1);
75
+ // Result should be floored integer
76
+ expect(Number.isInteger(waitTime)).toBe(true);
77
+ });
78
+ });
79
+ describe("constants", () => {
80
+ it("should export MAX_CONSECUTIVE_ERRORS", () => {
81
+ expect(MAX_CONSECUTIVE_ERRORS).toBe(3);
82
+ });
83
+ it("should export BASE_ERROR_BACKOFF_MS", () => {
84
+ expect(BASE_ERROR_BACKOFF_MS).toBe(1000);
85
+ });
86
+ it("should export JITTER_FACTOR", () => {
87
+ expect(JITTER_FACTOR).toBe(0.5);
88
+ });
89
+ });
90
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zapier/zapier-sdk",
3
- "version": "0.13.8",
3
+ "version": "0.14.0",
4
4
  "description": "Complete Zapier SDK - combines all Zapier SDK packages",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",