@heymantle/core-api-client 0.1.10 → 0.1.11
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/dist/index.d.mts +84 -1
- package/dist/index.d.ts +84 -1
- package/dist/index.js +134 -2
- package/dist/index.mjs +132 -1
- package/package.json +3 -1
package/dist/index.d.mts
CHANGED
|
@@ -3571,4 +3571,87 @@ interface AuthRefreshOptions {
|
|
|
3571
3571
|
*/
|
|
3572
3572
|
declare function createAuthRefreshMiddleware(options: AuthRefreshOptions): Middleware;
|
|
3573
3573
|
|
|
3574
|
-
|
|
3574
|
+
/**
|
|
3575
|
+
* Options for the rate limit middleware
|
|
3576
|
+
*/
|
|
3577
|
+
interface RateLimitOptions {
|
|
3578
|
+
/**
|
|
3579
|
+
* Enable automatic retry on 429 responses
|
|
3580
|
+
* @default false
|
|
3581
|
+
*/
|
|
3582
|
+
enableRetry?: boolean;
|
|
3583
|
+
/**
|
|
3584
|
+
* Enable preemptive throttling to avoid hitting rate limits
|
|
3585
|
+
* @default false
|
|
3586
|
+
*/
|
|
3587
|
+
enableThrottle?: boolean;
|
|
3588
|
+
/**
|
|
3589
|
+
* Maximum number of retry attempts
|
|
3590
|
+
* @default 3
|
|
3591
|
+
*/
|
|
3592
|
+
maxRetries?: number;
|
|
3593
|
+
/**
|
|
3594
|
+
* Base delay in milliseconds for retries when no retryAfter is provided
|
|
3595
|
+
* @default 1000
|
|
3596
|
+
*/
|
|
3597
|
+
baseDelay?: number;
|
|
3598
|
+
/**
|
|
3599
|
+
* Use exponential backoff for retries
|
|
3600
|
+
* @default true
|
|
3601
|
+
*/
|
|
3602
|
+
exponentialBackoff?: boolean;
|
|
3603
|
+
/**
|
|
3604
|
+
* Add random jitter to retry delays to prevent thundering herd
|
|
3605
|
+
* @default true
|
|
3606
|
+
*/
|
|
3607
|
+
jitter?: boolean;
|
|
3608
|
+
/**
|
|
3609
|
+
* Maximum requests per minute (primary limit)
|
|
3610
|
+
* @default 1000
|
|
3611
|
+
*/
|
|
3612
|
+
requestsPerMinute?: number;
|
|
3613
|
+
/**
|
|
3614
|
+
* Maximum requests per burst window
|
|
3615
|
+
* @default 5000
|
|
3616
|
+
*/
|
|
3617
|
+
burstLimit?: number;
|
|
3618
|
+
/**
|
|
3619
|
+
* Burst window in milliseconds
|
|
3620
|
+
* @default 300000 (5 minutes)
|
|
3621
|
+
*/
|
|
3622
|
+
burstWindowMs?: number;
|
|
3623
|
+
/**
|
|
3624
|
+
* Start throttling when usage reaches this percentage of the limit (0-1)
|
|
3625
|
+
* @default 0.9
|
|
3626
|
+
*/
|
|
3627
|
+
throttleThreshold?: number;
|
|
3628
|
+
}
|
|
3629
|
+
/**
|
|
3630
|
+
* Creates a middleware that handles rate limiting with optional retry and throttling
|
|
3631
|
+
*
|
|
3632
|
+
* @example
|
|
3633
|
+
* ```typescript
|
|
3634
|
+
* const client = new MantleCoreClient({ ... });
|
|
3635
|
+
*
|
|
3636
|
+
* // Enable retry on 429 responses
|
|
3637
|
+
* client.use(createRateLimitMiddleware({
|
|
3638
|
+
* enableRetry: true,
|
|
3639
|
+
* }));
|
|
3640
|
+
*
|
|
3641
|
+
* // Enable preemptive throttling
|
|
3642
|
+
* client.use(createRateLimitMiddleware({
|
|
3643
|
+
* enableThrottle: true,
|
|
3644
|
+
* }));
|
|
3645
|
+
*
|
|
3646
|
+
* // Enable both features
|
|
3647
|
+
* client.use(createRateLimitMiddleware({
|
|
3648
|
+
* enableRetry: true,
|
|
3649
|
+
* enableThrottle: true,
|
|
3650
|
+
* maxRetries: 5,
|
|
3651
|
+
* requestsPerMinute: 500,
|
|
3652
|
+
* }));
|
|
3653
|
+
* ```
|
|
3654
|
+
*/
|
|
3655
|
+
declare function createRateLimitMiddleware(options?: RateLimitOptions): Middleware;
|
|
3656
|
+
|
|
3657
|
+
export { type AccountOwner, type AccountOwnersListResponse, type Affiliate, type AffiliateCommission, type AffiliateCommissionListParams, type AffiliateCommissionListResponse, AffiliateCommissionsResource, type AffiliateListParams, type AffiliateListResponse, type AffiliatePayout, type AffiliatePayoutListParams, type AffiliatePayoutListResponse, AffiliatePayoutsResource, type AffiliateProgram, type AffiliateProgramCreateParams, type AffiliateProgramUpdateParams, AffiliateProgramsResource, type AffiliateReferral, type AffiliateReferralListParams, type AffiliateReferralListResponse, AffiliateReferralsResource, type AffiliateUpdateParams, AffiliatesResource, type Agent, type AgentCreateParams, type AgentListResponse, type AgentResponse, AgentsResource, type App, type AppEvent, type AppEventListParams, type AppEventListResponse, type AppInstallation, type AppInstallationParams, type AppListParams, AppsResource, type AuthRefreshOptions, BaseResource, type Channel, type ChannelCreateParams, type ChannelListParams, ChannelsResource, type Charge, type ChargeListParams, type ChargeListResponse, ChargesResource, CompaniesResource, type Company, type CompanyCreateParams, type CompanyListParams, type CompanyListResponse, type CompanyUpdateParams, type Contact, type ContactCreateParams, type ContactEntity, type ContactListParams, type ContactListResponse, type ContactUpdateParams, ContactsResource, type CustomDataDeleteParams, type CustomDataGetParams, CustomDataResource, type CustomDataResourceType, type CustomDataResponse, type CustomDataSetParams, type CustomField, type CustomFieldCreateParams, type CustomFieldUpdateParams, type Customer, type CustomerCreateParams, type CustomerEntity, type CustomerListParams, type CustomerListResponse, type CustomerRetrieveParams, type CustomerSegment, type CustomerSegmentListParams, type CustomerSegmentListResponse, CustomerSegmentsResource, type CustomerUpdateParams, CustomersResource, type DateRangeType, type Deal, DealActivitiesResource, type DealActivity, type DealActivityCreateParams, type DealActivityUpdateParams, type DealContactInput, type DealCreateParams, type DealCustomerInput, type DealEvent, type DealEventCreateParams, type DealEventCreateResponse, type DealEventListResponse, type DealFlow, type DealFlowCreateParams, type DealFlowUpdateParams, DealFlowsResource, type DealListParams, type DealListResponse, type DealStage, type DealUpdateParams, DealsResource, type DeleteResponse, type DocCollection, type DocCollectionCreateParams, type DocCollectionUpdateParams, type DocGroup, type DocGroupCreateParams, type DocGroupUpdateParams, type DocPage, type DocPageCreateParams, type DocPageListParams, type DocPageListResponse, type DocPageStatus, type DocPageUpdateParams, type DocTreeNode, type DocTreeResponse, DocsResource, EntitiesResource, type EntitiesSearchParams, type EntitiesSearchResponse, type Entity, type EntityType, type Feature, type FeatureCreateParams, type FeatureUpdateParams, type Flow, type FlowCreateParams, type FlowListParams, type FlowListResponse, type FlowStatus, type FlowUpdateParams, FlowsResource, type HttpMethod, type ListParams, MantleAPIError, MantleAuthenticationError, MantleCoreClient, type MantleCoreClientConfig, MantleNotFoundError, MantlePermissionError, MantleRateLimitError, MantleValidationError, MeResource, type MeResponse, type MessageAttachment, type MetricDataPoint, type MetricType, type MetricsBaseParams, type MetricsGetParams, MetricsResource, type MetricsResponse, type Middleware, type MiddlewareContext, MiddlewareManager, type MiddlewareOptions, type MiddlewareRequest, type MiddlewareResponse, type NextFunction, type Organization, OrganizationResource, type PaginatedResponse, type Plan, type PlanCreateParams, type PlanFeature, type PlanListParams, type PlanListResponse, type PlanUpdateParams, type PlanUsageCharge, type RateLimitOptions, type RequestOptions, type Review, type ReviewCreateParams, type ReviewUpdateParams, type SocialProfile, type SocialProfileType, type Subscription, type SubscriptionListParams, type SubscriptionListResponse, SubscriptionsResource, type Task, type TaskCreateParams, type TaskListParams, type TaskListResponse, type TaskPriority, type TaskStatus, type TaskUpdateParams, TasksResource, type Ticket, type TicketContactData, type TicketCreateParams, type TicketListParams, type TicketListResponse, type TicketMessage, type TicketMessageCreateParams, type TicketMessageUpdateParams, type TicketUpdateParams, TicketsResource, type TimelineEvent, type TimelineListParams, type TimelineListResponse, type Transaction, type TransactionListParams, type TransactionListResponse, TransactionsResource, type UsageEvent, type UsageEventCreateData, type UsageEventCreateParams, type UsageEventCreateResponse, type UsageEventListParams, type UsageEventListResponse, type UsageEventMetricsParams, UsageEventsResource, type UsageMetric, type UsageMetricCreateParams, type UsageMetricParams, type UsageMetricUpdateParams, type User, type UserListParams, type UserListResponse, UsersResource, type Webhook, type WebhookCreateParams, type WebhookFilter, type WebhookListResponse, type WebhookTopic, type WebhookUpdateParams, WebhooksResource, createAuthRefreshMiddleware, createRateLimitMiddleware };
|
package/dist/index.d.ts
CHANGED
|
@@ -3571,4 +3571,87 @@ interface AuthRefreshOptions {
|
|
|
3571
3571
|
*/
|
|
3572
3572
|
declare function createAuthRefreshMiddleware(options: AuthRefreshOptions): Middleware;
|
|
3573
3573
|
|
|
3574
|
-
|
|
3574
|
+
/**
|
|
3575
|
+
* Options for the rate limit middleware
|
|
3576
|
+
*/
|
|
3577
|
+
interface RateLimitOptions {
|
|
3578
|
+
/**
|
|
3579
|
+
* Enable automatic retry on 429 responses
|
|
3580
|
+
* @default false
|
|
3581
|
+
*/
|
|
3582
|
+
enableRetry?: boolean;
|
|
3583
|
+
/**
|
|
3584
|
+
* Enable preemptive throttling to avoid hitting rate limits
|
|
3585
|
+
* @default false
|
|
3586
|
+
*/
|
|
3587
|
+
enableThrottle?: boolean;
|
|
3588
|
+
/**
|
|
3589
|
+
* Maximum number of retry attempts
|
|
3590
|
+
* @default 3
|
|
3591
|
+
*/
|
|
3592
|
+
maxRetries?: number;
|
|
3593
|
+
/**
|
|
3594
|
+
* Base delay in milliseconds for retries when no retryAfter is provided
|
|
3595
|
+
* @default 1000
|
|
3596
|
+
*/
|
|
3597
|
+
baseDelay?: number;
|
|
3598
|
+
/**
|
|
3599
|
+
* Use exponential backoff for retries
|
|
3600
|
+
* @default true
|
|
3601
|
+
*/
|
|
3602
|
+
exponentialBackoff?: boolean;
|
|
3603
|
+
/**
|
|
3604
|
+
* Add random jitter to retry delays to prevent thundering herd
|
|
3605
|
+
* @default true
|
|
3606
|
+
*/
|
|
3607
|
+
jitter?: boolean;
|
|
3608
|
+
/**
|
|
3609
|
+
* Maximum requests per minute (primary limit)
|
|
3610
|
+
* @default 1000
|
|
3611
|
+
*/
|
|
3612
|
+
requestsPerMinute?: number;
|
|
3613
|
+
/**
|
|
3614
|
+
* Maximum requests per burst window
|
|
3615
|
+
* @default 5000
|
|
3616
|
+
*/
|
|
3617
|
+
burstLimit?: number;
|
|
3618
|
+
/**
|
|
3619
|
+
* Burst window in milliseconds
|
|
3620
|
+
* @default 300000 (5 minutes)
|
|
3621
|
+
*/
|
|
3622
|
+
burstWindowMs?: number;
|
|
3623
|
+
/**
|
|
3624
|
+
* Start throttling when usage reaches this percentage of the limit (0-1)
|
|
3625
|
+
* @default 0.9
|
|
3626
|
+
*/
|
|
3627
|
+
throttleThreshold?: number;
|
|
3628
|
+
}
|
|
3629
|
+
/**
|
|
3630
|
+
* Creates a middleware that handles rate limiting with optional retry and throttling
|
|
3631
|
+
*
|
|
3632
|
+
* @example
|
|
3633
|
+
* ```typescript
|
|
3634
|
+
* const client = new MantleCoreClient({ ... });
|
|
3635
|
+
*
|
|
3636
|
+
* // Enable retry on 429 responses
|
|
3637
|
+
* client.use(createRateLimitMiddleware({
|
|
3638
|
+
* enableRetry: true,
|
|
3639
|
+
* }));
|
|
3640
|
+
*
|
|
3641
|
+
* // Enable preemptive throttling
|
|
3642
|
+
* client.use(createRateLimitMiddleware({
|
|
3643
|
+
* enableThrottle: true,
|
|
3644
|
+
* }));
|
|
3645
|
+
*
|
|
3646
|
+
* // Enable both features
|
|
3647
|
+
* client.use(createRateLimitMiddleware({
|
|
3648
|
+
* enableRetry: true,
|
|
3649
|
+
* enableThrottle: true,
|
|
3650
|
+
* maxRetries: 5,
|
|
3651
|
+
* requestsPerMinute: 500,
|
|
3652
|
+
* }));
|
|
3653
|
+
* ```
|
|
3654
|
+
*/
|
|
3655
|
+
declare function createRateLimitMiddleware(options?: RateLimitOptions): Middleware;
|
|
3656
|
+
|
|
3657
|
+
export { type AccountOwner, type AccountOwnersListResponse, type Affiliate, type AffiliateCommission, type AffiliateCommissionListParams, type AffiliateCommissionListResponse, AffiliateCommissionsResource, type AffiliateListParams, type AffiliateListResponse, type AffiliatePayout, type AffiliatePayoutListParams, type AffiliatePayoutListResponse, AffiliatePayoutsResource, type AffiliateProgram, type AffiliateProgramCreateParams, type AffiliateProgramUpdateParams, AffiliateProgramsResource, type AffiliateReferral, type AffiliateReferralListParams, type AffiliateReferralListResponse, AffiliateReferralsResource, type AffiliateUpdateParams, AffiliatesResource, type Agent, type AgentCreateParams, type AgentListResponse, type AgentResponse, AgentsResource, type App, type AppEvent, type AppEventListParams, type AppEventListResponse, type AppInstallation, type AppInstallationParams, type AppListParams, AppsResource, type AuthRefreshOptions, BaseResource, type Channel, type ChannelCreateParams, type ChannelListParams, ChannelsResource, type Charge, type ChargeListParams, type ChargeListResponse, ChargesResource, CompaniesResource, type Company, type CompanyCreateParams, type CompanyListParams, type CompanyListResponse, type CompanyUpdateParams, type Contact, type ContactCreateParams, type ContactEntity, type ContactListParams, type ContactListResponse, type ContactUpdateParams, ContactsResource, type CustomDataDeleteParams, type CustomDataGetParams, CustomDataResource, type CustomDataResourceType, type CustomDataResponse, type CustomDataSetParams, type CustomField, type CustomFieldCreateParams, type CustomFieldUpdateParams, type Customer, type CustomerCreateParams, type CustomerEntity, type CustomerListParams, type CustomerListResponse, type CustomerRetrieveParams, type CustomerSegment, type CustomerSegmentListParams, type CustomerSegmentListResponse, CustomerSegmentsResource, type CustomerUpdateParams, CustomersResource, type DateRangeType, type Deal, DealActivitiesResource, type DealActivity, type DealActivityCreateParams, type DealActivityUpdateParams, type DealContactInput, type DealCreateParams, type DealCustomerInput, type DealEvent, type DealEventCreateParams, type DealEventCreateResponse, type DealEventListResponse, type DealFlow, type DealFlowCreateParams, type DealFlowUpdateParams, DealFlowsResource, type DealListParams, type DealListResponse, type DealStage, type DealUpdateParams, DealsResource, type DeleteResponse, type DocCollection, type DocCollectionCreateParams, type DocCollectionUpdateParams, type DocGroup, type DocGroupCreateParams, type DocGroupUpdateParams, type DocPage, type DocPageCreateParams, type DocPageListParams, type DocPageListResponse, type DocPageStatus, type DocPageUpdateParams, type DocTreeNode, type DocTreeResponse, DocsResource, EntitiesResource, type EntitiesSearchParams, type EntitiesSearchResponse, type Entity, type EntityType, type Feature, type FeatureCreateParams, type FeatureUpdateParams, type Flow, type FlowCreateParams, type FlowListParams, type FlowListResponse, type FlowStatus, type FlowUpdateParams, FlowsResource, type HttpMethod, type ListParams, MantleAPIError, MantleAuthenticationError, MantleCoreClient, type MantleCoreClientConfig, MantleNotFoundError, MantlePermissionError, MantleRateLimitError, MantleValidationError, MeResource, type MeResponse, type MessageAttachment, type MetricDataPoint, type MetricType, type MetricsBaseParams, type MetricsGetParams, MetricsResource, type MetricsResponse, type Middleware, type MiddlewareContext, MiddlewareManager, type MiddlewareOptions, type MiddlewareRequest, type MiddlewareResponse, type NextFunction, type Organization, OrganizationResource, type PaginatedResponse, type Plan, type PlanCreateParams, type PlanFeature, type PlanListParams, type PlanListResponse, type PlanUpdateParams, type PlanUsageCharge, type RateLimitOptions, type RequestOptions, type Review, type ReviewCreateParams, type ReviewUpdateParams, type SocialProfile, type SocialProfileType, type Subscription, type SubscriptionListParams, type SubscriptionListResponse, SubscriptionsResource, type Task, type TaskCreateParams, type TaskListParams, type TaskListResponse, type TaskPriority, type TaskStatus, type TaskUpdateParams, TasksResource, type Ticket, type TicketContactData, type TicketCreateParams, type TicketListParams, type TicketListResponse, type TicketMessage, type TicketMessageCreateParams, type TicketMessageUpdateParams, type TicketUpdateParams, TicketsResource, type TimelineEvent, type TimelineListParams, type TimelineListResponse, type Transaction, type TransactionListParams, type TransactionListResponse, TransactionsResource, type UsageEvent, type UsageEventCreateData, type UsageEventCreateParams, type UsageEventCreateResponse, type UsageEventListParams, type UsageEventListResponse, type UsageEventMetricsParams, UsageEventsResource, type UsageMetric, type UsageMetricCreateParams, type UsageMetricParams, type UsageMetricUpdateParams, type User, type UserListParams, type UserListResponse, UsersResource, type Webhook, type WebhookCreateParams, type WebhookFilter, type WebhookListResponse, type WebhookTopic, type WebhookUpdateParams, WebhooksResource, createAuthRefreshMiddleware, createRateLimitMiddleware };
|
package/dist/index.js
CHANGED
|
@@ -59,7 +59,8 @@ __export(index_exports, {
|
|
|
59
59
|
UsageEventsResource: () => UsageEventsResource,
|
|
60
60
|
UsersResource: () => UsersResource,
|
|
61
61
|
WebhooksResource: () => WebhooksResource,
|
|
62
|
-
createAuthRefreshMiddleware: () => createAuthRefreshMiddleware
|
|
62
|
+
createAuthRefreshMiddleware: () => createAuthRefreshMiddleware,
|
|
63
|
+
createRateLimitMiddleware: () => createRateLimitMiddleware
|
|
63
64
|
});
|
|
64
65
|
module.exports = __toCommonJS(index_exports);
|
|
65
66
|
|
|
@@ -2254,6 +2255,136 @@ function createAuthRefreshMiddleware(options) {
|
|
|
2254
2255
|
}
|
|
2255
2256
|
};
|
|
2256
2257
|
}
|
|
2258
|
+
|
|
2259
|
+
// src/middleware/rate-limit.ts
|
|
2260
|
+
var RateLimiter = class {
|
|
2261
|
+
constructor(options) {
|
|
2262
|
+
this.timestamps = [];
|
|
2263
|
+
this.requestsPerMinute = options.requestsPerMinute;
|
|
2264
|
+
this.burstLimit = options.burstLimit;
|
|
2265
|
+
this.burstWindowMs = options.burstWindowMs;
|
|
2266
|
+
this.throttleThreshold = options.throttleThreshold;
|
|
2267
|
+
}
|
|
2268
|
+
/**
|
|
2269
|
+
* Prune timestamps older than the burst window
|
|
2270
|
+
*/
|
|
2271
|
+
prune() {
|
|
2272
|
+
const now = Date.now();
|
|
2273
|
+
const cutoff = now - this.burstWindowMs;
|
|
2274
|
+
this.timestamps = this.timestamps.filter((ts) => ts > cutoff);
|
|
2275
|
+
}
|
|
2276
|
+
/**
|
|
2277
|
+
* Get current usage statistics
|
|
2278
|
+
*/
|
|
2279
|
+
getUsage() {
|
|
2280
|
+
this.prune();
|
|
2281
|
+
const now = Date.now();
|
|
2282
|
+
const oneMinuteAgo = now - 6e4;
|
|
2283
|
+
const minuteUsage = this.timestamps.filter((ts) => ts > oneMinuteAgo).length;
|
|
2284
|
+
const burstUsage = this.timestamps.length;
|
|
2285
|
+
return { minuteUsage, burstUsage };
|
|
2286
|
+
}
|
|
2287
|
+
/**
|
|
2288
|
+
* Calculate the delay needed before the next request can be made
|
|
2289
|
+
* Returns 0 if no delay is needed
|
|
2290
|
+
*/
|
|
2291
|
+
getDelay() {
|
|
2292
|
+
const { minuteUsage, burstUsage } = this.getUsage();
|
|
2293
|
+
const minuteThreshold = Math.floor(this.requestsPerMinute * this.throttleThreshold);
|
|
2294
|
+
const burstThreshold = Math.floor(this.burstLimit * this.throttleThreshold);
|
|
2295
|
+
if (minuteUsage >= minuteThreshold) {
|
|
2296
|
+
const now = Date.now();
|
|
2297
|
+
const oneMinuteAgo = now - 6e4;
|
|
2298
|
+
const oldestInMinute = this.timestamps.find((ts) => ts > oneMinuteAgo);
|
|
2299
|
+
if (oldestInMinute) {
|
|
2300
|
+
const delay = oldestInMinute + 6e4 - now;
|
|
2301
|
+
if (delay > 0) {
|
|
2302
|
+
return delay;
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
if (burstUsage >= burstThreshold) {
|
|
2307
|
+
const now = Date.now();
|
|
2308
|
+
const burstCutoff = now - this.burstWindowMs;
|
|
2309
|
+
const oldestInBurst = this.timestamps.find((ts) => ts > burstCutoff);
|
|
2310
|
+
if (oldestInBurst) {
|
|
2311
|
+
const delay = oldestInBurst + this.burstWindowMs - now;
|
|
2312
|
+
if (delay > 0) {
|
|
2313
|
+
return delay;
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
return 0;
|
|
2318
|
+
}
|
|
2319
|
+
/**
|
|
2320
|
+
* Record a request timestamp
|
|
2321
|
+
*/
|
|
2322
|
+
recordRequest() {
|
|
2323
|
+
this.timestamps.push(Date.now());
|
|
2324
|
+
}
|
|
2325
|
+
};
|
|
2326
|
+
function calculateRetryDelay(retryAfter, retryCount, options) {
|
|
2327
|
+
let delay;
|
|
2328
|
+
if (retryAfter !== void 0 && retryAfter > 0) {
|
|
2329
|
+
return retryAfter * 1e3;
|
|
2330
|
+
} else if (options.exponentialBackoff) {
|
|
2331
|
+
delay = options.baseDelay * Math.pow(2, retryCount);
|
|
2332
|
+
} else {
|
|
2333
|
+
delay = options.baseDelay;
|
|
2334
|
+
}
|
|
2335
|
+
if (options.jitter) {
|
|
2336
|
+
const jitterFactor = 0.75 + Math.random() * 0.5;
|
|
2337
|
+
delay = Math.floor(delay * jitterFactor);
|
|
2338
|
+
}
|
|
2339
|
+
return delay;
|
|
2340
|
+
}
|
|
2341
|
+
function createRateLimitMiddleware(options = {}) {
|
|
2342
|
+
const {
|
|
2343
|
+
enableRetry = false,
|
|
2344
|
+
enableThrottle = false,
|
|
2345
|
+
maxRetries = 3,
|
|
2346
|
+
baseDelay = 1e3,
|
|
2347
|
+
exponentialBackoff = true,
|
|
2348
|
+
jitter = true,
|
|
2349
|
+
requestsPerMinute = 1e3,
|
|
2350
|
+
burstLimit = 5e3,
|
|
2351
|
+
burstWindowMs = 3e5,
|
|
2352
|
+
throttleThreshold = 0.9
|
|
2353
|
+
} = options;
|
|
2354
|
+
const rateLimiter = enableThrottle ? new RateLimiter({
|
|
2355
|
+
requestsPerMinute,
|
|
2356
|
+
burstLimit,
|
|
2357
|
+
burstWindowMs,
|
|
2358
|
+
throttleThreshold
|
|
2359
|
+
}) : null;
|
|
2360
|
+
return async (ctx, next) => {
|
|
2361
|
+
if (rateLimiter) {
|
|
2362
|
+
const delay = rateLimiter.getDelay();
|
|
2363
|
+
if (delay > 0) {
|
|
2364
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
try {
|
|
2368
|
+
await next();
|
|
2369
|
+
rateLimiter?.recordRequest();
|
|
2370
|
+
} catch (error) {
|
|
2371
|
+
rateLimiter?.recordRequest();
|
|
2372
|
+
if (enableRetry && error instanceof MantleRateLimitError) {
|
|
2373
|
+
if (ctx.retryCount < maxRetries) {
|
|
2374
|
+
const delay = calculateRetryDelay(error.retryAfter, ctx.retryCount, {
|
|
2375
|
+
baseDelay,
|
|
2376
|
+
exponentialBackoff,
|
|
2377
|
+
jitter
|
|
2378
|
+
});
|
|
2379
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
2380
|
+
ctx.retry = true;
|
|
2381
|
+
return;
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
throw error;
|
|
2385
|
+
}
|
|
2386
|
+
};
|
|
2387
|
+
}
|
|
2257
2388
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2258
2389
|
0 && (module.exports = {
|
|
2259
2390
|
AffiliateCommissionsResource,
|
|
@@ -2295,5 +2426,6 @@ function createAuthRefreshMiddleware(options) {
|
|
|
2295
2426
|
UsageEventsResource,
|
|
2296
2427
|
UsersResource,
|
|
2297
2428
|
WebhooksResource,
|
|
2298
|
-
createAuthRefreshMiddleware
|
|
2429
|
+
createAuthRefreshMiddleware,
|
|
2430
|
+
createRateLimitMiddleware
|
|
2299
2431
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -2189,6 +2189,136 @@ function createAuthRefreshMiddleware(options) {
|
|
|
2189
2189
|
}
|
|
2190
2190
|
};
|
|
2191
2191
|
}
|
|
2192
|
+
|
|
2193
|
+
// src/middleware/rate-limit.ts
|
|
2194
|
+
var RateLimiter = class {
|
|
2195
|
+
constructor(options) {
|
|
2196
|
+
this.timestamps = [];
|
|
2197
|
+
this.requestsPerMinute = options.requestsPerMinute;
|
|
2198
|
+
this.burstLimit = options.burstLimit;
|
|
2199
|
+
this.burstWindowMs = options.burstWindowMs;
|
|
2200
|
+
this.throttleThreshold = options.throttleThreshold;
|
|
2201
|
+
}
|
|
2202
|
+
/**
|
|
2203
|
+
* Prune timestamps older than the burst window
|
|
2204
|
+
*/
|
|
2205
|
+
prune() {
|
|
2206
|
+
const now = Date.now();
|
|
2207
|
+
const cutoff = now - this.burstWindowMs;
|
|
2208
|
+
this.timestamps = this.timestamps.filter((ts) => ts > cutoff);
|
|
2209
|
+
}
|
|
2210
|
+
/**
|
|
2211
|
+
* Get current usage statistics
|
|
2212
|
+
*/
|
|
2213
|
+
getUsage() {
|
|
2214
|
+
this.prune();
|
|
2215
|
+
const now = Date.now();
|
|
2216
|
+
const oneMinuteAgo = now - 6e4;
|
|
2217
|
+
const minuteUsage = this.timestamps.filter((ts) => ts > oneMinuteAgo).length;
|
|
2218
|
+
const burstUsage = this.timestamps.length;
|
|
2219
|
+
return { minuteUsage, burstUsage };
|
|
2220
|
+
}
|
|
2221
|
+
/**
|
|
2222
|
+
* Calculate the delay needed before the next request can be made
|
|
2223
|
+
* Returns 0 if no delay is needed
|
|
2224
|
+
*/
|
|
2225
|
+
getDelay() {
|
|
2226
|
+
const { minuteUsage, burstUsage } = this.getUsage();
|
|
2227
|
+
const minuteThreshold = Math.floor(this.requestsPerMinute * this.throttleThreshold);
|
|
2228
|
+
const burstThreshold = Math.floor(this.burstLimit * this.throttleThreshold);
|
|
2229
|
+
if (minuteUsage >= minuteThreshold) {
|
|
2230
|
+
const now = Date.now();
|
|
2231
|
+
const oneMinuteAgo = now - 6e4;
|
|
2232
|
+
const oldestInMinute = this.timestamps.find((ts) => ts > oneMinuteAgo);
|
|
2233
|
+
if (oldestInMinute) {
|
|
2234
|
+
const delay = oldestInMinute + 6e4 - now;
|
|
2235
|
+
if (delay > 0) {
|
|
2236
|
+
return delay;
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
if (burstUsage >= burstThreshold) {
|
|
2241
|
+
const now = Date.now();
|
|
2242
|
+
const burstCutoff = now - this.burstWindowMs;
|
|
2243
|
+
const oldestInBurst = this.timestamps.find((ts) => ts > burstCutoff);
|
|
2244
|
+
if (oldestInBurst) {
|
|
2245
|
+
const delay = oldestInBurst + this.burstWindowMs - now;
|
|
2246
|
+
if (delay > 0) {
|
|
2247
|
+
return delay;
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
return 0;
|
|
2252
|
+
}
|
|
2253
|
+
/**
|
|
2254
|
+
* Record a request timestamp
|
|
2255
|
+
*/
|
|
2256
|
+
recordRequest() {
|
|
2257
|
+
this.timestamps.push(Date.now());
|
|
2258
|
+
}
|
|
2259
|
+
};
|
|
2260
|
+
function calculateRetryDelay(retryAfter, retryCount, options) {
|
|
2261
|
+
let delay;
|
|
2262
|
+
if (retryAfter !== void 0 && retryAfter > 0) {
|
|
2263
|
+
return retryAfter * 1e3;
|
|
2264
|
+
} else if (options.exponentialBackoff) {
|
|
2265
|
+
delay = options.baseDelay * Math.pow(2, retryCount);
|
|
2266
|
+
} else {
|
|
2267
|
+
delay = options.baseDelay;
|
|
2268
|
+
}
|
|
2269
|
+
if (options.jitter) {
|
|
2270
|
+
const jitterFactor = 0.75 + Math.random() * 0.5;
|
|
2271
|
+
delay = Math.floor(delay * jitterFactor);
|
|
2272
|
+
}
|
|
2273
|
+
return delay;
|
|
2274
|
+
}
|
|
2275
|
+
function createRateLimitMiddleware(options = {}) {
|
|
2276
|
+
const {
|
|
2277
|
+
enableRetry = false,
|
|
2278
|
+
enableThrottle = false,
|
|
2279
|
+
maxRetries = 3,
|
|
2280
|
+
baseDelay = 1e3,
|
|
2281
|
+
exponentialBackoff = true,
|
|
2282
|
+
jitter = true,
|
|
2283
|
+
requestsPerMinute = 1e3,
|
|
2284
|
+
burstLimit = 5e3,
|
|
2285
|
+
burstWindowMs = 3e5,
|
|
2286
|
+
throttleThreshold = 0.9
|
|
2287
|
+
} = options;
|
|
2288
|
+
const rateLimiter = enableThrottle ? new RateLimiter({
|
|
2289
|
+
requestsPerMinute,
|
|
2290
|
+
burstLimit,
|
|
2291
|
+
burstWindowMs,
|
|
2292
|
+
throttleThreshold
|
|
2293
|
+
}) : null;
|
|
2294
|
+
return async (ctx, next) => {
|
|
2295
|
+
if (rateLimiter) {
|
|
2296
|
+
const delay = rateLimiter.getDelay();
|
|
2297
|
+
if (delay > 0) {
|
|
2298
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
try {
|
|
2302
|
+
await next();
|
|
2303
|
+
rateLimiter?.recordRequest();
|
|
2304
|
+
} catch (error) {
|
|
2305
|
+
rateLimiter?.recordRequest();
|
|
2306
|
+
if (enableRetry && error instanceof MantleRateLimitError) {
|
|
2307
|
+
if (ctx.retryCount < maxRetries) {
|
|
2308
|
+
const delay = calculateRetryDelay(error.retryAfter, ctx.retryCount, {
|
|
2309
|
+
baseDelay,
|
|
2310
|
+
exponentialBackoff,
|
|
2311
|
+
jitter
|
|
2312
|
+
});
|
|
2313
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
2314
|
+
ctx.retry = true;
|
|
2315
|
+
return;
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
throw error;
|
|
2319
|
+
}
|
|
2320
|
+
};
|
|
2321
|
+
}
|
|
2192
2322
|
export {
|
|
2193
2323
|
AffiliateCommissionsResource,
|
|
2194
2324
|
AffiliatePayoutsResource,
|
|
@@ -2229,5 +2359,6 @@ export {
|
|
|
2229
2359
|
UsageEventsResource,
|
|
2230
2360
|
UsersResource,
|
|
2231
2361
|
WebhooksResource,
|
|
2232
|
-
createAuthRefreshMiddleware
|
|
2362
|
+
createAuthRefreshMiddleware,
|
|
2363
|
+
createRateLimitMiddleware
|
|
2233
2364
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heymantle/core-api-client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "TypeScript SDK for the Mantle Core API",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
20
20
|
"test": "vitest run",
|
|
21
21
|
"test:watch": "vitest",
|
|
22
|
+
"test:ui": "vitest --ui",
|
|
22
23
|
"test:coverage": "vitest run --coverage",
|
|
23
24
|
"typecheck": "tsc --noEmit",
|
|
24
25
|
"build-and-publish": "npm install && npm run build && npm publish"
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@types/node": "^20.11.0",
|
|
48
49
|
"@vitest/coverage-v8": "^1.2.0",
|
|
50
|
+
"@vitest/ui": "^1.2.0",
|
|
49
51
|
"tsup": "^8.0.2",
|
|
50
52
|
"typescript": "^5.4.3",
|
|
51
53
|
"vitest": "^1.2.0"
|