lago-javascript-client 1.45.0 → 1.46.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/esm/mod.d.ts CHANGED
@@ -1,5 +1,15 @@
1
1
  import { Api, ApiConfig, HttpResponse } from "./openapi/client.js";
2
- export declare const Client: (apiKey: string, apiConfig?: ApiConfig) => Api<unknown>;
2
+ import type { RateLimitFetchConfig } from "./rate_limit_fetch.js";
3
+ export interface LagoClientConfig extends ApiConfig {
4
+ /**
5
+ * Rate limit retry configuration
6
+ */
7
+ rateLimitRetry?: RateLimitFetchConfig;
8
+ }
9
+ export declare const Client: (apiKey: string, apiConfig?: LagoClientConfig) => Api<unknown>;
3
10
  type ExtractLagoError<E> = E extends (...args: any) => Promise<HttpResponse<infer T, infer P>> ? P : never;
4
11
  export declare function getLagoError<T>(error: any): Promise<ExtractLagoError<T>>;
12
+ export { LagoRateLimitError } from "./rate_limit_error.js";
13
+ export { parseRateLimitHeaders, type RateLimitHeaders } from "./rate_limit_headers.js";
14
+ export { createRateLimitFetch, type RateLimitFetchConfig } from "./rate_limit_fetch.js";
5
15
  export * from "./openapi/client.js";
package/esm/mod.js CHANGED
@@ -1,13 +1,20 @@
1
1
  // deno-lint-ignore-file no-explicit-any
2
2
  import { Api } from "./openapi/client.js";
3
+ import { createRateLimitFetch } from "./rate_limit_fetch.js";
3
4
  export const Client = (apiKey, apiConfig) => {
5
+ const { rateLimitRetry, ...restConfig } = apiConfig ?? {};
6
+ // Create rate-limit-aware fetch if configured
7
+ const customFetch = rateLimitRetry
8
+ ? createRateLimitFetch((restConfig?.customFetch ?? globalThis.fetch), rateLimitRetry)
9
+ : restConfig?.customFetch;
4
10
  const api = new Api({
5
11
  securityWorker: (apiKey) => apiKey ? { headers: { Authorization: `Bearer ${apiKey}` } } : {},
6
12
  // Cloudflare Workers doesn't support some options like credentials so need to override default
7
13
  baseApiParams: {
8
14
  redirect: "follow",
9
15
  },
10
- ...apiConfig,
16
+ ...restConfig,
17
+ ...(customFetch && { customFetch }),
11
18
  });
12
19
  api.setSecurityData(apiKey);
13
20
  return api;
@@ -30,4 +37,8 @@ export async function getLagoError(error) {
30
37
  }
31
38
  throw new Error(error);
32
39
  }
40
+ // Rate limit exports
41
+ export { LagoRateLimitError } from "./rate_limit_error.js";
42
+ export { parseRateLimitHeaders } from "./rate_limit_headers.js";
43
+ export { createRateLimitFetch } from "./rate_limit_fetch.js";
33
44
  export * from "./openapi/client.js";
@@ -2226,6 +2226,16 @@ export interface FeeObject {
2226
2226
  * @example "0.0"
2227
2227
  */
2228
2228
  precise_coupons_amount_cents?: string;
2229
+ /**
2230
+ * The sub total of the fee excluding taxes, in cents.
2231
+ * @example 100
2232
+ */
2233
+ sub_total_excluding_taxes_amount_cents: number;
2234
+ /**
2235
+ * The sub total of the fee excluding taxes, with precision.
2236
+ * @example "100.0"
2237
+ */
2238
+ sub_total_excluding_taxes_precise_amount_cents: string;
2229
2239
  /** List of all unit amount details for calculating the fee. */
2230
2240
  amount_details?: FeeAmountDetails;
2231
2241
  /**
@@ -3837,18 +3847,20 @@ export interface AppliedInvoiceCustomSectionObject {
3837
3847
  * @example "1a901a90-1a90-1a90-1a90-1a901a901a90"
3838
3848
  */
3839
3849
  lago_id: string;
3840
- /**
3841
- * Unique identifier of the invoice custom section that was applied.
3842
- * @format uuid
3843
- * @example "1a901a90-1a90-1a90-1a90-1a901a901a90"
3844
- */
3845
- invoice_custom_section_id: string;
3846
3850
  /**
3847
3851
  * The date of the applied invoice custom section creation, represented in ISO 8601 datetime format and expressed in Coordinated Universal Time (UTC).
3848
3852
  * @format date-time
3849
3853
  * @example "2023-07-06T14:35:58Z"
3850
3854
  */
3851
3855
  created_at: string;
3856
+ /**
3857
+ * Unique identifier of the invoice custom section that was applied.
3858
+ * @deprecated
3859
+ * @format uuid
3860
+ * @example "1a901a90-1a90-1a90-1a90-1a901a901a90"
3861
+ */
3862
+ invoice_custom_section_id?: string;
3863
+ invoice_custom_section: InvoiceCustomSectionObject;
3852
3864
  }
