@heymantle/core-api-client 0.1.3 → 0.1.5

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 CHANGED
@@ -1,3 +1,89 @@
1
+ /**
2
+ * Middleware types for the Mantle Core API Client
3
+ */
4
+ /**
5
+ * HTTP methods supported by the client
6
+ */
7
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
8
+ /**
9
+ * Request information passed through the middleware chain
10
+ */
11
+ interface MiddlewareRequest {
12
+ /** Full URL (baseURL + endpoint) */
13
+ url: string;
14
+ /** HTTP method */
15
+ method: HttpMethod;
16
+ /** Request headers */
17
+ headers: Record<string, string>;
18
+ /** Request body (for POST/PUT) */
19
+ body?: string;
20
+ /** Original endpoint (before baseURL prepend) */
21
+ endpoint: string;
22
+ }
23
+ /**
24
+ * Response information returned through the middleware chain
25
+ */
26
+ interface MiddlewareResponse<T = unknown> {
27
+ /** Parsed response data */
28
+ data: T;
29
+ /** HTTP status code */
30
+ status: number;
31
+ /** Response headers */
32
+ headers: Headers;
33
+ }
34
+ /**
35
+ * Context object passed to middleware functions
36
+ */
37
+ interface MiddlewareContext<T = unknown> {
38
+ /** The request being made */
39
+ request: MiddlewareRequest;
40
+ /** The response (populated after downstream execution) */
41
+ response?: MiddlewareResponse<T>;
42
+ /** Error that occurred (if any) */
43
+ error?: Error;
44
+ /** Set to true to retry the request */
45
+ retry: boolean;
46
+ /** Number of retry attempts made */
47
+ retryCount: number;
48
+ /** Maximum retry attempts allowed (default: 3) */
49
+ maxRetries: number;
50
+ /** Update the client's auth credentials */
51
+ updateAuth: (credentials: {
52
+ apiKey?: string;
53
+ accessToken?: string;
54
+ }) => void;
55
+ }
56
+ /**
57
+ * Next function to call the next middleware in the chain
58
+ */
59
+ type NextFunction = () => Promise<void>;
60
+ /**
61
+ * Middleware function signature (Koa-style)
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * const loggingMiddleware: Middleware = async (ctx, next) => {
66
+ * console.log('Request:', ctx.request.url)
67
+ * await next()
68
+ * console.log('Response:', ctx.response?.status)
69
+ * }
70
+ * ```
71
+ */
72
+ type Middleware<T = unknown> = (ctx: MiddlewareContext<T>, next: NextFunction) => Promise<void>;
73
+ /**
74
+ * Options for registering middleware
75
+ */
76
+ interface MiddlewareOptions {
77
+ /** Unique name for debugging/removal */
78
+ name?: string;
79
+ /** Priority (lower = earlier execution, default: 100) */
80
+ priority?: number;
81
+ }
82
+
83
+ /**
84
+ * Middleware configuration item
85
+ */
86
+ type MiddlewareConfig = Middleware | [Middleware, MiddlewareOptions];
1
87
  /**
2
88
  * Configuration for the MantleCoreClient
3
89
  */
@@ -10,6 +96,8 @@ interface MantleCoreClientConfig {
10
96
  accessToken?: string;
11
97
  /** Request timeout in milliseconds. Defaults to 30000 */
12
98
  timeout?: number;
99
+ /** Middleware to register on instantiation */
100
+ middleware?: MiddlewareConfig[];
13
101
  }
14
102
  /**
15
103
  * Generic paginated list response
@@ -734,6 +822,54 @@ interface DealListParams extends ListParams {
734
822
  interface DealListResponse extends PaginatedResponse {
735
823
  deals: Deal[];
736
824
  }
825
+ /**
826
+ * Inline customer data for deal creation/update.
827
+ * Matches existing customers by domain or shopifyDomain.
828
+ * If no match found, creates a new customer.
829
+ */
830
+ interface DealCustomerInput {
831
+ /** The name of the customer */
832
+ name?: string;
833
+ /** The email of the customer */
834
+ email?: string;
835
+ /** The domain of the customer (used for matching existing customers) */
836
+ domain?: string;
837
+ /** The Shopify domain of the customer (used for matching existing customers) */
838
+ shopifyDomain?: string;
839
+ /** The Shopify shop ID */
840
+ shopifyShopId?: string;
841
+ /** Tags to associate with the customer */
842
+ tags?: string[];
843
+ /** Custom fields for the customer */
844
+ customFields?: Record<string, unknown>;
845
+ /** The country code of the customer */
846
+ countryCode?: string;
847
+ /** The preferred currency of the customer */
848
+ preferredCurrency?: string;
849
+ /** Description of the customer */
850
+ description?: string;
851
+ }
852
+ /**
853
+ * Inline contact data for deal creation/update.
854
+ * Matches existing contacts by email.
855
+ * Contacts are linked to both the customer and the deal.
856
+ */
857
+ interface DealContactInput {
858
+ /** The email of the contact (required, used for matching existing contacts) */
859
+ email: string;
860
+ /** The name of the contact */
861
+ name?: string;
862
+ /** The phone number of the contact */
863
+ phone?: string;
864
+ /** The job title of the contact */
865
+ jobTitle?: string;
866
+ /** The label for the contact relationship (e.g., "primary", "technical") */
867
+ label?: string;
868
+ /** Notes about the contact */
869
+ notes?: string;
870
+ /** Tags for the contact */
871
+ tags?: string[];
872
+ }
737
873
  /**
738
874
  * Parameters for creating a deal
739
875
  */
