ezthrottle 1.0.0 → 1.1.1

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/README.md CHANGED
@@ -1,28 +1,280 @@
1
1
  # EZThrottle Node.js SDK
2
2
 
3
- The World's First API Aqueduct.
3
+ The API Dam for rate-limited services. Queue and execute HTTP requests with smart retry logic, multi-region racing, and webhook delivery.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install @tracktags/ezthrottle
8
+ npm install ezthrottle
9
9
  ```
10
10
 
11
11
  ## Quick Start
12
12
 
13
13
  ```javascript
14
- const { EZThrottle } = require('@tracktags/ezthrottle');
14
+ const { EZThrottle, Step, StepType } = require('ezthrottle');
15
15
 
16
- const client = new EZThrottle({
17
- apiKey: 'ck_live_cust_XXX_YYY',
18
- });
16
+ const client = new EZThrottle({ apiKey: 'your_api_key' });
17
+
18
+ // Simple job submission
19
+ const result = await new Step(client)
20
+ .url('https://api.example.com/endpoint')
21
+ .method('POST')
22
+ .type(StepType.PERFORMANCE)
23
+ .webhooks([{ url: 'https://your-app.com/webhook' }])
24
+ .execute();
25
+
26
+ console.log(`Job ID: ${result.job_id}`);
27
+ ```
28
+
29
+ ## Step Types
30
+
31
+ ### StepType.PERFORMANCE (Server-side execution)
32
+
33
+ Submit jobs to EZThrottle for distributed execution with multi-region racing and webhook delivery.
34
+
35
+ ```javascript
36
+ await new Step(client)
37
+ .url('https://api.stripe.com/charges')
38
+ .type(StepType.PERFORMANCE)
39
+ .webhooks([{ url: 'https://app.com/webhook' }])
40
+ .regions(['iad', 'lax', 'ord']) // Multi-region racing
41
+ .executionMode('race') // First completion wins
42
+ .execute();
43
+ ```
44
+
45
+ ### StepType.FRUGAL (Client-side first)
46
+
47
+ Execute locally first, only forward to EZThrottle on specific error codes. Saves money!
48
+
49
+ ```javascript
50
+ await new Step(client)
51
+ .url('https://api.example.com')
52
+ .type(StepType.FRUGAL)
53
+ .fallbackOnError([429, 500, 503]) // Forward to EZThrottle on these codes
54
+ .execute();
55
+ ```
56
+
57
+ ## Idempotent Key Strategies
58
+
59
+ **Critical concept:** Idempotent keys prevent duplicate job execution. Choose the right strategy for your use case.
60
+
61
+ ### IdempotentStrategy.HASH (Default)
62
+
63
+ Backend generates deterministic hash of (url, method, body, customer_id). **Prevents duplicates.**
64
+
65
+ **Use when:**
66
+ - Payment processing (don't charge twice!)
67
+ - Critical operations (create user, send notification)
68
+ - You want automatic deduplication
69
+
70
+ **Example:**
71
+ ```javascript
72
+ const { IdempotentStrategy } = require('ezthrottle');
73
+
74
+ // Prevents duplicate charges - same request = rejected as duplicate
75
+ await new Step(client)
76
+ .url('https://api.stripe.com/charges')
77
+ .body(JSON.stringify({ amount: 1000, currency: 'usd' }))
78
+ .idempotentStrategy(IdempotentStrategy.HASH) // Default
79
+ .execute();
80
+ ```
81
+
82
+ ### IdempotentStrategy.UNIQUE
83
+
84
+ SDK generates unique UUID per request. **Allows duplicates.**
85
+
86
+ **Use when:**
87
+ - Polling endpoints (same URL, different data each time)
88
+ - Webhooks (want to send every time)
89
+ - Scheduled jobs (run every minute/hour)
90
+ - GET requests that return changing data
91
+
92
+ **Example:**
93
+ ```javascript
94
+ // Poll API every minute - each request gets unique UUID
95
+ setInterval(async () => {
96
+ await new Step(client)
97
+ .url('https://api.example.com/status')
98
+ .idempotentStrategy(IdempotentStrategy.UNIQUE) // New UUID each time
99
+ .execute();
100
+ }, 60000);
101
+ ```
102
+
103
+ ## Workflow Chaining
104
+
105
+ Chain steps together with `.onSuccess()`, `.onFailure()`, and `.fallback()`:
106
+
107
+ ```javascript
108
+ // Analytics step (cheap)
109
+ const analytics = new Step(client)
110
+ .url('https://analytics.com/track')
111
+ .type(StepType.FRUGAL);
112
+
113
+ // Notification (fast, distributed)
114
+ const notification = new Step(client)
115
+ .url('https://notify.com')
116
+ .type(StepType.PERFORMANCE)
117
+ .webhooks([{ url: 'https://app.com/webhook' }])
118
+ .regions(['iad', 'lax'])
119
+ .onSuccess(analytics);
120
+
121
+ // Primary API call (cheap local execution)
122
+ await new Step(client)
123
+ .url('https://api.example.com')
124
+ .type(StepType.FRUGAL)
125
+ .fallbackOnError([429, 500])
126
+ .onSuccess(notification)
127
+ .execute();
128
+ ```
129
+
130
+ ## Fallback Chains
131
+
132
+ Handle failures with automatic fallback execution:
133
+
134
+ ```javascript
135
+ const backupApi = new Step().url('https://backup-api.com');
136
+
137
+ await new Step(client)
138
+ .url('https://primary-api.com')
139
+ .fallback(backupApi, { triggerOnError: [500, 502, 503] })
140
+ .execute();
141
+ ```
142
+
143
+ ## Multi-Region Racing
19
144
 
20
- const result = await client.queueRequest({
21
- url: 'https://api.example.com/data',
22
- webhookUrl: 'https://myapp.com/webhook',
145
+ Submit jobs to multiple regions, fastest wins:
146
+
147
+ ```javascript
148
+ await new Step(client)
149
+ .url('https://api.example.com')
150
+ .regions(['iad', 'lax', 'ord']) // Try all 3 regions
151
+ .regionPolicy('fallback') // Auto-route if region down
152
+ .executionMode('race') // First completion wins
153
+ .webhooks([{ url: 'https://app.com/webhook' }])
154
+ .execute();
155
+ ```
156
+
157
+ ## Webhook Fanout (Multiple Webhooks)
158
+
159
+ Deliver job results to multiple services simultaneously:
160
+
161
+ ```javascript
162
+ await new Step(client)
163
+ .url('https://api.stripe.com/charges')
164
+ .method('POST')
165
+ .webhooks([
166
+ // Primary webhook (must succeed)
167
+ { url: 'https://app.com/payment-complete', has_quorum_vote: true },
168
+
169
+ // Analytics webhook (optional)
170
+ { url: 'https://analytics.com/track', has_quorum_vote: false },
171
+
172
+ // Notification service (must succeed)
173
+ { url: 'https://notify.com/alert', has_quorum_vote: true },
174
+
175
+ // Multi-region webhook racing
176
+ { url: 'https://backup.com/webhook', regions: ['iad', 'lax'], has_quorum_vote: true }
177
+ ])
178
+ .webhookQuorum(2) // At least 2 webhooks with has_quorum_vote=true must succeed
179
+ .execute();
180
+ ```
181
+
182
+ ## Retry Policies
183
+
184
+ Customize retry behavior:
185
+
186
+ ```javascript
187
+ await new Step(client)
188
+ .url('https://api.example.com')
189
+ .retryPolicy({
190
+ max_retries: 5,
191
+ max_reroutes: 3,
192
+ retry_codes: [429, 503], // Retry in same region
193
+ reroute_codes: [500, 502, 504] // Try different region
194
+ })
195
+ .execute();
196
+ ```
197
+
198
+ ## Production Ready ✅
199
+
200
+ This SDK is production-ready with **working examples validated in CI on every push**.
201
+
202
+ ### Reference Implementation: test-app/
203
+
204
+ The `test-app/` directory contains **real, working code** you can learn from. Not toy examples - this is production code we run in automated tests against live EZThrottle backend.
205
+
206
+ **Multi-Region Racing** ([test-app/app.js:104-122](test-app/app.js#L104-L122))
207
+ ```javascript
208
+ await new Step(client)
209
+ .url('https://httpbin.org/delay/1')
210
+ .type(StepType.PERFORMANCE)
211
+ .webhooks([{ url: `${APP_URL}/webhook` }])
212
+ .regions(['iad', 'lax', 'ord']) // Race across 3 regions
213
+ .executionMode('race') // First completion wins
214
+ .execute();
215
+ ```
216
+
217
+ **Idempotent HASH (Deduplication)** ([test-app/app.js:181-203](test-app/app.js#L181-L203))
218
+ ```javascript
219
+ // Same request twice = same job_id (deduplicated)
220
+ await new Step(client)
221
+ .url(`https://httpbin.org/get?run=${runId}`)
222
+ .idempotentStrategy(IdempotentStrategy.HASH)
223
+ .execute();
224
+ ```
225
+
226
+ **Fallback Chain** ([test-app/app.js:125-154](test-app/app.js#L125-L154))
227
+ ```javascript
228
+ await new Step(client)
229
+ .url('https://httpbin.org/status/500')
230
+ .fallback(
231
+ new Step().url('https://httpbin.org/status/200'),
232
+ { triggerOnError: [500, 502, 503] }
233
+ )
234
+ .execute();
235
+ ```
236
+
237
+ **On-Success Workflow** ([test-app/app.js:157-178](test-app/app.js#L157-L178))
238
+ ```javascript
239
+ await new Step(client)
240
+ .url('https://httpbin.org/status/200')
241
+ .onSuccess(
242
+ new Step().url('https://httpbin.org/delay/1')
243
+ )
244
+ .execute();
245
+ ```
246
+
247
+ **FRUGAL Local Execution** ([test-app/app.js:247-260](test-app/app.js#L247-L260))
248
+ ```javascript
249
+ await new Step(client)
250
+ .url('https://httpbin.org/status/200')
251
+ .type(StepType.FRUGAL)
252
+ .execute();
253
+ ```
254
+
255
+ **Validated in CI:**
256
+ - ✅ GitHub Actions runs these examples against live backend on every push
257
+ - ✅ 7 integration tests covering all SDK features
258
+ - ✅ Proves the code actually works, not just documentation
259
+
260
+ ## Legacy API (Deprecated)
261
+
262
+ For backward compatibility, the old `queueRequest()` method is still available:
263
+
264
+ ```javascript
265
+ await client.queueRequest({
266
+ url: 'https://api.example.com',
267
+ webhookUrl: 'https://your-app.com/webhook', // Note: singular
268
+ method: 'POST'
23
269
  });