3853
3865
  /** Reference to a specific payment method for processing the payment. */
3854
3866
  export interface PaymentMethodReference {
@@ -10316,7 +10328,9 @@ export declare class Api<SecurityDataType extends unknown> extends HttpClient<Se
10316
10328
  * @request POST:/customers/{external_customer_id}/checkout_url
10317
10329
  * @secure
10318
10330
  */
10319
- generateCustomerCheckoutUrl: (externalCustomerId: string, params?: RequestParams) => Promise<HttpResponse<CustomerCheckoutUrl, ApiErrorUnauthorized | ApiErrorUnprocessableEntity | ApiErrorNotFound>>;
10331
+ generateCustomerCheckoutUrl: (externalCustomerId: string, params?: RequestParams) => Promise<HttpResponse<{
10332
+ customer: CustomerCheckoutUrl;
10333
+ }, ApiErrorUnauthorized | ApiErrorUnprocessableEntity | ApiErrorNotFound>>;
10320
10334
  /**
10321
10335
  * @description This endpoint retrieves all payment methods of a Customer.
10322
10336
  *
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Error class for rate limit (HTTP 429) responses
3
+ */
4
+ export declare class LagoRateLimitError extends Error {
5
+ readonly limit: number;
6
+ readonly remaining: number;
7
+ readonly reset: number;
8
+ readonly retryAfter: number;
9
+ constructor(limit: number, remaining: number, reset: number);
10
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Error class for rate limit (HTTP 429) responses
3
+ */
4
+ export class LagoRateLimitError extends Error {
5
+ limit;
6
+ remaining;
7
+ reset; // seconds until window resets
8
+ retryAfter; // milliseconds to wait before retrying
9
+ constructor(limit, remaining, reset) {
10
+ super(`Rate limit exceeded. Limit: ${limit}, Remaining: ${remaining}, Reset in: ${reset}s`);
11
+ this.name = "LagoRateLimitError";
12
+ this.limit = limit;
13
+ this.remaining = remaining;
14
+ this.reset = reset;
15
+ this.retryAfter = reset * 1000; // Convert seconds to milliseconds
16
+ // Maintain proper prototype chain for instanceof checks
17
+ Object.setPrototypeOf(this, LagoRateLimitError.prototype);
18
+ }
19
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Configuration for rate limit fetch behavior
3
+ */
4
+ export interface RateLimitFetchConfig {
5
+ /** Maximum number of retries on 429 (default: 3) */
6
+ maxRetries?: number;
7
+ /** Whether to automatically retry on rate limit (default: true) */
8
+ retryOnRateLimit?: boolean;
9
+ /** Maximum delay in milliseconds before a retry (default: 20000) */
10
+ maxRetryDelay?: number;
11
+ }
12
+ /**
13
+ * Creates a fetch wrapper that handles rate limiting with automatic retry
14
+ * Compatible with both Node.js fetch and browser fetch APIs
15
+ */
16
+ export declare function createRateLimitFetch(baseFetch: typeof fetch, config?: RateLimitFetchConfig): typeof fetch;
@@ -0,0 +1,76 @@
1
+ import { LagoRateLimitError } from "./rate_limit_error.js";
2
+ import { parseRateLimitHeaders, } from "./rate_limit_headers.js";
3
+ /**
4
+ * Creates a fetch wrapper that handles rate limiting with automatic retry
5
+ * Compatible with both Node.js fetch and browser fetch APIs
6
+ */
7
+ export function createRateLimitFetch(baseFetch, config = {}) {
8
+ const maxRetries = config.maxRetries ?? 3;
9
+ const retryOnRateLimit = config.retryOnRateLimit ?? true;
10
+ const maxRetryDelay = config.maxRetryDelay ?? 20_000;
11
+ return async function rateLimitFetch(input, init) {
12
+ let lastError;
13
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
14
+ try {
15
+ const response = await baseFetch(input, init);
16
+ // Handle 429 responses
17
+ if (response.status === 429) {
18
+ const headers = parseRateLimitHeaders(response.headers);
19
+ const limit = headers.limit ?? -1;
20
+ const remaining = headers.remaining ?? 0;
21
+ const reset = headers.reset ?? -1;
22
+ const error = new LagoRateLimitError(limit, remaining, reset);
23
+ if (!retryOnRateLimit) {
24
+ throw error;
25
+ }
26
+ if (attempt === maxRetries) {
27
+ throw error; // Max retries reached
28
+ }
29
+ // Wait before retry
30
+ const waitMs = getWaitTime(error, attempt, maxRetryDelay);
31
+ await sleep(waitMs);
32
+ continue; // Retry
33
+ }
34
+ // Success or non-rate-limit error - return the response
35
+ return response;
36
+ }
37
+ catch (error) {
38
+ lastError = error;
39
+ if (!(error instanceof LagoRateLimitError)) {
40
+ throw error; // Not a rate limit error, rethrow immediately
41
+ }
42
+ if (attempt === maxRetries) {
43
+ throw error; // Max retries reached
44
+ }
45
+ // Will retry on next iteration
46
+ }
47
+ }
48
+ throw lastError;
49
+ };
50
+ }
51
+ /**
52
+ * Calculate wait time before retry
53
+ * Uses the exact reset time from headers if available, otherwise exponential backoff
54
+ */
55
+ function getWaitTime(error, attempt, maxRetryDelay) {
56
+ let waitMs;
57
+ if (error.reset > 0) {
58
+ // Use the exact reset time from the header
59
+ waitMs = error.retryAfter;
60
+ }
61
+ else {
62
+ // Exponential backoff: 1s, 2s, 4s, 8s, etc.
63
+ waitMs = 1000 * Math.pow(2, attempt);
64
+ }
65
+ // Cap at maxRetryDelay
66
+ waitMs = Math.min(waitMs, maxRetryDelay);
67
+ // Add small jitter to prevent thundering herd (max 100ms)
68
+ const jitter = Math.random() * 100;
69
+ return waitMs + jitter;
70
+ }
71
+ /**
72
+ * Sleep for a specified number of milliseconds
73
+ */
74
+ function sleep(ms) {
75
+ return new Promise((resolve) => setTimeout(resolve, ms));
76
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Parses rate limit headers from HTTP responses
3
+ */
4
+ export interface RateLimitHeaders {
5
+ limit: number | null;
6
+ remaining: number | null;
7
+ reset: number | null;
8
+ }
9
+ /**
10
+ * Extract rate limit information from response headers
11
+ */
12
+ export declare function parseRateLimitHeaders(headers: Headers): RateLimitHeaders;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Extract rate limit information from response headers
3
+ */
4
+ export function parseRateLimitHeaders(headers) {
5
+ return {
6
+ limit: parseHeaderAsNumber(headers, "x-ratelimit-limit"),
7
+ remaining: parseHeaderAsNumber(headers, "x-ratelimit-remaining"),
8
+ reset: parseHeaderAsNumber(headers, "x-ratelimit-reset"),
9
+ };
10
+ }
11
+ /**
12
+ * Helper to parse a header value as a number
13
+ */
14
+ function parseHeaderAsNumber(headers, headerName) {
15
+ const value = headers.get(headerName);
16
+ if (value === null)
17
+ return null;
18
+ const num = parseInt(value, 10);
19
+ return isNaN(num) ? null : num;
20
+ }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "main": "./script/mod.js",
4
4
  "name": "lago-javascript-client",
5
5
  "sideEffects": false,
6
- "version": "v1.45.0",
6
+ "version": "v1.46.0",
7
7
  "description": "Lago JavaScript API Client",
8
8
  "repository": {
9
9
  "type": "git",
package/script/mod.d.ts CHANGED
@@ -1,5 +1,15 @@
1
1
  import { Api, ApiConfig, HttpResponse } from "./openapi/client.js";
2
- export declare const Client: (apiKey: string, apiConfig?: ApiConfig) => Api<unknown>;
2
+ import type { RateLimitFetchConfig } from "./rate_limit_fetch.js";
3
+ export interface LagoClientConfig extends ApiConfig {
4
+ /**
5
+ * Rate limit retry configuration
6
+ */
7
+ rateLimitRetry?: RateLimitFetchConfig;
8
+ }
9
+ export declare const Client: (apiKey: string, apiConfig?: LagoClientConfig) => Api<unknown>;
3
10
  type ExtractLagoError<E> = E extends (...args: any) => Promise<HttpResponse<infer T, infer P>> ? P : never;
4
11
  export declare function getLagoError<T>(error: any): Promise<ExtractLagoError<T>>;
12
+ export { LagoRateLimitError } from "./rate_limit_error.js";
13
+ export { parseRateLimitHeaders, type RateLimitHeaders } from "./rate_limit_headers.js";
14
+ export { createRateLimitFetch, type RateLimitFetchConfig } from "./rate_limit_fetch.js";
5
15
  export * from "./openapi/client.js";
package/script/mod.js CHANGED
@@ -14,17 +14,24 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.getLagoError = exports.Client = void 0;
17
+ exports.createRateLimitFetch = exports.parseRateLimitHeaders = exports.LagoRateLimitError = exports.getLagoError = exports.Client = void 0;
18
18
  // deno-lint-ignore-file no-explicit-any
19
19
  const client_js_1 = require("./openapi/client.js");
20
+ const rate_limit_fetch_js_1 = require("./rate_limit_fetch.js");
20
21
  const Client = (apiKey, apiConfig) => {
22
+ const { rateLimitRetry, ...restConfig } = apiConfig ?? {};
23
+ // Create rate-limit-aware fetch if configured
24
+ const customFetch = rateLimitRetry
25
+ ? (0, rate_limit_fetch_js_1.createRateLimitFetch)((restConfig?.customFetch ?? globalThis.fetch), rateLimitRetry)
26
+ : restConfig?.customFetch;
21
27
  const api = new client_js_1.Api({
22
28
  securityWorker: (apiKey) => apiKey ? { headers: { Authorization: `Bearer ${apiKey}` } } : {},
23
29
  // Cloudflare Workers doesn't support some options like credentials so need to override default
24
30
  baseApiParams: {
25
31
  redirect: "follow",
26
32
  },
27
- ...apiConfig,
33
+ ...restConfig,
34
+ ...(customFetch && { customFetch }),
28
35
  });
29
36
  api.setSecurityData(apiKey);
30
37
  return api;
@@ -49,4 +56,11 @@ async function getLagoError(error) {
49
56
  throw new Error(error);
50
57
  }
51
58
  exports.getLagoError = getLagoError;
59
+ // Rate limit exports
60
+ var rate_limit_error_js_1 = require("./rate_limit_error.js");
61
+ Object.defineProperty(exports, "LagoRateLimitError", { enumerable: true, get: function () { return rate_limit_error_js_1.LagoRateLimitError; } });
62
+ var rate_limit_headers_js_1 = require("./rate_limit_headers.js");
63
+ Object.defineProperty(exports, "parseRateLimitHeaders", { enumerable: true, get: function () { return rate_limit_headers_js_1.parseRateLimitHeaders; } });
64
+ var rate_limit_fetch_js_2 = require("./rate_limit_fetch.js");
65
+ Object.defineProperty(exports, "createRateLimitFetch", { enumerable: true, get: function () { return rate_limit_fetch_js_2.createRateLimitFetch; } });
52
66
  __exportStar(require("./openapi/client.js"), exports);
@@ -2226,6 +2226,16 @@ export interface FeeObject {
2226
2226
  * @example "0.0"
2227
2227
  */
2228
2228
  precise_coupons_amount_cents?: string;
2229
+ /**
2230
+ * The sub total of the fee excluding taxes, in cents.
2231
+ * @example 100
2232
+ */
2233
+ sub_total_excluding_taxes_amount_cents: number;
2234
+ /**
2235
+ * The sub total of the fee excluding taxes, with precision.
2236
+ * @example "100.0"
2237
+ */
2238
+ sub_total_excluding_taxes_precise_amount_cents: string;
2229
2239
  /** List of all unit amount details for calculating the fee. */
2230
2240
  amount_details?: FeeAmountDetails;
2231
2241
  /**
@@ -3837,18 +3847,20 @@ export interface AppliedInvoiceCustomSectionObject {
3837
3847
  * @example "1a901a90-1a90-1a90-1a90-1a901a901a90"
3838
3848
  */
3839
3849
  lago_id: string;
3840
- /**
3841
- * Unique identifier of the invoice custom section that was applied.
3842
- * @format uuid
3843
- * @example "1a901a90-1a90-1a90-1a90-1a901a901a90"
3844
- */
3845
- invoice_custom_section_id: string;
3846
3850
  /**
3847
3851
  * The date of the applied invoice custom section creation, represented in ISO 8601 datetime format and expressed in Coordinated Universal Time (UTC).
3848
3852
  * @format date-time
3849
3853
  * @example "2023-07-06T14:35:58Z"
3850
3854
  */
3851
3855
  created_at: string;
3856
+ /**
3857
+ * Unique identifier of the invoice custom section that was applied.
3858
+ * @deprecated
3859
+ * @format uuid
3860
+ * @example "1a901a90-1a90-1a90-1a90-1a901a901a90"
3861
+ */
3862
+ invoice_custom_section_id?: string;
3863
+ invoice_custom_section: InvoiceCustomSectionObject;
3852
3864
  }
3853
3865
  /** Reference to a specific payment method for processing the payment. */
3854
3866
  export interface PaymentMethodReference {
@@ -10316,7 +10328,9 @@ export declare class Api<SecurityDataType extends unknown> extends HttpClient<Se
10316
10328
  * @request POST:/customers/{external_customer_id}/checkout_url
10317
10329
  * @secure
10318
10330
  */
10319
- generateCustomerCheckoutUrl: (externalCustomerId: string, params?: RequestParams) => Promise<HttpResponse<CustomerCheckoutUrl, ApiErrorUnauthorized | ApiErrorUnprocessableEntity | ApiErrorNotFound>>;
10331
+ generateCustomerCheckoutUrl: (externalCustomerId: string, params?: RequestParams) => Promise<HttpResponse<{
10332
+ customer: CustomerCheckoutUrl;
10333
+ }, ApiErrorUnauthorized | ApiErrorUnprocessableEntity | ApiErrorNotFound>>;
10320
10334
  /**
10321
10335
  * @description This endpoint retrieves all payment methods of a Customer.
10322
10336
  *
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Error class for rate limit (HTTP 429) responses
3
+ */
4
+ export declare class LagoRateLimitError extends Error {
5
+ readonly limit: number;
6
+ readonly remaining: number;
7
+ readonly reset: number;
8
+ readonly retryAfter: number;
9
+ constructor(limit: number, remaining: number, reset: number);
10
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LagoRateLimitError = void 0;
4
+ /**
5
+ * Error class for rate limit (HTTP 429) responses
6
+ */
7
+ class LagoRateLimitError extends Error {
8
+ limit;
9
+ remaining;
10
+ reset; // seconds until window resets
11
+ retryAfter; // milliseconds to wait before retrying
12
+ constructor(limit, remaining, reset) {
13
+ super(`Rate limit exceeded. Limit: ${limit}, Remaining: ${remaining}, Reset in: ${reset}s`);
14
+ this.name = "LagoRateLimitError";
15
+ this.limit = limit;
16
+ this.remaining = remaining;
17
+ this.reset = reset;
18
+ this.retryAfter = reset * 1000; // Convert seconds to milliseconds
19
+ // Maintain proper prototype chain for instanceof checks
20
+ Object.setPrototypeOf(this, LagoRateLimitError.prototype);
21
+ }
22
+ }
23
+ exports.LagoRateLimitError = LagoRateLimitError;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Configuration for rate limit fetch behavior
3
+ */
4
+ export interface RateLimitFetchConfig {
5
+ /** Maximum number of retries on 429 (default: 3) */
6
+ maxRetries?: number;
7
+ /** Whether to automatically retry on rate limit (default: true) */
8
+ retryOnRateLimit?: boolean;
9
+ /** Maximum delay in milliseconds before a retry (default: 20000) */
10
+ maxRetryDelay?: number;
11
+ }
12
+ /**
13
+ * Creates a fetch wrapper that handles rate limiting with automatic retry
14
+ * Compatible with both Node.js fetch and browser fetch APIs
15
+ */
16
+ export declare function createRateLimitFetch(baseFetch: typeof fetch, config?: RateLimitFetchConfig): typeof fetch;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createRateLimitFetch = void 0;
4
+ const rate_limit_error_js_1 = require("./rate_limit_error.js");
5
+ const rate_limit_headers_js_1 = require("./rate_limit_headers.js");
6
+ /**
7
+ * Creates a fetch wrapper that handles rate limiting with automatic retry
8
+ * Compatible with both Node.js fetch and browser fetch APIs
9
+ */
10
+ function createRateLimitFetch(baseFetch, config = {}) {
11
+ const maxRetries = config.maxRetries ?? 3;
12
+ const retryOnRateLimit = config.retryOnRateLimit ?? true;
13
+ const maxRetryDelay = config.maxRetryDelay ?? 20_000;
14
+ return async function rateLimitFetch(input, init) {
15
+ let lastError;
16
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
17
+ try {
18
+ const response = await baseFetch(input, init);
19
+ // Handle 429 responses
20
+ if (response.status === 429) {
21
+ const headers = (0, rate_limit_headers_js_1.parseRateLimitHeaders)(response.headers);
22
+ const limit = headers.limit ?? -1;
23
+ const remaining = headers.remaining ?? 0;
24
+ const reset = headers.reset ?? -1;
25
+ const error = new rate_limit_error_js_1.LagoRateLimitError(limit, remaining, reset);
26
+ if (!retryOnRateLimit) {
27
+ throw error;
28
+ }
29
+ if (attempt === maxRetries) {
30
+ throw error; // Max retries reached
31
+ }
32
+ // Wait before retry
33
+ const waitMs = getWaitTime(error, attempt, maxRetryDelay);
34
+ await sleep(waitMs);
35
+ continue; // Retry
36
+ }
37
+ // Success or non-rate-limit error - return the response
38
+ return response;
39
+ }
40
+ catch (error) {
41
+ lastError = error;
42
+ if (!(error instanceof rate_limit_error_js_1.LagoRateLimitError)) {
43
+ throw error; // Not a rate limit error, rethrow immediately
44
+ }
45
+ if (attempt === maxRetries) {
46
+ throw error; // Max retries reached
47
+ }
48
+ // Will retry on next iteration
49
+ }
50
+ }
51
+ throw lastError;
52
+ };
53
+ }
54
+ exports.createRateLimitFetch = createRateLimitFetch;
55
+ /**
56
+ * Calculate wait time before retry
57
+ * Uses the exact reset time from headers if available, otherwise exponential backoff
58
+ */
59
+ function getWaitTime(error, attempt, maxRetryDelay) {
60
+ let waitMs;
61
+ if (error.reset > 0) {
62
+ // Use the exact reset time from the header
63
+ waitMs = error.retryAfter;
64
+ }
65
+ else {
66
+ // Exponential backoff: 1s, 2s, 4s, 8s, etc.
67
+ waitMs = 1000 * Math.pow(2, attempt);
68
+ }
69
+ // Cap at maxRetryDelay
70
+ waitMs = Math.min(waitMs, maxRetryDelay);
71
+ // Add small jitter to prevent thundering herd (max 100ms)
72
+ const jitter = Math.random() * 100;
73
+ return waitMs + jitter;
74
+ }
75
+ /**
76
+ * Sleep for a specified number of milliseconds
77
+ */
78
+ function sleep(ms) {
79
+ return new Promise((resolve) => setTimeout(resolve, ms));
80
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Parses rate limit headers from HTTP responses
3
+ */
4
+ export interface RateLimitHeaders {
5
+ limit: number | null;
6
+ remaining: number | null;
7
+ reset: number | null;
8
+ }
9
+ /**
10
+ * Extract rate limit information from response headers
11
+ */
12
+ export declare function parseRateLimitHeaders(headers: Headers): RateLimitHeaders;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseRateLimitHeaders = void 0;
4
+ /**
5
+ * Extract rate limit information from response headers
6
+ */
7
+ function parseRateLimitHeaders(headers) {
8
+ return {
9
+ limit: parseHeaderAsNumber(headers, "x-ratelimit-limit"),
10
+ remaining: parseHeaderAsNumber(headers, "x-ratelimit-remaining"),
11
+ reset: parseHeaderAsNumber(headers, "x-ratelimit-reset"),
12
+ };
13
+ }
14
+ exports.parseRateLimitHeaders = parseRateLimitHeaders;
15
+ /**
16
+ * Helper to parse a header value as a number
17
+ */
18
+ function parseHeaderAsNumber(headers, headerName) {
19
+ const value = headers.get(headerName);
20
+ if (value === null)
21
+ return null;
22
+ const num = parseInt(value, 10);
23
+ return isNaN(num) ? null : num;
24
+ }