@@ -748,14 +884,26 @@ interface DealCreateParams {
748
884
  closedAt?: string;
749
885
  dealFlowId?: string;
750
886
  dealStageId?: string;
887
+ /** The ID of an existing customer (alternative to customer object) */
751
888
  customerId?: string;
889
+ /**
890
+ * Create or update a customer inline (alternative to customerId).
891
+ * Matches existing customers by domain or shopifyDomain.
892
+ */
893
+ customer?: DealCustomerInput;
752
894
  domain?: string;
753
895
  shopifyDomain?: string;
754
896
  companyId?: string;
755
897
  appId?: string;
756
898
  planId?: string;
757
899
  ownerIds?: string[];
900
+ /** Array of existing contact IDs (alternative to contacts array) */
758
901
  contactIds?: string[];
902
+ /**
903
+ * Create or update contacts inline (alternative to contactIds).
904
+ * Matches existing contacts by email. Contacts are linked to both the customer and the deal.
905
+ */
906
+ contacts?: DealContactInput[];
759
907
  notes?: string;
760
908
  affiliateId?: string;
761
909
  partnershipId?: string;
@@ -2850,9 +2998,10 @@ declare class EntitiesResource extends BaseResource {
2850
2998
  */
2851
2999
  declare class MantleCoreClient {
2852
3000
  private readonly baseURL;
2853
- private readonly apiKey?;
2854
- private readonly accessToken?;
3001
+ private apiKey?;
3002
+ private accessToken?;
2855
3003
  private readonly timeout;
3004
+ private readonly middlewareManager;
2856
3005
  readonly customers: CustomersResource;
2857
3006
  readonly contacts: ContactsResource;
2858
3007
  readonly subscriptions: SubscriptionsResource;
@@ -2883,6 +3032,40 @@ declare class MantleCoreClient {
2883
3032
  readonly docs: DocsResource;
2884
3033
  readonly entities: EntitiesResource;
2885
3034
  constructor(config: MantleCoreClientConfig);
3035
+ /**
3036
+ * Register a middleware function
3037
+ *
3038
+ * @param middleware - The middleware function to register
3039
+ * @param options - Optional configuration (name, priority)
3040
+ * @returns this for chaining
3041
+ *
3042
+ * @example
3043
+ * ```typescript
3044
+ * client.use(async (ctx, next) => {
3045
+ * console.log('Request:', ctx.request.url);
3046
+ * await next();
3047
+ * console.log('Response:', ctx.response?.status);
3048
+ * });
3049
+ * ```
3050
+ */
3051
+ use(middleware: Middleware, options?: MiddlewareOptions): this;
3052
+ /**
3053
+ * Remove a middleware by name
3054
+ *
3055
+ * @param name - The name of the middleware to remove
3056
+ * @returns true if removed, false if not found
3057
+ */
3058
+ removeMiddleware(name: string): boolean;
3059
+ /**
3060
+ * Update authentication credentials
3061
+ * Useful for middleware that needs to refresh tokens
3062
+ *
3063
+ * @param credentials - New credentials to set
3064
+ */
3065
+ updateAuth(credentials: {
3066
+ apiKey?: string;
3067
+ accessToken?: string;
3068
+ }): void;
2886
3069
  /**
2887
3070
  * Performs a GET request to the API
2888
3071
  */
@@ -2903,6 +3086,14 @@ declare class MantleCoreClient {
2903
3086
  * Makes an HTTP request to the API
2904
3087
  */
2905
3088
  private makeRequest;
3089
+ /**
3090
+ * Execute request through middleware chain
3091
+ */
3092
+ private makeRequestWithMiddleware;
3093
+ /**
3094
+ * Direct request execution (no middleware)
3095
+ */
3096
+ private executeRequest;
2906
3097
  /**
2907
3098
  * Gets the authorization header value
2908
3099
  */
@@ -2957,4 +3148,92 @@ declare class MantleRateLimitError extends MantleAPIError {
2957
3148
  constructor(message?: string, retryAfter?: number);
2958
3149
  }
2959
3150
 
2960
- 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 AgentListResponse, AgentsResource, type App, type AppEvent, type AppEventListParams, type AppEventListResponse, type AppInstallation, type AppInstallationParams, type AppListParams, AppsResource, 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 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 DealCreateParams, 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 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 Organization, OrganizationResource, type PaginatedResponse, type Plan, type PlanCreateParams, type PlanFeature, type PlanListParams, type PlanListResponse, type PlanUpdateParams, type PlanUsageCharge, 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 };
3151
+ /**
3152
+ * Manages middleware registration and execution
3153
+ */
3154
+ declare class MiddlewareManager {
3155
+ private middlewares;
3156
+ /**
3157
+ * Register a middleware function
3158
+ *
3159
+ * @param middleware - The middleware function to register
3160
+ * @param options - Optional configuration
3161
+ * @returns this for chaining
3162
+ */
3163
+ use(middleware: Middleware, options?: MiddlewareOptions): this;
3164
+ /**
3165
+ * Remove a middleware by name
3166
+ *
3167
+ * @param name - The name of the middleware to remove
3168
+ * @returns true if removed, false if not found
3169
+ */
3170
+ remove(name: string): boolean;
3171
+ /**
3172
+ * Get all registered middleware names
3173
+ */
3174
+ list(): string[];
3175
+ /**
3176
+ * Check if any middleware is registered
3177
+ */
3178
+ hasMiddleware(): boolean;
3179
+ /**
3180
+ * Execute the middleware chain with retry support
3181
+ *
3182
+ * @param ctx - The middleware context
3183
+ * @param coreHandler - The core request handler to call at the end of the chain
3184
+ * @returns The response from the core handler
3185
+ */
3186
+ execute<T>(ctx: MiddlewareContext<T>, coreHandler: () => Promise<MiddlewareResponse<T>>): Promise<MiddlewareResponse<T>>;
3187
+ /**
3188
+ * Run the middleware chain (onion model)
3189
+ */
3190
+ private runChain;
3191
+ }
3192
+
3193
+ /**
3194
+ * Options for the auth refresh middleware
3195
+ */
3196
+ interface AuthRefreshOptions {
3197
+ /**
3198
+ * Function to refresh the access token
3199
+ * Should return the new access token
3200
+ */
3201
+ refreshToken: () => Promise<string>;
3202
+ /**
3203
+ * Optional callback when refresh succeeds
3204
+ */
3205
+ onRefreshSuccess?: (newToken: string) => void;
3206
+ /**
3207
+ * Optional callback when refresh fails
3208
+ */
3209
+ onRefreshFailed?: (error: Error) => void;
3210
+ /**
3211
+ * Maximum refresh attempts per request (default: 1)
3212
+ */
3213
+ maxRefreshAttempts?: number;
3214
+ }
3215
+ /**
3216
+ * Creates a middleware that automatically refreshes access tokens on 401 errors
3217
+ *
3218
+ * @example
3219
+ * ```typescript
3220
+ * const client = new MantleCoreClient({
3221
+ * accessToken: 'initial-token',
3222
+ * });
3223
+ *
3224
+ * client.use(createAuthRefreshMiddleware({
3225
+ * refreshToken: async () => {
3226
+ * const response = await fetch('/refresh', { method: 'POST' });
3227
+ * const data = await response.json();
3228
+ * return data.accessToken;
3229
+ * },
3230
+ * onRefreshSuccess: (newToken) => {
3231
+ * // Persist the new token
3232
+ * localStorage.setItem('accessToken', newToken);
3233
+ * },
3234
+ * }), { name: 'auth-refresh' });
3235
+ * ```
3236
+ */
3237
+ declare function createAuthRefreshMiddleware(options: AuthRefreshOptions): Middleware;
3238
+
3239
+ 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 AgentListResponse, 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 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 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 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 };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,89 @@
1
+ /**
2
+ * Middleware types for the Mantle Core API Client
3
+ */
4
+ /**
5
+ * HTTP methods supported by the client
6
+ */
7
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
8
+ /**
9
+ * Request information passed through the middleware chain
10
+ */
11
+ interface MiddlewareRequest {
12
+ /** Full URL (baseURL + endpoint) */
13
+ url: string;
14
+ /** HTTP method */
15
+ method: HttpMethod;
16
+ /** Request headers */
17
+ headers: Record<string, string>;
18
+ /** Request body (for POST/PUT) */
19
+ body?: string;
20
+ /** Original endpoint (before baseURL prepend) */
21
+ endpoint: string;
22
+ }
23
+ /**
24
+ * Response information returned through the middleware chain
25
+ */
26
+ interface MiddlewareResponse<T = unknown> {
27
+ /** Parsed response data */
28
+ data: T;
29
+ /** HTTP status code */
30
+ status: number;
31
+ /** Response headers */
32
+ headers: Headers;
33
+ }
34
+ /**
35
+ * Context object passed to middleware functions
36
+ */
37
+ interface MiddlewareContext<T = unknown> {
38
+ /** The request being made */
39
+ request: MiddlewareRequest;
40
+ /** The response (populated after downstream execution) */
41
+ response?: MiddlewareResponse<T>;
42
+ /** Error that occurred (if any) */
43
+ error?: Error;
44
+ /** Set to true to retry the request */
45
+ retry: boolean;
46
+ /** Number of retry attempts made */
47
+ retryCount: number;
48
+ /** Maximum retry attempts allowed (default: 3) */
49
+ maxRetries: number;
50
+ /** Update the client's auth credentials */
51
+ updateAuth: (credentials: {
52
+ apiKey?: string;
53
+ accessToken?: string;
54
+ }) => void;
55
+ }
56
+ /**
57
+ * Next function to call the next middleware in the chain
58
+ */
59
+ type NextFunction = () => Promise<void>;
60
+ /**
61
+ * Middleware function signature (Koa-style)
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * const loggingMiddleware: Middleware = async (ctx, next) => {
66
+ * console.log('Request:', ctx.request.url)
67
+ * await next()
68
+ * console.log('Response:', ctx.response?.status)
69
+ * }
70
+ * ```
71
+ */
72
+ type Middleware<T = unknown> = (ctx: MiddlewareContext<T>, next: NextFunction) => Promise<void>;
73
+ /**
74
+ * Options for registering middleware
75
+ */
76
+ interface MiddlewareOptions {
77
+ /** Unique name for debugging/removal */
78
+ name?: string;
79
+ /** Priority (lower = earlier execution, default: 100) */
80
+ priority?: number;
81
+ }
82
+
83
+ /**
84
+ * Middleware configuration item
85
+ */
86
+ type MiddlewareConfig = Middleware | [Middleware, MiddlewareOptions];
1
87
  /**
2
88
  * Configuration for the MantleCoreClient
3
89
  */
@@ -10,6 +96,8 @@ interface MantleCoreClientConfig {
10
96
  accessToken?: string;
11
97
  /** Request timeout in milliseconds. Defaults to 30000 */
12
98
  timeout?: number;
99
+ /** Middleware to register on instantiation */
100
+ middleware?: MiddlewareConfig[];
13
101
  }
14
102
  /**
15
103
  * Generic paginated list response
@@ -734,6 +822,54 @@ interface DealListParams extends ListParams {
734
822
  interface DealListResponse extends PaginatedResponse {
735
823
  deals: Deal[];
736
824
  }
825
+ /**
826
+ * Inline customer data for deal creation/update.
827
+ * Matches existing customers by domain or shopifyDomain.
828
+ * If no match found, creates a new customer.
829
+ */
830
+ interface DealCustomerInput {
831
+ /** The name of the customer */
832
+ name?: string;
833
+ /** The email of the customer */
834
+ email?: string;
835
+ /** The domain of the customer (used for matching existing customers) */
836
+ domain?: string;
837
+ /** The Shopify domain of the customer (used for matching existing customers) */
838
+ shopifyDomain?: string;
839
+ /** The Shopify shop ID */
840
+ shopifyShopId?: string;
841
+ /** Tags to associate with the customer */
842
+ tags?: string[];
843
+ /** Custom fields for the customer */
844
+ customFields?: Record<string, unknown>;
845
+ /** The country code of the customer */
846
+ countryCode?: string;
847
+ /** The preferred currency of the customer */
848
+ preferredCurrency?: string;
849
+ /** Description of the customer */
850
+ description?: string;
851
+ }
852
+ /**
853
+ * Inline contact data for deal creation/update.
854
+ * Matches existing contacts by email.
855
+ * Contacts are linked to both the customer and the deal.
856
+ */
857
+ interface DealContactInput {
858
+ /** The email of the contact (required, used for matching existing contacts) */
859
+ email: string;
860
+ /** The name of the contact */
861
+ name?: string;
862
+ /** The phone number of the contact */
863
+ phone?: string;
864
+ /** The job title of the contact */
865
+ jobTitle?: string;
866
+ /** The label for the contact relationship (e.g., "primary", "technical") */
867
+ label?: string;
868
+ /** Notes about the contact */
869
+ notes?: string;
870
+ /** Tags for the contact */
871
+ tags?: string[];
872
+ }
737
873
  /**
738
874
  * Parameters for creating a deal
739
875
  */
@@ -748,14 +884,26 @@ interface DealCreateParams {
748
884
  closedAt?: string;
749
885
  dealFlowId?: string;
750
886
  dealStageId?: string;
887
+ /** The ID of an existing customer (alternative to customer object) */
751
888
  customerId?: string;
889
+ /**
890
+ * Create or update a customer inline (alternative to customerId).
891
+ * Matches existing customers by domain or shopifyDomain.
892
+ */
893
+ customer?: DealCustomerInput;
752
894
  domain?: string;
753
895
  shopifyDomain?: string;
754
896
  companyId?: string;
755
897
  appId?: string;
756
898
  planId?: string;
757
899
  ownerIds?: string[];
900
+ /** Array of existing contact IDs (alternative to contacts array) */
758
901
  contactIds?: string[];
902
+ /**
903
+ * Create or update contacts inline (alternative to contactIds).
904
+ * Matches existing contacts by email. Contacts are linked to both the customer and the deal.
905
+ */
906
+ contacts?: DealContactInput[];
759
907
  notes?: string;
760
908
  affiliateId?: string;
761
909
  partnershipId?: string;
@@ -2850,9 +2998,10 @@ declare class EntitiesResource extends BaseResource {
2850
2998
  */
2851
2999
  declare class MantleCoreClient {
2852
3000
  private readonly baseURL;
2853
- private readonly apiKey?;
2854
- private readonly accessToken?;
3001
+ private apiKey?;
3002
+ private accessToken?;
2855
3003
  private readonly timeout;
3004
+ private readonly middlewareManager;
2856
3005
  readonly customers: CustomersResource;
2857
3006
  readonly contacts: ContactsResource;
2858
3007
  readonly subscriptions: SubscriptionsResource;
@@ -2883,6 +3032,40 @@ declare class MantleCoreClient {
2883
3032
  readonly docs: DocsResource;
2884
3033
  readonly entities: EntitiesResource;
2885
3034
  constructor(config: MantleCoreClientConfig);
3035
+ /**
3036
+ * Register a middleware function
3037
+ *
3038
+ * @param middleware - The middleware function to register
3039
+ * @param options - Optional configuration (name, priority)
3040
+ * @returns this for chaining
3041
+ *
3042
+ * @example
3043
+ * ```typescript
3044
+ * client.use(async (ctx, next) => {
3045
+ * console.log('Request:', ctx.request.url);
3046
+ * await next();
3047
+ * console.log('Response:', ctx.response?.status);
3048
+ * });
3049
+ * ```
3050
+ */
3051
+ use(middleware: Middleware, options?: MiddlewareOptions): this;
3052
+ /**
3053
+ * Remove a middleware by name
3054
+ *
3055
+ * @param name - The name of the middleware to remove
3056
+ * @returns true if removed, false if not found
3057
+ */
3058
+ removeMiddleware(name: string): boolean;
3059
+ /**
3060
+ * Update authentication credentials
3061
+ * Useful for middleware that needs to refresh tokens
3062
+ *
3063
+ * @param credentials - New credentials to set
3064
+ */
3065
+ updateAuth(credentials: {
3066
+ apiKey?: string;
3067
+ accessToken?: string;
3068
+ }): void;
2886
3069
  /**
2887
3070
  * Performs a GET request to the API
2888
3071
  */
@@ -2903,6 +3086,14 @@ declare class MantleCoreClient {
2903
3086
  * Makes an HTTP request to the API
2904
3087
  */
2905
3088
  private makeRequest;
3089
+ /**
3090
+ * Execute request through middleware chain
3091
+ */
3092
+ private makeRequestWithMiddleware;
3093
+ /**
3094
+ * Direct request execution (no middleware)
3095
+ */
3096
+ private executeRequest;
2906
3097
  /**
2907
3098
  * Gets the authorization header value
2908
3099
  */
@@ -2957,4 +3148,92 @@ declare class MantleRateLimitError extends MantleAPIError {
2957
3148
  constructor(message?: string, retryAfter?: number);
2958
3149
  }
2959
3150
 
2960
- 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 AgentListResponse, AgentsResource, type App, type AppEvent, type AppEventListParams, type AppEventListResponse, type AppInstallation, type AppInstallationParams, type AppListParams, AppsResource, 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 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 DealCreateParams, 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 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 Organization, OrganizationResource, type PaginatedResponse, type Plan, type PlanCreateParams, type PlanFeature, type PlanListParams, type PlanListResponse, type PlanUpdateParams, type PlanUsageCharge, 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 };
3151
+ /**
3152
+ * Manages middleware registration and execution
3153
+ */
3154
+ declare class MiddlewareManager {
3155
+ private middlewares;
3156
+ /**
3157
+ * Register a middleware function
3158
+ *
3159
+ * @param middleware - The middleware function to register
3160
+ * @param options - Optional configuration
3161
+ * @returns this for chaining
3162
+ */
3163
+ use(middleware: Middleware, options?: MiddlewareOptions): this;
3164
+ /**
3165
+ * Remove a middleware by name
3166
+ *
3167
+ * @param name - The name of the middleware to remove
3168
+ * @returns true if removed, false if not found
3169
+ */
3170
+ remove(name: string): boolean;
3171
+ /**
3172
+ * Get all registered middleware names
3173
+ */
3174
+ list(): string[];
3175
+ /**
3176
+ * Check if any middleware is registered
3177
+ */
3178
+ hasMiddleware(): boolean;
3179
+ /**
3180
+ * Execute the middleware chain with retry support
3181
+ *
3182
+ * @param ctx - The middleware context
3183
+ * @param coreHandler - The core request handler to call at the end of the chain
3184
+ * @returns The response from the core handler
3185
+ */
3186
+ execute<T>(ctx: MiddlewareContext<T>, coreHandler: () => Promise<MiddlewareResponse<T>>): Promise<MiddlewareResponse<T>>;
3187
+ /**
3188
+ * Run the middleware chain (onion model)
3189
+ */
3190
+ private runChain;
3191
+ }
3192
+
3193
+ /**
3194
+ * Options for the auth refresh middleware
3195
+ */
3196
+ interface AuthRefreshOptions {
3197
+ /**
3198
+ * Function to refresh the access token
3199
+ * Should return the new access token
3200
+ */
3201
+ refreshToken: () => Promise<string>;
3202
+ /**
3203
+ * Optional callback when refresh succeeds
3204
+ */
3205
+ onRefreshSuccess?: (newToken: string) => void;
3206
+ /**
3207
+ * Optional callback when refresh fails
3208
+ */
3209
+ onRefreshFailed?: (error: Error) => void;
3210
+ /**
3211
+ * Maximum refresh attempts per request (default: 1)
3212
+ */
3213
+ maxRefreshAttempts?: number;
3214
+ }
3215
+ /**
3216
+ * Creates a middleware that automatically refreshes access tokens on 401 errors
3217
+ *
3218
+ * @example
3219
+ * ```typescript
3220
+ * const client = new MantleCoreClient({
3221
+ * accessToken: 'initial-token',
3222
+ * });
3223
+ *
3224
+ * client.use(createAuthRefreshMiddleware({
3225
+ * refreshToken: async () => {
3226
+ * const response = await fetch('/refresh', { method: 'POST' });
3227
+ * const data = await response.json();
3228
+ * return data.accessToken;
3229
+ * },
3230
+ * onRefreshSuccess: (newToken) => {
3231
+ * // Persist the new token
3232
+ * localStorage.setItem('accessToken', newToken);
3233
+ * },
3234
+ * }), { name: 'auth-refresh' });
3235
+ * ```
3236
+ */
3237
+ declare function createAuthRefreshMiddleware(options: AuthRefreshOptions): Middleware;
3238
+
3239
+ 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 AgentListResponse, 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 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 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 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 };
package/dist/index.js CHANGED
@@ -49,6 +49,7 @@ __export(index_exports, {
49
49
  MantleValidationError: () => MantleValidationError,
50
50
  MeResource: () => MeResource,
51
51
  MetricsResource: () => MetricsResource,
52
+ MiddlewareManager: () => MiddlewareManager,
52
53
  OrganizationResource: () => OrganizationResource,
53
54
  SubscriptionsResource: () => SubscriptionsResource,
54
55
  TasksResource: () => TasksResource,
@@ -56,10 +57,114 @@ __export(index_exports, {
56
57
  TransactionsResource: () => TransactionsResource,
57
58
  UsageEventsResource: () => UsageEventsResource,
58
59
  UsersResource: () => UsersResource,
59
- WebhooksResource: () => WebhooksResource
60
+ WebhooksResource: () => WebhooksResource,
61
+ createAuthRefreshMiddleware: () => createAuthRefreshMiddleware
60
62
  });
61
63
  module.exports = __toCommonJS(index_exports);
62
64
 
65
+ // src/middleware/manager.ts
66
+ var MiddlewareManager = class {
67
+ constructor() {
68
+ this.middlewares = [];
69
+ }
70
+ /**
71
+ * Register a middleware function
72
+ *
73
+ * @param middleware - The middleware function to register
74
+ * @param options - Optional configuration
75
+ * @returns this for chaining
76
+ */
77
+ use(middleware, options = {}) {
78
+ const registered = {
79
+ fn: middleware,
80
+ name: options.name ?? `middleware_${Date.now()}_${Math.random().toString(36).slice(2)}`,
81
+ priority: options.priority ?? 100
82
+ };
83
+ this.middlewares.push(registered);
84
+ this.middlewares.sort((a, b) => a.priority - b.priority);
85
+ return this;
86
+ }
87
+ /**
88
+ * Remove a middleware by name
89
+ *
90
+ * @param name - The name of the middleware to remove
91
+ * @returns true if removed, false if not found
92
+ */
93
+ remove(name) {
94
+ const index = this.middlewares.findIndex((m) => m.name === name);
95
+ if (index !== -1) {
96
+ this.middlewares.splice(index, 1);
97
+ return true;
98
+ }
99
+ return false;
100
+ }
101
+ /**
102
+ * Get all registered middleware names
103
+ */
104
+ list() {
105
+ return this.middlewares.map((m) => m.name);
106
+ }
107
+ /**
108
+ * Check if any middleware is registered
109
+ */
110
+ hasMiddleware() {
111
+ return this.middlewares.length > 0;
112
+ }
113
+ /**
114
+ * Execute the middleware chain with retry support
115
+ *
116
+ * @param ctx - The middleware context
117
+ * @param coreHandler - The core request handler to call at the end of the chain
118
+ * @returns The response from the core handler
119
+ */
120
+ async execute(ctx, coreHandler) {
121
+ const maxAttempts = ctx.maxRetries + 1;
122
+ let attempts = 0;
123
+ while (attempts < maxAttempts) {
124
+ ctx.retryCount = attempts;
125
+ ctx.retry = false;
126
+ ctx.error = void 0;
127
+ try {
128
+ await this.runChain(ctx, coreHandler);
129
+ if (!ctx.retry) {
130
+ return ctx.response;
131
+ }
132
+ attempts++;
133
+ } catch (error) {
134
+ if (!ctx.retry || attempts >= maxAttempts - 1) {
135
+ throw error;
136
+ }
137
+ attempts++;
138
+ }
139
+ }
140
+ throw ctx.error ?? new Error("Max retries exceeded");
141
+ }
142
+ /**
143
+ * Run the middleware chain (onion model)
144
+ */
145
+ async runChain(ctx, coreHandler) {
146
+ let index = -1;
147
+ const dispatch = async (i) => {
148
+ if (i <= index) {
149
+ throw new Error("next() called multiple times");
150
+ }
151
+ index = i;
152
+ if (i < this.middlewares.length) {
153
+ const middleware = this.middlewares[i];
154
+ await middleware.fn(ctx, () => dispatch(i + 1));
155
+ } else {
156
+ try {
157
+ ctx.response = await coreHandler();
158
+ } catch (error) {
159
+ ctx.error = error;
160
+ throw error;
161
+ }
162
+ }
163
+ };
164
+ await dispatch(0);
165
+ }
166
+ };
167
+
63
168
  // src/utils/sanitize.ts
64
169
  function sanitizeObject(obj) {
65
170
  if (!obj || typeof obj !== "object") {
@@ -1667,6 +1772,16 @@ var MantleCoreClient = class {
1667
1772
  this.apiKey = config.apiKey;
1668
1773
  this.accessToken = config.accessToken;
1669
1774
  this.timeout = config.timeout || 3e4;
1775
+ this.middlewareManager = new MiddlewareManager();
1776
+ if (config.middleware) {
1777
+ for (const mw of config.middleware) {
1778
+ if (Array.isArray(mw)) {
1779
+ this.middlewareManager.use(mw[0], mw[1]);
1780
+ } else {
1781
+ this.middlewareManager.use(mw);
1782
+ }
1783
+ }
1784
+ }
1670
1785
  this.customers = new CustomersResource(this);
1671
1786
  this.contacts = new ContactsResource(this);
1672
1787
  this.subscriptions = new SubscriptionsResource(this);
@@ -1697,6 +1812,49 @@ var MantleCoreClient = class {
1697
1812
  this.docs = new DocsResource(this);
1698
1813
  this.entities = new EntitiesResource(this);
1699
1814
  }
1815
+ /**
1816
+ * Register a middleware function
1817
+ *
1818
+ * @param middleware - The middleware function to register
1819
+ * @param options - Optional configuration (name, priority)
1820
+ * @returns this for chaining
1821
+ *
1822
+ * @example
1823
+ * ```typescript
1824
+ * client.use(async (ctx, next) => {
1825
+ * console.log('Request:', ctx.request.url);
1826
+ * await next();
1827
+ * console.log('Response:', ctx.response?.status);
1828
+ * });
1829
+ * ```
1830
+ */
1831
+ use(middleware, options) {
1832
+ this.middlewareManager.use(middleware, options);
1833
+ return this;
1834
+ }
1835
+ /**
1836
+ * Remove a middleware by name
1837
+ *
1838
+ * @param name - The name of the middleware to remove
1839
+ * @returns true if removed, false if not found
1840
+ */
1841
+ removeMiddleware(name) {
1842
+ return this.middlewareManager.remove(name);
1843
+ }
1844
+ /**
1845
+ * Update authentication credentials
1846
+ * Useful for middleware that needs to refresh tokens
1847
+ *
1848
+ * @param credentials - New credentials to set
1849
+ */
1850
+ updateAuth(credentials) {
1851
+ if (credentials.apiKey !== void 0) {
1852
+ this.apiKey = credentials.apiKey;
1853
+ }
1854
+ if (credentials.accessToken !== void 0) {
1855
+ this.accessToken = credentials.accessToken;
1856
+ }
1857
+ }
1700
1858
  /**
1701
1859
  * Performs a GET request to the API
1702
1860
  */
@@ -1736,6 +1894,75 @@ var MantleCoreClient = class {
1736
1894
  * Makes an HTTP request to the API
1737
1895
  */
1738
1896
  async makeRequest(endpoint, options) {
1897
+ if (this.middlewareManager.hasMiddleware()) {
1898
+ return this.makeRequestWithMiddleware(endpoint, options);
1899
+ }
1900
+ return this.executeRequest(endpoint, options);
1901
+ }
1902
+ /**
1903
+ * Execute request through middleware chain
1904
+ */
1905
+ async makeRequestWithMiddleware(endpoint, options) {
1906
+ const request = {
1907
+ url: `${this.baseURL}${endpoint}`,
1908
+ method: options.method,
1909
+ headers: {
1910
+ Authorization: this.getAuthHeader(),
1911
+ "Content-Type": "application/json",
1912
+ ...options.headers
1913
+ },
1914
+ body: options.body,
1915
+ endpoint
1916
+ };
1917
+ const ctx = {
1918
+ request,
1919
+ retry: false,
1920
+ retryCount: 0,
1921
+ maxRetries: 3,
1922
+ updateAuth: (credentials) => this.updateAuth(credentials)
1923
+ };
1924
+ const coreHandler = async () => {
1925
+ const controller = new AbortController();
1926
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1927
+ try {
1928
+ const response2 = await fetch(ctx.request.url, {
1929
+ method: ctx.request.method,
1930
+ body: ctx.request.body,
1931
+ headers: ctx.request.headers,
1932
+ signal: controller.signal
1933
+ });
1934
+ clearTimeout(timeoutId);
1935
+ if (!response2.ok) {
1936
+ await this.handleErrorResponse(response2);
1937
+ }
1938
+ const text = await response2.text();
1939
+ const data = text ? JSON.parse(text) : {};
1940
+ return {
1941
+ data,
1942
+ status: response2.status,
1943
+ headers: response2.headers
1944
+ };
1945
+ } catch (error) {
1946
+ clearTimeout(timeoutId);
1947
+ if (error instanceof MantleAPIError) {
1948
+ throw error;
1949
+ }
1950
+ if (error instanceof Error && error.name === "AbortError") {
1951
+ throw new MantleAPIError("Request timeout", 408);
1952
+ }
1953
+ throw new MantleAPIError(
1954
+ error instanceof Error ? error.message : "Unknown error occurred",
1955
+ 500
1956
+ );
1957
+ }
1958
+ };
1959
+ const response = await this.middlewareManager.execute(ctx, coreHandler);
1960
+ return response.data;
1961
+ }
1962
+ /**
1963
+ * Direct request execution (no middleware)
1964
+ */
1965
+ async executeRequest(endpoint, options) {
1739
1966
  const authHeader = this.getAuthHeader();
1740
1967
  const controller = new AbortController();
1741
1968
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
@@ -1821,6 +2048,45 @@ var MantleCoreClient = class {
1821
2048
  }
1822
2049
  }
1823
2050
  };
2051
+
2052
+ // src/middleware/auth-refresh.ts
2053
+ function createAuthRefreshMiddleware(options) {
2054
+ const {
2055
+ refreshToken,
2056
+ onRefreshSuccess,
2057
+ onRefreshFailed,
2058
+ maxRefreshAttempts = 1
2059
+ } = options;
2060
+ let refreshAttempts = 0;
2061
+ return async (ctx, next) => {
2062
+ try {
2063
+ await next();
2064
+ } catch (error) {
2065
+ if (!(error instanceof MantleAuthenticationError)) {
2066
+ throw error;
2067
+ }
2068
+ if (refreshAttempts >= maxRefreshAttempts) {
2069
+ refreshAttempts = 0;
2070
+ throw error;
2071
+ }
2072
+ refreshAttempts++;
2073
+ try {
2074
+ const newToken = await refreshToken();
2075
+ ctx.updateAuth({ accessToken: newToken });
2076
+ ctx.request.headers.Authorization = `Bearer ${newToken}`;
2077
+ onRefreshSuccess?.(newToken);
2078
+ ctx.retry = true;
2079
+ refreshAttempts = 0;
2080
+ } catch (refreshError) {
2081
+ refreshAttempts = 0;
2082
+ onRefreshFailed?.(refreshError);
2083
+ throw new MantleAuthenticationError(
2084
+ "Authentication failed. Please re-authenticate."
2085
+ );
2086
+ }
2087
+ }
2088
+ };
2089
+ }
1824
2090
  // Annotate the CommonJS export names for ESM import in node:
1825
2091
  0 && (module.exports = {
1826
2092
  AffiliateCommissionsResource,
@@ -1852,6 +2118,7 @@ var MantleCoreClient = class {
1852
2118
  MantleValidationError,
1853
2119
  MeResource,
1854
2120
  MetricsResource,
2121
+ MiddlewareManager,
1855
2122
  OrganizationResource,
1856
2123
  SubscriptionsResource,
1857
2124
  TasksResource,
@@ -1859,5 +2126,6 @@ var MantleCoreClient = class {
1859
2126
  TransactionsResource,
1860
2127
  UsageEventsResource,
1861
2128
  UsersResource,
1862
- WebhooksResource
2129
+ WebhooksResource,
2130
+ createAuthRefreshMiddleware
1863
2131
  });
package/dist/index.mjs CHANGED
@@ -1,3 +1,106 @@
1
+ // src/middleware/manager.ts
2
+ var MiddlewareManager = class {
3
+ constructor() {
4
+ this.middlewares = [];
5
+ }
6
+ /**
7
+ * Register a middleware function
8
+ *
9
+ * @param middleware - The middleware function to register
10
+ * @param options - Optional configuration
11
+ * @returns this for chaining
12
+ */
13
+ use(middleware, options = {}) {
14
+ const registered = {
15
+ fn: middleware,
16
+ name: options.name ?? `middleware_${Date.now()}_${Math.random().toString(36).slice(2)}`,
17
+ priority: options.priority ?? 100
18
+ };
19
+ this.middlewares.push(registered);
20
+ this.middlewares.sort((a, b) => a.priority - b.priority);
21
+ return this;
22
+ }
23
+ /**
24
+ * Remove a middleware by name
25
+ *
26
+ * @param name - The name of the middleware to remove
27
+ * @returns true if removed, false if not found
28
+ */
29
+ remove(name) {
30
+ const index = this.middlewares.findIndex((m) => m.name === name);
31
+ if (index !== -1) {
32
+ this.middlewares.splice(index, 1);
33
+ return true;
34
+ }
35
+ return false;
36
+ }
37
+ /**
38
+ * Get all registered middleware names
39
+ */
40
+ list() {
41
+ return this.middlewares.map((m) => m.name);
42
+ }
43
+ /**
44
+ * Check if any middleware is registered
45
+ */
46
+ hasMiddleware() {
47
+ return this.middlewares.length > 0;
48
+ }
49
+ /**
50
+ * Execute the middleware chain with retry support
51
+ *
52
+ * @param ctx - The middleware context
53
+ * @param coreHandler - The core request handler to call at the end of the chain
54
+ * @returns The response from the core handler
55
+ */
56
+ async execute(ctx, coreHandler) {
57
+ const maxAttempts = ctx.maxRetries + 1;
58
+ let attempts = 0;
59
+ while (attempts < maxAttempts) {
60
+ ctx.retryCount = attempts;
61
+ ctx.retry = false;
62
+ ctx.error = void 0;
63
+ try {
64
+ await this.runChain(ctx, coreHandler);
65
+ if (!ctx.retry) {
66
+ return ctx.response;
67
+ }
68
+ attempts++;
69
+ } catch (error) {
70
+ if (!ctx.retry || attempts >= maxAttempts - 1) {
71
+ throw error;
72
+ }
73
+ attempts++;
74
+ }
75
+ }
76
+ throw ctx.error ?? new Error("Max retries exceeded");
77
+ }
78
+ /**
79
+ * Run the middleware chain (onion model)
80
+ */
81
+ async runChain(ctx, coreHandler) {
82
+ let index = -1;
83
+ const dispatch = async (i) => {
84
+ if (i <= index) {
85
+ throw new Error("next() called multiple times");
86
+ }
87
+ index = i;
88
+ if (i < this.middlewares.length) {
89
+ const middleware = this.middlewares[i];
90
+ await middleware.fn(ctx, () => dispatch(i + 1));
91
+ } else {
92
+ try {
93
+ ctx.response = await coreHandler();
94
+ } catch (error) {
95
+ ctx.error = error;
96
+ throw error;
97
+ }
98
+ }
99
+ };
100
+ await dispatch(0);
101
+ }
102
+ };
103
+
1
104
  // src/utils/sanitize.ts
2
105
  function sanitizeObject(obj) {
3
106
  if (!obj || typeof obj !== "object") {
@@ -1605,6 +1708,16 @@ var MantleCoreClient = class {
1605
1708
  this.apiKey = config.apiKey;
1606
1709
  this.accessToken = config.accessToken;
1607
1710
  this.timeout = config.timeout || 3e4;
1711
+ this.middlewareManager = new MiddlewareManager();
1712
+ if (config.middleware) {
1713
+ for (const mw of config.middleware) {
1714
+ if (Array.isArray(mw)) {
1715
+ this.middlewareManager.use(mw[0], mw[1]);
1716
+ } else {
1717
+ this.middlewareManager.use(mw);
1718
+ }
1719
+ }
1720
+ }
1608
1721
  this.customers = new CustomersResource(this);
1609
1722
  this.contacts = new ContactsResource(this);
1610
1723
  this.subscriptions = new SubscriptionsResource(this);
@@ -1635,6 +1748,49 @@ var MantleCoreClient = class {
1635
1748
  this.docs = new DocsResource(this);
1636
1749
  this.entities = new EntitiesResource(this);
1637
1750
  }
1751
+ /**
1752
+ * Register a middleware function
1753
+ *
1754
+ * @param middleware - The middleware function to register
1755
+ * @param options - Optional configuration (name, priority)
1756
+ * @returns this for chaining
1757
+ *
1758
+ * @example
1759
+ * ```typescript
1760
+ * client.use(async (ctx, next) => {
1761
+ * console.log('Request:', ctx.request.url);
1762
+ * await next();
1763
+ * console.log('Response:', ctx.response?.status);
1764
+ * });
1765
+ * ```
1766
+ */
1767
+ use(middleware, options) {
1768
+ this.middlewareManager.use(middleware, options);
1769
+ return this;
1770
+ }
1771
+ /**
1772
+ * Remove a middleware by name
1773
+ *
1774
+ * @param name - The name of the middleware to remove
1775
+ * @returns true if removed, false if not found
1776
+ */
1777
+ removeMiddleware(name) {
1778
+ return this.middlewareManager.remove(name);
1779
+ }
1780
+ /**
1781
+ * Update authentication credentials
1782
+ * Useful for middleware that needs to refresh tokens
1783
+ *
1784
+ * @param credentials - New credentials to set
1785
+ */
1786
+ updateAuth(credentials) {
1787
+ if (credentials.apiKey !== void 0) {
1788
+ this.apiKey = credentials.apiKey;
1789
+ }
1790
+ if (credentials.accessToken !== void 0) {
1791
+ this.accessToken = credentials.accessToken;
1792
+ }
1793
+ }
1638
1794
  /**
1639
1795
  * Performs a GET request to the API
1640
1796
  */
@@ -1674,6 +1830,75 @@ var MantleCoreClient = class {
1674
1830
  * Makes an HTTP request to the API
1675
1831
  */
1676
1832
  async makeRequest(endpoint, options) {
1833
+ if (this.middlewareManager.hasMiddleware()) {
1834
+ return this.makeRequestWithMiddleware(endpoint, options);
1835
+ }
1836
+ return this.executeRequest(endpoint, options);
1837
+ }
1838
+ /**
1839
+ * Execute request through middleware chain
1840
+ */
1841
+ async makeRequestWithMiddleware(endpoint, options) {
1842
+ const request = {
1843
+ url: `${this.baseURL}${endpoint}`,
1844
+ method: options.method,
1845
+ headers: {
1846
+ Authorization: this.getAuthHeader(),
1847
+ "Content-Type": "application/json",
1848
+ ...options.headers
1849
+ },
1850
+ body: options.body,
1851
+ endpoint
1852
+ };
1853
+ const ctx = {
1854
+ request,
1855
+ retry: false,
1856
+ retryCount: 0,
1857
+ maxRetries: 3,
1858
+ updateAuth: (credentials) => this.updateAuth(credentials)
1859
+ };
1860
+ const coreHandler = async () => {
1861
+ const controller = new AbortController();
1862
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1863
+ try {
1864
+ const response2 = await fetch(ctx.request.url, {
1865
+ method: ctx.request.method,
1866
+ body: ctx.request.body,
1867
+ headers: ctx.request.headers,
1868
+ signal: controller.signal
1869
+ });
1870
+ clearTimeout(timeoutId);
1871
+ if (!response2.ok) {
1872
+ await this.handleErrorResponse(response2);
1873
+ }
1874
+ const text = await response2.text();
1875
+ const data = text ? JSON.parse(text) : {};
1876
+ return {
1877
+ data,
1878
+ status: response2.status,
1879
+ headers: response2.headers
1880
+ };
1881
+ } catch (error) {
1882
+ clearTimeout(timeoutId);
1883
+ if (error instanceof MantleAPIError) {
1884
+ throw error;
1885
+ }
1886
+ if (error instanceof Error && error.name === "AbortError") {
1887
+ throw new MantleAPIError("Request timeout", 408);
1888
+ }
1889
+ throw new MantleAPIError(
1890
+ error instanceof Error ? error.message : "Unknown error occurred",
1891
+ 500
1892
+ );
1893
+ }
1894
+ };
1895
+ const response = await this.middlewareManager.execute(ctx, coreHandler);
1896
+ return response.data;
1897
+ }
1898
+ /**
1899
+ * Direct request execution (no middleware)
1900
+ */
1901
+ async executeRequest(endpoint, options) {
1677
1902
  const authHeader = this.getAuthHeader();
1678
1903
  const controller = new AbortController();
1679
1904
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
@@ -1759,6 +1984,45 @@ var MantleCoreClient = class {
1759
1984
  }
1760
1985
  }
1761
1986
  };
1987
+
1988
+ // src/middleware/auth-refresh.ts
1989
+ function createAuthRefreshMiddleware(options) {
1990
+ const {
1991
+ refreshToken,
1992
+ onRefreshSuccess,
1993
+ onRefreshFailed,
1994
+ maxRefreshAttempts = 1
1995
+ } = options;
1996
+ let refreshAttempts = 0;
1997
+ return async (ctx, next) => {
1998
+ try {
1999
+ await next();
2000
+ } catch (error) {
2001
+ if (!(error instanceof MantleAuthenticationError)) {
2002
+ throw error;
2003
+ }
2004
+ if (refreshAttempts >= maxRefreshAttempts) {
2005
+ refreshAttempts = 0;
2006
+ throw error;
2007
+ }
2008
+ refreshAttempts++;
2009
+ try {
2010
+ const newToken = await refreshToken();
2011
+ ctx.updateAuth({ accessToken: newToken });
2012
+ ctx.request.headers.Authorization = `Bearer ${newToken}`;
2013
+ onRefreshSuccess?.(newToken);
2014
+ ctx.retry = true;
2015
+ refreshAttempts = 0;
2016
+ } catch (refreshError) {
2017
+ refreshAttempts = 0;
2018
+ onRefreshFailed?.(refreshError);
2019
+ throw new MantleAuthenticationError(
2020
+ "Authentication failed. Please re-authenticate."
2021
+ );
2022
+ }
2023
+ }
2024
+ };
2025
+ }
1762
2026
  export {
1763
2027
  AffiliateCommissionsResource,
1764
2028
  AffiliatePayoutsResource,
@@ -1789,6 +2053,7 @@ export {
1789
2053
  MantleValidationError,
1790
2054
  MeResource,
1791
2055
  MetricsResource,
2056
+ MiddlewareManager,
1792
2057
  OrganizationResource,
1793
2058
  SubscriptionsResource,
1794
2059
  TasksResource,
@@ -1796,5 +2061,6 @@ export {
1796
2061
  TransactionsResource,
1797
2062
  UsageEventsResource,
1798
2063
  UsersResource,
1799
- WebhooksResource
2064
+ WebhooksResource,
2065
+ createAuthRefreshMiddleware
1800
2066
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heymantle/core-api-client",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "TypeScript SDK for the Mantle Core API",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",