@cshah18/sdk 4.12.0 → 4.14.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.
@@ -1,4 +1,5 @@
1
1
  import { ApiClient } from "./api-client";
2
+ import { GeoData, DeviceData } from "./types";
2
3
  /**
3
4
  * Analytics event interface matching backend expectations
4
5
  */
@@ -11,6 +12,12 @@ export interface AnalyticsEvent {
11
12
  pageUrl?: string;
12
13
  userAgent?: string;
13
14
  sdkVersion?: string;
15
+ groupId?: string;
16
+ channel?: string;
17
+ totalMembers?: number;
18
+ errorCode?: string;
19
+ errorMessage?: string;
20
+ [key: string]: unknown;
14
21
  };
15
22
  }
16
23
  /**
@@ -35,10 +42,58 @@ export declare class AnalyticsClient {
35
42
  * @internal
36
43
  */
37
44
  private sendEvent;
45
+ /**
46
+ * Track session init event fired when the SDK initializes
47
+ */
48
+ trackSessionInit(geo?: GeoData, device?: DeviceData): Promise<void>;
38
49
  /**
39
50
  * Track page view event
40
51
  */
41
52
  trackPageView(): Promise<void>;
53
+ /**
54
+ * Track creative view event (widget rendered and visible)
55
+ */
56
+ trackCreativeView(productId: string): Promise<void>;
57
+ /**
58
+ * Track popup/lobby modal open event
59
+ */
60
+ trackPopupOpen(productId: string, groupId?: string): Promise<void>;
61
+ /**
62
+ * Track join attempt event (before API call)
63
+ */
64
+ trackJoinAttempt(productId: string, groupId: string): Promise<void>;
65
+ /**
66
+ * Track successful group join event
67
+ */
68
+ trackJoinSuccess(productId: string, groupId: string): Promise<void>;
69
+ /**
70
+ * Track join failure event
71
+ */
72
+ trackJoinFailure(productId: string, groupId?: string, errorCode?: string, message?: string): Promise<void>;
73
+ /**
74
+ * Track already joined event (user attempts to join a group they're already in)
75
+ */
76
+ trackAlreadyJoined(productId: string, groupId?: string): Promise<void>;
77
+ /**
78
+ * Track group full view event (user sees a fulfilled/full group)
79
+ */
80
+ trackGroupFullView(productId: string, groupId?: string, totalMembers?: number): Promise<void>;
81
+ /**
82
+ * Track share click event
83
+ */
84
+ trackShareClick(productId: string, groupId?: string, channel?: string): Promise<void>;
85
+ /**
86
+ * Track group creation attempt event
87
+ */
88
+ trackGroupCreateAttempt(productId: string): Promise<void>;
89
+ /**
90
+ * Track successful group creation event
91
+ */
92
+ trackGroupCreateSuccess(productId: string, groupId: string): Promise<void>;
93
+ /**
94
+ * Track group creation failure event
95
+ */
96
+ trackGroupCreateFailure(productId: string, errorCode?: string, message?: string): Promise<void>;
42
97
  /**
43
98
  * Track custom event (extensible for future use)
44
99
  */
@@ -1,4 +1,4 @@
1
- import { ApiRequestOptions, ApiResponse, ApiClientConfig, ProductRewardData, ProductPrimaryGroupData, GroupJoinResponseData, GroupInviteResponseData, AuthStrategy, ShareChannel, Contact, CheckoutValidationData, CheckoutConfirmData } from "./types";
1
+ import { ApiRequestOptions, ApiResponse, ApiClientConfig, ProductRewardData, ProductContextData, ProductPrimaryGroupData, GroupJoinResponseData, GroupInviteResponseData, InviteResolveResponseData, AuthStrategy, ShareChannel, Contact, CheckoutValidationData, CheckoutConfirmData } from "./types";
2
2
  /**
3
3
  * HTTP client for communicating with CoBuy API
4
4
  *
@@ -17,8 +17,11 @@ export declare class ApiClient {
17
17
  private botdScore;
18
18
  private traceId;
19
19
  private readonly rewardCache;
20
+ private readonly productContextCache;
20
21
  private readonly REWARD_CACHE_TTL;
21
- private readonly pendingRequests;
22
+ private readonly PRODUCT_CONTEXT_CACHE_TTL;
23
+ private readonly pendingRewardRequests;
24
+ private readonly pendingContextRequests;
22
25
  constructor(config: ApiClientConfig);
23
26
  /**
24
27
  * Update the BotD (Bot Detection) score for fraud detection
@@ -168,6 +171,18 @@ export declare class ApiClient {
168
171
  * }
169
172
  */
