@cshah18/sdk 4.7.0 → 4.9.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.
@@ -18,10 +18,10 @@ export interface AnalyticsEvent {
18
18
  * Uses session ID provided by the SDK for all analytics events
19
19
  */
20
20
  export declare class AnalyticsClient {
21
- private logger;
22
- private apiClient;
23
- private sdkVersion;
24
- private sessionId;
21
+ private readonly logger;
22
+ private readonly apiClient;
23
+ private readonly sdkVersion;
24
+ private readonly sessionId;
25
25
  constructor(_merchantKey: string, sdkVersion: string, sessionId: string, apiClient: ApiClient | null, debug?: boolean);
26
26
  /**
27
27
  * Track a CTA click event
@@ -29,6 +29,10 @@ export declare class AnalyticsClient {
29
29
  trackCtaClick(productId: string): Promise<void>;
30
30
  /**
31
31
  * Send event to backend analytics endpoint using unified ApiClient
32
+ *
33
+ * @throws {CoBuyApiError} If API request fails
34
+ * @private
35
+ * @internal
32
36
  */
33
37
  private sendEvent;
34
38
  /**
@@ -11,10 +11,30 @@ export declare class ApiClient {
11
11
  private baseUrl;
12
12
  private authStrategy;
13
13
  private sessionId;
14
- private logger;
15
- private defaultTimeout;
14
+ private readonly logger;
15
+ private readonly defaultTimeout;
16
+ private readonly maxRetries;
17
+ private botdScore;
16
18
  private traceId;
19
+ private readonly rewardCache;
20
+ private readonly REWARD_CACHE_TTL;
21
+ private readonly pendingRequests;
17
22
  constructor(config: ApiClientConfig);
23
+ /**
24
+ * Update the BotD (Bot Detection) score for fraud detection
25
+ *
26
+ * @param {number | undefined} score - The BotD score (0-100) or undefined to clear
27
+ * @returns {void}
28
+ *
29
+ * @description
30
+ * Sets the fraud detection score that will be included in API request headers.
31
+ * Used to improve fraud detection accuracy. Cleared if undefined is passed.
32
+ *
33
+ * @example
34
+ * CoBuy.getApiClient()?.setBotdScore(45); // Set BotD score
35
+ * CoBuy.getApiClient()?.setBotdScore(undefined); // Clear score
36
+ */
37
+ setBotdScore(score: number | undefined): void;
18
38
  /**
19
39
  * Generate a unique trace ID for request correlation
20
40
  */
@@ -24,7 +44,46 @@ export declare class ApiClient {
24
44
  */
25
45
  private isRetryableError;
26
46
  /**
27
- * Make an HTTP request to the API with retry logic
47
+ * Make an authenticated HTTP request with automatic retry logic
48
+ *
49
+ * Low-level method for making requests to the API. Handles authentication headers,
50
+ * timeout management, error handling, and automatic retries for transient failures.
51
+ *
52
+ * @template T - The type of data returned on success
53
+ * @param {string} endpoint - The API endpoint path (e.g., '/products/12345/reward')
54
+ * @param {ApiRequestOptions} [options={}] - Request configuration options
55
+ * @param {"GET" | "POST" | "PUT" | "DELETE"} [options.method="GET"] - HTTP method
56
+ * @param {unknown} [options.body] - Request body (automatically JSON stringified)
57
+ * @param {Record<string, string>} [options.headers] - Additional headers to include
58
+ * @param {number} [options.timeout] - Request timeout in milliseconds
59
+ *
60
+ * @returns {Promise<ApiResponse<T>>} Response with success flag and data or error
61
+ *
62
+ * @description
63
+ * Request Features:
64
+ * - Automatic authentication header injection from auth strategy
65
+ * - Session tracking via X-CoBuy-Session header
66
+ * - Request correlation via trace ID (X-CoBuy-Trace header)
67
+ * - Configurable timeout (default 30 seconds)
68
+ * - Automatic retry on transient errors (timeout, 502, 503, 504)
69
+ * - Exponential backoff: 100ms, 200ms, 400ms
70
+ * - Auth token refresh on 401/403 responses
71
+ * - Full response body logging in debug mode
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * const client = CoBuy.getApiClient();
76
+ * const response = await client.request('/products/abc123/groups', {
77
+ * method: 'GET',
78
+ * timeout: 15000
79
+ * });
80
+ *
81
+ * if (response.success) {
82
+ * console.log('Groups:', response.data);
83
+ * } else {
84
+ * console.error('Error:', response.error?.message);
85
+ * }
86
+ * ```
28
87
  */
29
88
  request<T = unknown>(endpoint: string, options?: ApiRequestOptions): Promise<ApiResponse<T>>;
30
89
  /**
@@ -52,44 +111,157 @@ export declare class ApiClient {
52
111
  */
53
112
  delete<T = unknown>(endpoint: string, options?: Omit<ApiRequestOptions, "method" | "body">): Promise<ApiResponse<T>>;
54
113
  /**
55
- * Update the base URL
114
+ * Update the API base URL
115
+ *
116
+ * @param {string} baseUrl - The new base URL for API requests
117
+ * @returns {void}
118
+ *
119
+ * @example
120
+ * CoBuy.getApiClient()?.setBaseUrl('https://api-staging.cobuy.com');
56
121
  */
57
122
  setBaseUrl(baseUrl: string): void;
58
123
  /**
59
- * Update the auth strategy
124
+ * Update the authentication strategy
125
+ *
126
+ * @param {AuthStrategy} authStrategy - The new auth strategy to use
127
+ * @returns {void}
128
+ *
129
+ * @description
130
+ * Allows switching between public key and token-based authentication at runtime.
131
+ *
132
+ * @example
133
+ * const newAuth = new TokenAuth("new_token");
134
+ * CoBuy.getApiClient()?.setAuthStrategy(newAuth);
60
135
  */
61
136
  setAuthStrategy(authStrategy: AuthStrategy): void;
62
137
  /**
63
138
  * Get the current session ID
139
+ *
140
+ * @returns {string} The current session ID used for API requests
141
+ *
142
+ * @example
143
+ * const sessionId = CoBuy.getApiClient()?.getSessionId();
144
+ * console.log('Current session:', sessionId);
64
145
  */
65
146
  getSessionId(): string;
66
147
  /**
67
148
  * Update the session ID
149
+ *
150
+ * @param {string} sessionId - The new session ID for API requests
151
+ * @returns {void}
152
+ *
153
+ * @example
154
+ * CoBuy.getApiClient()?.setSessionId('new-session-uuid');
68
155
  */
69
156
  setSessionId(sessionId: string): void;
70
157
  /**
71
- * Get the current trace ID
158
+ * Get the most recent request trace ID
159
+ *
160
+ * Useful for debugging and correlating client requests with server logs.
161
+ *
162
+ * @returns {string | null} The trace ID from the last request, or null if no requests made
163
+ *
164
+ * @example
165
+ * const traceId = CoBuy.getApiClient()?.getTraceId();
166
+ * if (traceId) {
167
+ * console.log('Last request trace:', traceId); // Use for support tickets
168
+ * }
72
169
  */
73
170
  getTraceId(): string | null;
74
171
  /**
75
172
  * Get product reward information
76
173
  *
77
- * Retrieves reward data and eligibility for a specific product.
78
- * This is a core method for SCRUM-247: Retrieve reward information.
174
+ * Retrieves discount and reward eligibility for a specific product.
175
+ * Results are cached for 1 minute to reduce API load.
176
+ *
177
+ * @param {string} productId - The product ID to fetch reward information for
178
+ * @returns {Promise<ApiResponse<ProductRewardData>>} Product reward and eligibility data
79
179
  *
80
- * @param productId - The product ID to fetch reward information for
81
- * @returns Promise with reward data including eligibility status
180
+ * @description
181
+ * Features:
182
+ * - Caches results for 60 seconds to reduce API calls
183
+ * - Deduplicates concurrent requests for the same product
184
+ * - Includes reward amount, eligibility status, and discount percentage
185
+ *
186
+ * @throws Does not throw; returns ApiResponse with error details on failure
187
+ *
188
+ * @example
189
+ * ```typescript
190
+ * const response = await client.getProductReward('prod_abc123');
191
+ * if (response.success) {
192
+ * console.log('Discount:', response.data?.discount_percentage);
193
+ * console.log('Eligible:', response.data?.eligible);
194
+ * }
195
+ * ```
82
196
  */
83
197
  getProductReward(productId: string): Promise<ApiResponse<ProductRewardData>>;
84
198
  /**
85
- * Get primary group information for a product (participants, max, expiry)
199
+ * Clear all cached product rewards
200
+ *
201
+ * Primarily used for testing or forcing fresh data from the server.
202
+ *
203
+ * @returns {void}
204
+ *
205
+ * @example
206
+ * CoBuy.getApiClient()?.clearRewardCache();
207
+ * // Next getProductReward call will fetch fresh data
208
+ */
209
+ clearRewardCache(): void;
210
+ private fetchProductReward;
211
+ /**
212
+ * Get primary group information for a product
213
+ *
214
+ * Retrieves the primary group data including member count, capacity, and expiry time.
215
+ * Optionally creates a new group if none exists.
216
+ *
217
+ * @param {string} productId - The product ID to fetch primary group for
218
+ * @returns {Promise<ApiResponse<ProductPrimaryGroupData>>} Primary group data or error
219
+ *
220
+ * @description
221
+ * Returns group information including:
222
+ * - Current participant count
223
+ * - Maximum participants allowed
224
+ * - Group status (pending, active, fulfilled, expired)
225
+ * - Time remaining for group to close
226
+ * - Group ID for joining operations
227
+ *
228
+ * @example
229
+ * ```typescript
230
+ * const response = await client.getProductPrimaryGroup('prod_abc123');
231
+ * if (response.success) {
232
+ * const group = response.data;
233
+ * console.log(`${group.participants_count}/${group.max_participants} members`);
234
+ * }
235
+ * ```
86
236
  */
87
237
  getProductPrimaryGroup(productId: string): Promise<ApiResponse<ProductPrimaryGroupData>>;
88
238
  /**
89
- * Get active groups for a product
239
+ * Get all active groups for a product
240
+ *
241
+ * Retrieves a list of currently active groups for a product, including
242
+ * member count, capacity, and whether the current user is a member.
90
243
  *
91
- * @param productId - The product ID to fetch active groups for
92
- * @returns Promise with active groups list
244
+ * @param {string} productId - The product ID to fetch active groups for
245
+ * @returns {Promise<ApiResponse<{groups: Array}>>} List of active groups with member info
246
+ *
247
+ * @description
248
+ * Each group includes:
249
+ * - Group ID and number
250
+ * - Current and max participant counts
251
+ * - Status (pending, active, fulfilled, expired)
252
+ * - Time remaining before group closes
253
+ * - Whether current user is a member
254
+ * - Discount and reward information
255
+ *
256
+ * @example
257
+ * ```typescript
258
+ * const response = await client.getProductActiveGroups('prod_abc123');
259
+ * if (response.success) {
260
+ * response.data?.groups.forEach(group => {
261
+ * console.log(`Group ${group.group_number}: ${group.participants_count}/${group.max_participants}`);
262
+ * });
263
+ * }
264
+ * ```
93
265
  */
94
266
  getProductActiveGroups(productId: string): Promise<ApiResponse<{
95
267
  groups: Array<ProductPrimaryGroupData & {
@@ -98,41 +270,163 @@ export declare class ApiClient {
98
270
  }>>;
99
271
  /**
100
272
  * Create a new group for a product and join it
273
+ *
274
+ * Creates a brand new group for a product and immediately adds the current
275
+ * user as the first member. Useful when no existing groups meet the user's needs.
276
+ *
277
+ * @param {string} productId - The product ID to create a group for
278
+ * @returns {Promise<ApiResponse<GroupJoinResponseData>>} New group info and join status
279
+ *
280
+ * @description
281
+ * Returns:
282
+ * - New group ID and number
283
+ * - User's membership confirmation
284
+ * - Group details (capacity, status, etc.)
285
+ * - Discount values
286
+ *
287
+ * @example
288
+ * ```typescript
289
+ * const response = await client.createAndJoinGroup('prod_abc123');
290
+ * if (response.success) {
291
+ * const groupId = response.data?.group?.id;
292
+ * console.log('Created new group:', groupId);
293
+ * }
294
+ * ```
101
295
  */
102
296
  createAndJoinGroup(productId: string): Promise<ApiResponse<GroupJoinResponseData>>;
103
297
  /**
104
- * Join a group
298
+ * Join an existing group
299
+ *
300
+ * Adds the current user to an existing group, optionally providing contact
301
+ * information (email or phone) to enrich the session.
302
+ *
303
+ * @param {string} groupId - The group ID to join
304
+ * @param {Contact} [contact] - Optional contact information (email or phone)
305
+ * @param {"email" | "phone"} [contact.type] - Type of contact
306
+ * @param {string} [contact.value] - Email address or phone number
307
+ * @returns {Promise<ApiResponse<GroupJoinResponseData>>} Updated group info and join status
105
308
  *
106
- * @param groupId - The group ID to join
107
- * @param contact - Optional contact information to enrich the session
108
- * @returns Promise with join result
309
+ * @description
310
+ * Actions:
311
+ * - Adds user to group members
312
+ * - Records contact information if provided
313
+ * - Updates group status if member count reaches maximum
314
+ * - Returns updated group details and member count
315
+ *
316
+ * @example
317
+ * ```typescript
318
+ * // Join without contact
319
+ * const response = await client.joinGroup('grp_xyz789');
320
+ *
321
+ * // Join with email
322
+ * const response = await client.joinGroup('grp_xyz789', {
323
+ * type: 'email',
324
+ * value: 'user@example.com'
325
+ * });
326
+ *
327
+ * // Join with phone
328
+ * const response = await client.joinGroup('grp_xyz789', {
329
+ * type: 'phone',
330
+ * value: '+1234567890'
331
+ * });
332
+ * ```
109
333
  */
110
334
  joinGroup(groupId: string, contact?: Contact): Promise<ApiResponse<GroupJoinResponseData>>;
111
335
  /**
112
- * Send an invite/share event for a group
336
+ * Record a group share/invite event
337
+ *
338
+ * Tracks when a user shares or invites others to join a group via
339
+ * a specific channel (email, SMS, social, etc.). Helps analyze referral effectiveness.
340
+ *
341
+ * @param {string} groupId - The group ID being shared
342
+ * @param {ShareChannel} sharedVia - Channel used for sharing ("email", "sms", "whatsapp", "facebook", "twitter", "linkedin", "copy_link", "qr", "other")
343
+ * @returns {Promise<ApiResponse<GroupInviteResponseData>>} Invite tracking result
344
+ *
345
+ * @description
346
+ * Supported channels:
347
+ * - email: Email invitation
348
+ * - sms: SMS/text message
349
+ * - whatsapp: WhatsApp share
350
+ * - facebook: Facebook share
351
+ * - twitter: Twitter/X share
352
+ * - linkedin: LinkedIn share
353
+ * - copy_link: Direct link copy
354
+ * - qr: QR code scan
355
+ * - other: Other sharing method
356
+ *
357
+ * @example
358
+ * ```typescript
359
+ * // Track email share
360
+ * await client.inviteToGroup('grp_xyz789', 'email');
361
+ *
362
+ * // Track WhatsApp share
363
+ * await client.inviteToGroup('grp_xyz789', 'whatsapp');
364
+ *
365
+ * // Track copied link
366
+ * await client.inviteToGroup('grp_xyz789', 'copy_link');
367
+ * ```
113
368
  */
114
369
  inviteToGroup(groupId: string, sharedVia: ShareChannel): Promise<ApiResponse<GroupInviteResponseData>>;
115
370
  /**
116
371
  * Set or update contact information for the current session
117
372
  *
118
- * Sends contact information (email or phone) to link with the current session.
119
- * This allows merchants to identify a previously anonymous user.
120
- * Backend will not overwrite existing stored contact.
121
- * Safe to call multiple times (idempotent).
373
+ * Associates email or phone with the current session, allowing merchants
374
+ * to identify a previously anonymous user without requiring form submission.
375
+ *
376
+ * @param {Contact} contact - Contact information
377
+ * @param {"email" | "phone"} contact.type - Type of contact
378
+ * @param {string} contact.value - Email address or phone number
379
+ * @returns {Promise<ApiResponse<void>>} Success confirmation
380
+ *
381
+ * @description
382
+ * Features:
383
+ * - Idempotent: safe to call multiple times
384
+ * - Backend won't overwrite existing contact (if any)
385
+ * - Enables identifying returning customers
386
+ * - Enriches session data for analytics
387
+ *
388
+ * @example
389
+ * ```typescript
390
+ * // Set email
391
+ * await client.setContact({
392
+ * type: 'email',
393
+ * value: 'customer@example.com'
394
+ * });
122
395
  *
123
- * @param contact - Contact information with type and value
124
- * @returns Promise with success status
396
+ * // Set phone
397
+ * await client.setContact({
398
+ * type: 'phone',
399
+ * value: '+1-555-123-4567'
400
+ * });
401
+ * ```
125
402
  */
126
403
  setContact(contact: Contact): Promise<ApiResponse<void>>;
127
404
  /**
128
405
  * Prepare checkout for a group
129
406
  *
130
407
  * Signals the backend that the user is proceeding to checkout for a specific group.
131
- * This allows the backend to prepare order data, lock pricing, and track conversion.
132
- * Returns a checkout reference to be used in subsequent validate and confirm calls.
408
+ * Reserves order capacity, locks pricing, prepares order data, and enables conversion tracking.
409
+ * Must be completed before validateCheckout and confirmCheckout.
133
410
  *
134
- * @param groupId - The group ID to prepare checkout for
135
- * @returns Promise with success status and checkout reference
411
+ * @param {string} groupId - The group ID to prepare checkout for
412
+ * @returns {Promise<ApiResponse<{checkout_ref: string}>>} Checkout reference for use in subsequent calls
413
+ *
414
+ * @description
415
+ * Actions performed:
416
+ * - Validates group status and user membership
417
+ * - Reserves a seat in the group
418
+ * - Locks product reward/pricing
419
+ * - Generates a unique checkout reference
420
+ * - Enables server-side conversion tracking
421
+ *
422
+ * @example
423
+ * ```typescript
424
+ * const response = await client.prepareCheckout('grp_xyz789');
425
+ * if (response.success) {
426
+ * const checkoutRef = response.data?.checkout_ref;
427
+ * // Store this reference for validateCheckout and confirmCheckout
428
+ * }
429
+ * ```
136
430
  */
137
431
  prepareCheckout(groupId: string): Promise<ApiResponse<{
138
432
  checkout_ref: string;
@@ -141,22 +435,82 @@ export declare class ApiClient {
141
435
  * Validate checkout for a group
142
436
  *
143
437
  * Validates the checkout reference and confirms the order can proceed.
144
- * This should be called after prepareCheckout to verify the checkout state.
438
+ * Verifies group status, user membership, and pricing consistency.
439
+ * Should be called after prepareCheckout and before confirmCheckout.
440
+ *
441
+ * @param {string} groupId - The group ID being checked out
442
+ * @param {string} checkoutRef - The checkout reference from prepareCheckout
443
+ * @returns {Promise<ApiResponse<CheckoutValidationData>>} Validation result with order details
444
+ *
445
+ * @description
446
+ * Validations performed:
447
+ * - Checkout reference is valid and not expired
448
+ * - User is still a valid group member
449
+ * - Group hasn't changed status since prepare
450
+ * - Pricing/reward data is consistent
451
+ * - Order can safely proceed
145
452
  *
146
- * @param groupId - The group ID to validate checkout for
147
- * @param checkoutRef - The checkout reference ID from the prepare step
148
- * @returns Promise with success status
453
+ * @example
454
+ * ```typescript
455
+ * const validateResp = await client.validateCheckout('grp_xyz789', 'chk_abc123');
456
+ * if (validateResp.success) {
457
+ * const order = validateResp.data;
458
+ * console.log('Order total:', order.total);
459
+ * console.log('Discount:', order.discount);
460
+ * // Proceed to payment if validation passed
461
+ * }
462
+ * ```
149
463
  */
150
464
  validateCheckout(groupId: string, checkoutRef: string): Promise<ApiResponse<CheckoutValidationData>>;
151
465
  /**
152
466
  * Confirm checkout for a group
153
467
  *
154
- * Finalizes the checkout and confirms the order.
155
- * This should be called after validateCheckout to complete the checkout process.
468
+ * Finalizes and confirms the order after validation.
469
+ * Marks the order as complete, applies discounts, records the transaction,
470
+ * and triggers post-purchase workflows.
471
+ * Should be called after validateCheckout to complete the checkout flow.
472
+ *
473
+ * @param {string} groupId - The group ID being checked out
474
+ * @param {string} checkoutRef - The checkout reference from prepareCheckout
475
+ * @param {CheckoutConfirmData} [data] - Optional order details
476
+ * @param {string} [data.order_id] - Merchant's order ID for this purchase
477
+ * @param {number} [data.order_total] - Order total amount
478
+ * @param {number} [data.discount_applied] - Discount amount applied
479
+ * @param {string} [data.currency] - Currency code (e.g., "USD")
480
+ * @param {string} [data.payment_method] - Payment method used (e.g., "card", "paypal")
481
+ * @param {boolean} [data.micrositeCheckout] - Whether this was via microsite checkout
482
+ * @param {Record<string, unknown>} [data.metadata] - Custom metadata to attach to order
483
+ * @returns {Promise<ApiResponse<void>>} Confirmation result
484
+ *
485
+ * @description
486
+ * Actions performed after confirmation:
487
+ * - Order is recorded in the system
488
+ * - Discount is applied to the order
489
+ * - Group fulfillment may be triggered if complete
490
+ * - Merchant order system is updated
491
+ * - Customer receives confirmation
492
+ * - Post-purchase emails/notifications sent
493
+ * - Analytics events recorded
494
+ *
495
+ * @example
496
+ * ```typescript
497
+ * // Confirm with basic reference
498
+ * await client.confirmCheckout('grp_xyz789', 'chk_abc123');
156
499
  *
157
- * @param groupId - The group ID to confirm checkout for
158
- * @param checkoutRef - The checkout reference ID from the prepare step
159
- * @returns Promise with success status
500
+ * // Confirm with order details
501
+ * await client.confirmCheckout('grp_xyz789', 'chk_abc123', {
502
+ * order_id: 'ORDER-9001',
503
+ * order_total: 99.99,
504
+ * discount_applied: 20.00,
505
+ * currency: 'USD',
506
+ * payment_method: 'card',
507
+ * metadata: {
508
+ * coupon_code: 'WELCOME20',
509
+ * channel: 'widget',
510
+ * loyalty_member: true
511
+ * }
512
+ * });
513
+ * ```
160
514
  */
161
515
  confirmCheckout(groupId: string, checkoutRef: string, data?: CheckoutConfirmData): Promise<ApiResponse<void>>;
162
516
  }
@@ -25,9 +25,9 @@ export interface AuthStrategy {
25
25
  * Used for no-backend integrations with read-only endpoints
26
26
  */
27
27
  export declare class PublicKeyAuth implements AuthStrategy {
28
- private merchantKey;
29
- private logger;
30
- private onError?;
28
+ private readonly merchantKey;
29
+ private readonly logger;
30
+ private readonly onError?;
31
31
  constructor(merchantKey: string, debug?: boolean, onError?: (error: Error) => void);
32
32
  getHeaders(): Record<string, string>;
33
33
  refreshIfNeeded(): Promise<boolean>;
@@ -38,11 +38,11 @@ export declare class PublicKeyAuth implements AuthStrategy {
38
38
  * Used for backend-integrated sites with full access to protected endpoints
39
39
  */
40
40
  export declare class TokenAuth implements AuthStrategy {
41
- private tokenGetter;
41
+ private readonly tokenGetter;
42
42
  private currentToken;
43
- private logger;
44
- private onError?;
45
- private onTokenExpired?;
43
+ private readonly logger;
44
+ private readonly onError?;
45
+ private readonly onTokenExpired?;
46
46
  private tokenRefreshPromise;
47
47
  constructor(tokenGetter: string | (() => string | Promise<string>), debug?: boolean, onError?: (error: Error) => void, onTokenExpired?: () => void | Promise<void>);
48
48
  getHeaders(): Record<string, string>;