270
+ ```
271
+
272
+ **Prefer the new `Step` builder API for all new code!**
24
273
 
25
- console.log('Job queued:', result.job_id);
274
+ ## Environment Variables
275
+
276
+ ```bash
277
+ EZTHROTTLE_API_KEY=your_api_key_here
26
278
  ```
27
279
 
28
280
  ## License
@@ -0,0 +1,58 @@
1
+ import { EZThrottleConfig, SubmitJobParams } from './types';
2
+ interface QueueRequestParams {
3
+ url: string;
4
+ webhookUrl?: string;
5
+ method?: string;
6
+ headers?: Record<string, string>;
7
+ body?: string;
8
+ metadata?: Record<string, any>;
9
+ retryAt?: number;
10
+ }
11
+ interface QueueAndWaitParams extends QueueRequestParams {
12
+ timeout?: number;
13
+ pollInterval?: number;
14
+ }
15
+ interface RequestParams {
16
+ url: string;
17
+ method?: string;
18
+ headers?: Record<string, string>;
19
+ body?: string;
20
+ }
21
+ export declare class EZThrottle {
22
+ private apiKey;
23
+ private tracktagsUrl;
24
+ private ezthrottleUrl;
25
+ constructor({ apiKey, tracktagsUrl, ezthrottleUrl }: EZThrottleConfig);
26
+ /**
27
+ * Submit a job through TracktTags proxy → EZThrottle (NEW API with full features)
28
+ *
29
+ * @param {Object} options - Job configuration
30
+ * @param {string} options.url - Target URL to request
31
+ * @param {string} [options.method='GET'] - HTTP method
32
+ * @param {Object} [options.headers] - Request headers
33
+ * @param {string} [options.body] - Request body
34
+ * @param {Object} [options.metadata] - Custom metadata
35
+ * @param {Array} [options.webhooks] - Array of webhook configs: [{url, regions, hasQuorumVote}]
36
+ * @param {number} [options.webhookQuorum=1] - Minimum webhooks that must succeed
37
+ * @param {Array<string>} [options.regions] - Regions to execute in (e.g., ['iad', 'lax', 'ord'])
38
+ * @param {string} [options.regionPolicy='fallback'] - 'fallback' or 'strict'
39
+ * @param {string} [options.executionMode='race'] - 'race' or 'fanout'
40
+ * @param {Object} [options.retryPolicy] - Retry configuration
41
+ * @param {Object} [options.fallbackJob] - Recursive fallback configuration
42
+ * @param {Object} [options.onSuccess] - Job to spawn on success
43
+ * @param {Object} [options.onFailure] - Job to spawn on failure
44
+ * @param {number} [options.onFailureTimeoutMs] - Timeout before triggering onFailure
45
+ * @param {string} [options.idempotentKey] - Deduplication key
46
+ * @param {number} [options.retryAt] - Timestamp (ms) when job can be retried
47
+ * @returns {Promise<Object>} - {job_id, status, ...}
48
+ */
49
+ submitJob({ url, method, headers, body, metadata, webhooks, webhookQuorum, regions, regionPolicy, executionMode, retryPolicy, fallbackJob, onSuccess, onFailure, onFailureTimeoutMs, idempotentKey, retryAt, }: SubmitJobParams): Promise<any>;
50
+ /**
51
+ * DEPRECATED: Use submitJob() instead
52
+ * Legacy method for backward compatibility
53
+ */
54
+ queueRequest({ url, webhookUrl, method, headers, body, metadata, retryAt }: QueueRequestParams): Promise<any>;
55
+ request({ url, method, headers, body }: RequestParams): Promise<any>;
56
+ queueAndWait({ url, webhookUrl, method, headers, body, metadata, retryAt, timeout, pollInterval, }: QueueAndWaitParams): Promise<any>;
57
+ }
58
+ export {};
package/dist/client.js ADDED
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.EZThrottle = void 0;
7
+ const node_fetch_1 = __importDefault(require("node-fetch"));
8
+ const errors_1 = require("./errors");
9
+ class EZThrottle {
10
+ constructor({ apiKey, tracktagsUrl, ezthrottleUrl }) {
11
+ if (!apiKey) {
12
+ throw new Error('apiKey is required');
13
+ }
14
+ this.apiKey = apiKey;
15
+ this.tracktagsUrl = tracktagsUrl || 'https://tracktags.fly.dev';
16
+ this.ezthrottleUrl = ezthrottleUrl || 'https://ezthrottle.fly.dev';
17
+ }
18
+ /**
19
+ * Submit a job through TracktTags proxy → EZThrottle (NEW API with full features)
20
+ *
21
+ * @param {Object} options - Job configuration
22
+ * @param {string} options.url - Target URL to request
23
+ * @param {string} [options.method='GET'] - HTTP method
24
+ * @param {Object} [options.headers] - Request headers
25
+ * @param {string} [options.body] - Request body
26
+ * @param {Object} [options.metadata] - Custom metadata
27
+ * @param {Array} [options.webhooks] - Array of webhook configs: [{url, regions, hasQuorumVote}]
28
+ * @param {number} [options.webhookQuorum=1] - Minimum webhooks that must succeed
29
+ * @param {Array<string>} [options.regions] - Regions to execute in (e.g., ['iad', 'lax', 'ord'])
30
+ * @param {string} [options.regionPolicy='fallback'] - 'fallback' or 'strict'
31
+ * @param {string} [options.executionMode='race'] - 'race' or 'fanout'
32
+ * @param {Object} [options.retryPolicy] - Retry configuration
33
+ * @param {Object} [options.fallbackJob] - Recursive fallback configuration
34
+ * @param {Object} [options.onSuccess] - Job to spawn on success
35
+ * @param {Object} [options.onFailure] - Job to spawn on failure
36
+ * @param {number} [options.onFailureTimeoutMs] - Timeout before triggering onFailure
37
+ * @param {string} [options.idempotentKey] - Deduplication key
38
+ * @param {number} [options.retryAt] - Timestamp (ms) when job can be retried
39
+ * @returns {Promise<Object>} - {job_id, status, ...}
40
+ */
41
+ async submitJob({ url, method = 'GET', headers, body, metadata, webhooks, webhookQuorum = 1, regions, regionPolicy = 'fallback', executionMode = 'race', retryPolicy, fallbackJob, onSuccess, onFailure, onFailureTimeoutMs, idempotentKey, retryAt, }) {
42
+ // Build EZThrottle job payload
43
+ const jobPayload = {
44
+ url,
45
+ method: method.toUpperCase(),
46
+ };
47
+ // Add optional parameters
48
+ if (headers)
49
+ jobPayload.headers = headers;
50
+ if (body)
51
+ jobPayload.body = body;
52
+ if (metadata)
53
+ jobPayload.metadata = metadata;
54
+ if (webhooks)
55
+ jobPayload.webhooks = webhooks;
56
+ if (webhookQuorum !== 1)
57
+ jobPayload.webhook_quorum = webhookQuorum;
58
+ if (regions)
59
+ jobPayload.regions = regions;
60
+ if (regionPolicy !== 'fallback')
61
+ jobPayload.region_policy = regionPolicy;
62
+ if (executionMode !== 'race')
63
+ jobPayload.execution_mode = executionMode;
64
+ if (retryPolicy)
65
+ jobPayload.retry_policy = retryPolicy;
66
+ if (fallbackJob)
67
+ jobPayload.fallback_job = fallbackJob;
68
+ if (onSuccess)
69
+ jobPayload.on_success = onSuccess;
70
+ if (onFailure)
71
+ jobPayload.on_failure = onFailure;
72
+ if (onFailureTimeoutMs !== undefined)
73
+ jobPayload.on_failure_timeout_ms = onFailureTimeoutMs;
74
+ if (idempotentKey)
75
+ jobPayload.idempotent_key = idempotentKey;
76
+ if (retryAt !== undefined)
77
+ jobPayload.retry_at = retryAt;
78
+ console.log('[SDK] Sending jobPayload with idempotent_key:', jobPayload.idempotent_key);
79
+ // Build proxy request
80
+ const proxyPayload = {
81
+ scope: 'customer',
82
+ metric_name: '',
83
+ target_url: `${this.ezthrottleUrl}/api/v1/jobs`,
84
+ method: 'POST',
85
+ headers: {
86
+ 'Content-Type': 'application/json',
87
+ },
88
+ body: JSON.stringify(jobPayload),
89
+ };
90
+ const response = await (0, node_fetch_1.default)(`${this.tracktagsUrl}/api/v1/proxy`, {
91
+ method: 'POST',
92
+ headers: {
93
+ 'Authorization': `Bearer ${this.apiKey}`,
94
+ 'Content-Type': 'application/json',
95
+ },
96
+ body: JSON.stringify(proxyPayload),
97
+ });
98
+ // Handle proxy responses
99
+ if (response.status === 429) {
100
+ const errorData = await response.json();
101
+ const retryAfterSeconds = response.headers.get('retry-after');
102
+ let calculatedRetryAt = errorData.retry_at;
103
+ if (retryAfterSeconds && !calculatedRetryAt) {
104
+ calculatedRetryAt = Date.now() + (parseInt(retryAfterSeconds) * 1000);
105
+ }
106
+ throw new errors_1.RateLimitError(`Rate limited: ${errorData.error || 'Unknown error'}`, calculatedRetryAt);
107
+ }
108
+ if (response.status !== 200) {
109
+ const text = await response.text();
110
+ throw new errors_1.EZThrottleError(`Proxy request failed: ${text}`);
111
+ }
112
+ const proxyResponse = await response.json();
113
+ if (proxyResponse.status !== 'allowed') {
114
+ throw new errors_1.EZThrottleError(`Request denied: ${proxyResponse.error || 'Unknown error'}`);
115
+ }
116
+ const forwarded = proxyResponse.forwarded_response || {};
117
+ const statusCode = forwarded.status_code || 0;
118
+ if (statusCode < 200 || statusCode >= 300) {
119
+ throw new errors_1.EZThrottleError(`EZThrottle job creation failed: ${forwarded.body || 'Unknown error'}`);
120
+ }
121
+ const ezthrottleResponse = JSON.parse(forwarded.body || '{}');
122
+ return ezthrottleResponse;
123
+ }
124
+ /**
125
+ * DEPRECATED: Use submitJob() instead
126
+ * Legacy method for backward compatibility
127
+ */
128
+ async queueRequest({ url, webhookUrl, method = 'GET', headers, body, metadata, retryAt }) {
129
+ // Convert singular webhookUrl to webhooks array
130
+ const webhooks = webhookUrl
131
+ ? [{ url: webhookUrl, has_quorum_vote: true }]
132
+ : undefined;
133
+ return this.submitJob({
134
+ url,
135
+ method,
136
+ headers,
137
+ body,
138
+ metadata,
139
+ webhooks,
140
+ retryAt,
141
+ });
142
+ }
143
+ async request({ url, method = 'GET', headers, body }) {
144
+ return (0, node_fetch_1.default)(url, {
145
+ method,
146
+ headers,
147
+ body,
148
+ });
149
+ }
150
+ async queueAndWait({ url, webhookUrl, method = 'GET', headers, body, metadata, retryAt, timeout = 300000, pollInterval = 2000, }) {
151
+ const result = await this.queueRequest({
152
+ url,
153
+ webhookUrl,
154
+ method,
155
+ headers,
156
+ body,
157
+ metadata,
158
+ retryAt,
159
+ });
160
+ const jobId = result.job_id;
161
+ if (!jobId) {
162
+ throw new errors_1.EZThrottleError('No job_id in response');
163
+ }
164
+ const startTime = Date.now();
165
+ return new Promise((resolve, reject) => {
166
+ const checkResult = async () => {
167
+ if (Date.now() - startTime > timeout) {
168
+ reject(new errors_1.TimeoutError(`Timeout waiting for job ${jobId}`));
169
+ return;
170
+ }
171
+ setTimeout(checkResult, pollInterval);
172
+ };
173
+ checkResult();
174
+ });
175
+ }
176
+ }
177
+ exports.EZThrottle = EZThrottle;
@@ -0,0 +1,10 @@
1
+ export declare class EZThrottleError extends Error {
2
+ retryAt: number | null;
3
+ constructor(message: string, retryAt?: number | null);
4
+ }
5
+ export declare class TimeoutError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ export declare class RateLimitError extends EZThrottleError {
9
+ constructor(message: string, retryAt: number);
10
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RateLimitError = exports.TimeoutError = exports.EZThrottleError = void 0;
4
+ class EZThrottleError extends Error {
5
+ constructor(message, retryAt = null) {
6
+ super(message);
7
+ this.name = 'EZThrottleError';
8
+ this.retryAt = retryAt;
9
+ }
10
+ }
11
+ exports.EZThrottleError = EZThrottleError;
12
+ class TimeoutError extends Error {
13
+ constructor(message) {
14
+ super(message);
15
+ this.name = 'TimeoutError';
16
+ }
17
+ }
18
+ exports.TimeoutError = TimeoutError;
19
+ class RateLimitError extends EZThrottleError {
20
+ constructor(message, retryAt) {
21
+ super(message, retryAt);
22
+ this.name = 'RateLimitError';
23
+ }
24
+ }
25
+ exports.RateLimitError = RateLimitError;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Idempotent key generation strategy
3
+ */
4
+ export declare enum IdempotentStrategy {
5
+ /** Backend generates deterministic hash - prevents duplicates (DEFAULT) */
6
+ HASH = "hash",
7
+ /** SDK generates UUID - allows duplicates (polling, webhooks, scheduled jobs) */
8
+ UNIQUE = "unique"
9
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IdempotentStrategy = void 0;
4
+ /**
5
+ * Idempotent key generation strategy
6
+ */
7
+ var IdempotentStrategy;
8
+ (function (IdempotentStrategy) {
9
+ /** Backend generates deterministic hash - prevents duplicates (DEFAULT) */
10
+ IdempotentStrategy["HASH"] = "hash";
11
+ /** SDK generates UUID - allows duplicates (polling, webhooks, scheduled jobs) */
12
+ IdempotentStrategy["UNIQUE"] = "unique";
13
+ })(IdempotentStrategy || (exports.IdempotentStrategy = IdempotentStrategy = {}));
@@ -0,0 +1,8 @@
1
+ export { EZThrottle } from './client';
2
+ export { EZThrottleError, TimeoutError, RateLimitError } from './errors';
3
+ export { Step } from './step';
4
+ export { StepType } from './stepType';
5
+ export { IdempotentStrategy } from './idempotentStrategy';
6
+ export * from './types';
7
+ import { EZThrottle } from './client';
8
+ export default EZThrottle;
package/dist/index.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.IdempotentStrategy = exports.StepType = exports.Step = exports.RateLimitError = exports.TimeoutError = exports.EZThrottleError = exports.EZThrottle = void 0;
18
+ var client_1 = require("./client");
19
+ Object.defineProperty(exports, "EZThrottle", { enumerable: true, get: function () { return client_1.EZThrottle; } });
20
+ var errors_1 = require("./errors");
21
+ Object.defineProperty(exports, "EZThrottleError", { enumerable: true, get: function () { return errors_1.EZThrottleError; } });
22
+ Object.defineProperty(exports, "TimeoutError", { enumerable: true, get: function () { return errors_1.TimeoutError; } });
23
+ Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return errors_1.RateLimitError; } });
24
+ var step_1 = require("./step");
25
+ Object.defineProperty(exports, "Step", { enumerable: true, get: function () { return step_1.Step; } });
26
+ var stepType_1 = require("./stepType");
27
+ Object.defineProperty(exports, "StepType", { enumerable: true, get: function () { return stepType_1.StepType; } });
28
+ var idempotentStrategy_1 = require("./idempotentStrategy");
29
+ Object.defineProperty(exports, "IdempotentStrategy", { enumerable: true, get: function () { return idempotentStrategy_1.IdempotentStrategy; } });
30
+ __exportStar(require("./types"), exports);
31
+ // Default export for CommonJS compatibility
32
+ const client_2 = require("./client");
33
+ exports.default = client_2.EZThrottle;