170
173
  getTraceId(): string | null;
174
+ private getCachedProductContext;
175
+ private normalizePrimaryGroup;
176
+ private buildRewardDataFromContext;
177
+ private setProductContextCache;
178
+ /**
179
+ * Get product context information
180
+ *
181
+ * Uses the consolidated bootstrap endpoint so the SDK can resolve campaign,
182
+ * reward, primary group, and active groups in a single request.
183
+ */
184
+ getProductContext(productId: string): Promise<ApiResponse<ProductContextData>>;
185
+ private fetchProductContext;
171
186
  /**
172
187
  * Get product reward information
173
188
  *
@@ -367,6 +382,36 @@ export declare class ApiClient {
367
382
  * ```
368
383
  */
369
384
  inviteToGroup(groupId: string, sharedVia: ShareChannel): Promise<ApiResponse<GroupInviteResponseData>>;
385
+ /**
386
+ * Resolve an invite token to get product and group information
387
+ *
388
+ * Resolves an invite link token (e.g., from https://brand.cobuyza.co.za/i/QMeHD7ew)
389
+ * to get the associated product, group, and invite metadata.
390
+ *
391
+ * @param {string} inviteToken - The invite token from the URL
392
+ * @returns {Promise<ApiResponse<InviteResolveResponseData>>} Product and group information
393
+ *
394
+ * @description
395
+ * Features:
396
+ * - Resolves invite tokens to product/group details
397
+ * - Tracks invite click counts
398
+ * - Returns invite metadata (shared_via, click_count)
399
+ * - Used for invite link handling in applications
400
+ *
401
+ * @example
402
+ * ```typescript
403
+ * // Resolve invite token from URL
404
+ * const response = await client.resolveInvite('QMeHD7ew');
405
+ *
406
+ * if (response.success) {
407
+ * const productId = response.data.product.id;
408
+ * const groupId = response.data.group.id;
409
+ * // Navigate to product page
410
+ * window.location.href = `/product/${productId}`;
411
+ * }
412
+ * ```
413
+ */
414
+ resolveInvite(inviteToken: string): Promise<ApiResponse<InviteResolveResponseData>>;
370
415
  /**
371
416
  * Set or update contact information for the current session
372
417
  *
@@ -1,4 +1,4 @@
1
- import { CoBuySDK, CoBuyInitOptions, RenderWidgetOptions, ModalOptions, Contact, CheckoutValidationData, CheckoutConfirmData } from "./types";
1
+ import { CoBuySDK, CoBuyInitOptions, RenderWidgetOptions, ModalOptions, Contact, CheckoutValidationData, CheckoutConfirmData, InviteResolveResponseData } from "./types";
2
2
  import { ApiClient } from "./api-client";
3
3
  import { AnalyticsClient } from "./analytics";
4
4
  import { SocketManager } from "./socket";
@@ -246,6 +246,32 @@ export declare class CoBuy implements CoBuySDK {
246
246
  * ```
247
247
  */
248
248
  setContact(contact: Contact): Promise<void>;
249
+ /**
250
+ * Resolve an invite token to get product and group information
251
+ *
252
+ * Resolves an invite link token (e.g., from https://brand.cobuyza.co.za/i/QMeHD7ew)
253
+ * to get the associated product, group, and invite metadata. Use this to handle
254
+ * invite links in your application routing.
255
+ *
256
+ * @param inviteToken - The invite token from the URL
257
+ * @returns Promise with invite resolution data or null if failed
258
+ *
259
+ * @example
260
+ * ```typescript
261
+ * // Extract token from URL path like /i/QMeHD7ew
262
+ * const pathParts = window.location.pathname.split('/i/');
263
+ * if (pathParts.length > 1) {
264
+ * const inviteToken = pathParts[1];
265
+ * const inviteData = await CoBuy.resolveInvite(inviteToken);
266
+ *
267
+ * if (inviteData) {
268
+ * // Navigate to product page
269
+ * window.location.href = `/product/${inviteData.product.id}`;
270
+ * }
271
+ * }
272
+ * ```
273
+ */
274
+ resolveInvite(inviteToken: string): Promise<InviteResolveResponseData | null>;
249
275
  /**
250
276
  * Validate checkout for a group
251
277
  *
@@ -2,6 +2,7 @@
2
2
  * API endpoint paths for active CoBuy backend endpoints
3
3
  */
4
4
  export declare const API_ENDPOINTS: {
5
+ readonly PRODUCT_CONTEXT: "/v1/sdk/products/:productId/context";
5
6
  readonly PRODUCT_REWARD: "/v1/sdk/products/:productId/reward";
6
7
  readonly PRODUCT_PRIMARY_GROUP: "/v1/sdk/products/:productId/group/primary";
7
8
  readonly GROUP_JOIN: "/v1/sdk/groups/:groupId/join";
@@ -11,6 +12,7 @@ export declare const API_ENDPOINTS: {
11
12
  readonly GROUP_CHECKOUT_PREPARE: "/v1/sdk/groups/:groupId/checkout/prepare";
12
13
  readonly GROUP_CHECKOUT_VALIDATE: "/v1/sdk/groups/:groupId/checkout/validate";
13
14
  readonly GROUP_CHECKOUT_CONFIRM: "/v1/sdk/groups/:groupId/checkout/confirm";
15
+ readonly INVITE_RESOLVE: "/v1/sdk/invite/resolve";
14
16
  };
15
17
  /**
16
18
  * Build full API URL from base URL and endpoint path
@@ -126,6 +126,29 @@ export interface PerformanceConfig {
126
126
  /**
127
127
  * Options for initializing the CoBuy SDK
128
128
  */
129
+ /**
130
+ * Geographic data provided by the merchant at SDK init time
131
+ */
132
+ export interface GeoData {
133
+ latitude?: number;
134
+ longitude?: number;
135
+ city?: string;
136
+ region?: string;
137
+ country?: string;
138
+ [key: string]: unknown;
139
+ }
140
+ /**
141
+ * Device data provided by the merchant at SDK init time
142
+ */
143
+ export interface DeviceData {
144
+ /** "mobile" | "tablet" | "desktop" */
145
+ type?: string;
146
+ os?: string;
147
+ browser?: string;
148
+ screenWidth?: number;
149
+ screenHeight?: number;
150
+ [key: string]: unknown;
151
+ }
129
152
  export interface CoBuyInitOptions {
130
153
  /**
131
154
  * Authentication mode (default: "public")
@@ -207,6 +230,16 @@ export interface CoBuyInitOptions {
207
230
  * ```
208
231
  */
209
232
  performance?: PerformanceConfig;
233
+ /**
234
+ * Optional geographic data for analytics (merchant-provided)
235
+ * Use when the merchant's backend has resolved geo info from IP or user input
236
+ */
237
+ geo?: GeoData;
238
+ /**
239
+ * Optional device data for analytics (merchant-provided)
240
+ * Collect from browser APIs (navigator, screen) and pass here
241
+ */
242
+ device?: DeviceData;
210
243
  }
211
244
  /**
212
245
  * Callback data structure for checkout events
@@ -503,7 +536,7 @@ export interface Reward {
503
536
  id: string;
504
537
  name: string;
505
538
  type: RewardType;
506
- value: string;
539
+ value: string | number;
507
540
  description: string | null;
508
541
  remaining_quantity: number;
509
542
  total_quantity: number;
@@ -523,14 +556,55 @@ export interface RewardEligibility {
523
556
  */
524
557
  export interface ProductRewardData {
525
558
  productId: string;
526
- reward: Reward;
559
+ reward: Reward | null;
560
+ campaign_mode?: "group" | "no_group";
561
+ campaign_creative_id?: string | null;
527
562
  eligibility: RewardEligibility;
528
563
  }
564
+ export interface ProductContextProductData {
565
+ id: string;
566
+ external_product_id: string | null;
567
+ name: string;
568
+ description: string | null;
569
+ sku: string | null;
570
+ price: number;
571
+ images: unknown[];
572
+ }
573
+ export interface ProductContextCampaignData {
574
+ id: string;
575
+ name: string;
576
+ description: string | null;
577
+ status: string | null;
578
+ campaign_mode?: "group" | "no_group" | null;
579
+ min_group_size?: number | null;
580
+ total_groups_count?: number | null;
581
+ reward_type?: string | null;
582
+ reward_value?: string | number | null;
583
+ start_date?: string | null;
584
+ end_date?: string | null;
585
+ }
586
+ export interface ProductContextData {
587
+ product_id: string;
588
+ product: ProductContextProductData | null;
589
+ campaign: ProductContextCampaignData | null;
590
+ reward: Reward | null;
591
+ primary_group: ProductPrimaryGroupData | null;
592
+ active_groups: Array<ProductPrimaryGroupData & {
593
+ is_member?: boolean;
594
+ }>;
595
+ eligibility: RewardEligibility;
596
+ sdk: {
597
+ ready: boolean;
598
+ campaign_status: string | null;
599
+ has_primary_group: boolean;
600
+ active_group_count: number;
601
+ };
602
+ }
529
603
  /**
530
604
  * Primary group information for a product (SCRUM-284)
531
605
  */
532
606
  export interface ProductPrimaryGroupData {
533
- group: ProductPrimaryGroupData | PromiseLike<ProductPrimaryGroupData | null> | null;
607
+ group?: ProductPrimaryGroupData | null;
534
608
  id: string;
535
609
  group_name: string;
536
610
  description: string | null;
@@ -582,6 +656,41 @@ export interface GroupInviteResponseData {
582
656
  };
583
657
  [key: string]: unknown;
584
658
  }
659
+ /**
660
+ * Invite resolution response data
661
+ */
662
+ export interface InviteResolveResponseData {
663
+ product: {
664
+ id: string;
665
+ name: string;
666
+ images: string[];
667
+ price: number;
668
+ description: string;
669
+ };
670
+ creative: {
671
+ id: string;
672
+ name: string;
673
+ contact_required: boolean;
674
+ };
675
+ brand: {
676
+ id: string;
677
+ name: string;
678
+ };
679
+ group: {
680
+ id: string;
681
+ group_name: string;
682
+ description: string;
683
+ current_count: number;
684
+ required_count: number;
685
+ status: string;
686
+ auto_created: boolean;
687
+ expiry_at: string;
688
+ };
689
+ invite_metadata: {
690
+ shared_via: string;
691
+ click_count: number;
692
+ };
693
+ }
585
694
  /**
586
695
  * Options for rendering the CoBuy widget
587
696
  */
@@ -672,6 +781,13 @@ export interface CoBuySDK {
672
781
  * @param _contact Contact information (email or phone)
673
782
  */
674
783
  setContact(_contact: Contact): Promise<void>;
784
+ /**
785
+ * Resolve an invite token to get product and group information
786
+ * Used to handle invite links like https://brand.cobuyza.co.za/i/{token}
787
+ * @param _inviteToken The invite token from the URL
788
+ * @returns Promise with invite resolution data including product, group, and metadata
789
+ */
790
+ resolveInvite(_inviteToken: string): Promise<InviteResolveResponseData | null>;
675
791
  /**
676
792
  * Validate checkout for a group
677
793
  * Validates the checkout reference and confirms the order can proceed
@@ -726,6 +842,8 @@ export interface InternalConfig {
726
842
  maxRetries: number;
727
843
  animationSpeed: "fast" | "normal" | "slow";
728
844
  };
845
+ geo?: GeoData;
846
+ device?: DeviceData;
729
847
  }
730
848
  /**
731
849
  * Group status enumeration
@@ -1,4 +1,5 @@
1
1
  import { ApiClient } from "../../core/api-client";
2
+ import { AnalyticsClient } from "../../core/analytics";
2
3
  import { ProductPrimaryGroupData, GroupJoinResponseData } from "../../core/types";
3
4
  export interface GroupListItem {
4
5
  groupId: string;
@@ -27,12 +28,15 @@ export declare class GroupListModal {
27
28
  private currentJoinedGroupId;
28
29
  private currentProductId;
29
30
  private currentSessionId;
31
+ private analyticsClient;
30
32
  private onGroupJoined;
31
33
  private onViewProgress;
32
34
  private socketListenerRegistered;
33
35
  private readonly escapeHandler;
34
36
  private readonly handleGroupMemberJoinedEvent;
35
37
  constructor(groups?: GroupListItem[], liveCount?: number, debug?: boolean, apiClient?: ApiClient | null);
38
+ /** Set the analytics client for event tracking */
39
+ setAnalyticsClient(client: AnalyticsClient): void;
36
40
  /** Set callback for when a group is joined successfully */
37
41
  setOnGroupJoined(callback: (joinData: GroupJoinResponseData) => void): void;
38
42
  /** Set callback for when viewing progress on an already joined group */
@@ -185,4 +185,10 @@ export declare class WidgetRoot {
185
185
  * Expose current product id for optional filtering by host
186
186
  */
187
187
  getProductId(): string | null;
188
+ /**
189
+ * Returns the group ID that the current user has joined via this widget, or null if the user
190
+ * is only an observer (has not actively joined a group this session).
191
+ * Used by the CoBuy host class to check membership before preparing checkout.
192
+ */
193
+ getJoinedGroupId(): string | null;
188
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cshah18/sdk",
3
- "version": "4.12.0",
3
+ "version": "4.14.0",
4
4
  "description": "CoBuy Embedded SDK for browser JavaScript integration",
5
5
  "type": "module",
6
6
  "main": "dist/cobuy-sdk.umd.js",