@tolinku/react-native-sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -105,6 +105,32 @@ await Tolinku.referrals.claimReward(referral_code);
105
105
  const { leaderboard } = await Tolinku.referrals.leaderboard(10);
106
106
  ```
107
107
 
108
+ ### Ecommerce
109
+
110
+ Track purchases, cart activity, and product events with built-in revenue analytics. Available on paid plans.
111
+
112
+ ```typescript
113
+ Tolinku.setUserId('user_123');
114
+
115
+ // Track a product view
116
+ await Tolinku.ecommerce.viewItem({
117
+ items: [{ item_id: 'sku_1', item_name: 'T-Shirt', price: 24.99 }]
118
+ });
119
+
120
+ // Track a purchase
121
+ await Tolinku.ecommerce.purchase({
122
+ transaction_id: 'order_456',
123
+ revenue: 49.99,
124
+ currency: 'USD',
125
+ items: [{ item_id: 'sku_1', item_name: 'T-Shirt', price: 24.99, quantity: 2 }]
126
+ });
127
+
128
+ // Flush ecommerce events
129
+ await Tolinku.ecommerce.flush();
130
+ ```
131
+
132
+ The SDK supports 13 event types covering the full shopping journey. Cart IDs are managed automatically via `AsyncStorage` and cleared after purchase. Events auto-flush when the app enters the background.
133
+
108
134
  ### Deferred Deep Links
109
135
 
110
136
  Recover deep link context for users who installed your app after clicking a link. Deferred deep linking lets you route users to specific content even when the app was not installed at the time of the click.
@@ -201,6 +227,25 @@ await Tolinku.destroy();
201
227
  | `claimReward(code)` | Claim a referral reward |
202
228
  | `leaderboard(limit?)` | Fetch the referral leaderboard |
203
229
 
230
+ ### `Tolinku.ecommerce`
231
+
232
+ | Method | Description |
233
+ |--------|-------------|
234
+ | `viewItem(params)` | Track a product view |
235
+ | `addToCart(params)` | Track item added to cart |
236
+ | `removeFromCart(params)` | Track item removed from cart |
237
+ | `addToWishlist(params)` | Track item added to wishlist |
238
+ | `viewCart()` | Track cart view |
239
+ | `addPaymentInfo()` | Track payment info entered |
240
+ | `beginCheckout(params?)` | Track checkout started |
241
+ | `purchase(params)` | Track a purchase |
242
+ | `refund(params)` | Track a refund |
243
+ | `search(params)` | Track a product search |
244
+ | `share(params)` | Track a product share |
245
+ | `rate(params)` | Track a product rating |
246
+ | `spendCredits(params)` | Track loyalty credits spent |
247
+ | `flush()` | Send all queued ecommerce events |
248
+
204
249
  ### `Tolinku.deferred`
205
250
 
206
251
  | Method | Description |
package/dist/index.d.mts CHANGED
@@ -146,6 +146,78 @@ interface ShowMessageOptions {
146
146
  onDismiss?: (messageId: string) => void;
147
147
  onButtonPress?: (action: string, messageId: string) => void;
148
148
  }
149
+ interface EcommerceItem {
150
+ item_id: string;
151
+ item_name?: string;
152
+ item_category?: string;
153
+ item_brand?: string;
154
+ item_variant?: string;
155
+ item_list_name?: string;
156
+ item_list_id?: string;
157
+ item_image_url?: string;
158
+ price?: number;
159
+ quantity?: number;
160
+ currency?: string;
161
+ coupon_code?: string;
162
+ discount?: number;
163
+ }
164
+ interface PurchaseParams {
165
+ transaction_id: string;
166
+ revenue: number;
167
+ currency: string;
168
+ items?: EcommerceItem[];
169
+ cart_id?: string;
170
+ coupon_code?: string;
171
+ discount?: number;
172
+ shipping?: number;
173
+ tax?: number;
174
+ }
175
+ interface AddToCartParams {
176
+ items: EcommerceItem[];
177
+ cart_id?: string;
178
+ }
179
+ interface RemoveFromCartParams {
180
+ items: EcommerceItem[];
181
+ cart_id?: string;
182
+ }
183
+ interface AddToWishlistParams {
184
+ items: EcommerceItem[];
185
+ }
186
+ interface BeginCheckoutParams {
187
+ revenue?: number;
188
+ currency?: string;
189
+ cart_id?: string;
190
+ items?: EcommerceItem[];
191
+ }
192
+ interface RefundParams {
193
+ transaction_id: string;
194
+ revenue: number;
195
+ currency?: string;
196
+ items?: EcommerceItem[];
197
+ }
198
+ interface ViewItemParams {
199
+ items: EcommerceItem[];
200
+ }
201
+ interface SearchParams {
202
+ search_term: string;
203
+ }
204
+ interface AddPaymentInfoParams {
205
+ cart_id?: string;
206
+ }
207
+ interface ShareParams {
208
+ item_id?: string;
209
+ url?: string;
210
+ method?: string;
211
+ }
212
+ interface RateParams {
213
+ item_id: string;
214
+ rating: number;
215
+ max_rating?: number;
216
+ }
217
+ interface SpendCreditsParams {
218
+ revenue: number;
219
+ currency: string;
220
+ }
149
221
 
150
222
  declare class HttpClient {
151
223
  private baseUrl;
@@ -185,6 +257,41 @@ declare class TolinkuError extends Error {
185
257
  constructor(message: string, status: number, code?: string);
186
258
  }
187
259
 
260
+ declare class Ecommerce {
261
+ private client;
262
+ private queue;
263
+ private flushTimer;
264
+ private appStateSubscription;
265
+ private isFlushing;
266
+ private getUserId;
267
+ private memoryCartId;
268
+ constructor(client: HttpClient, getUserId: () => string | null);
269
+ viewItem(params: ViewItemParams): Promise<void>;
270
+ addToCart(params: AddToCartParams): Promise<void>;
271
+ removeFromCart(params: RemoveFromCartParams): Promise<void>;
272
+ addToWishlist(params: AddToWishlistParams): Promise<void>;
273
+ viewCart(): Promise<void>;
274
+ addPaymentInfo(params?: AddPaymentInfoParams): Promise<void>;
275
+ beginCheckout(params: BeginCheckoutParams): Promise<void>;
276
+ purchase(params: PurchaseParams): Promise<void>;
277
+ refund(params: RefundParams): Promise<void>;
278
+ search(params: SearchParams): Promise<void>;
279
+ share(params: ShareParams): Promise<void>;
280
+ rate(params: RateParams): Promise<void>;
281
+ spendCredits(params: SpendCreditsParams): Promise<void>;
282
+ flush(): Promise<void>;
283
+ destroy(): Promise<void>;
284
+ private enqueue;
285
+ private handleAppStateChange;
286
+ private startFlushTimer;
287
+ private cancelFlushTimer;
288
+ private getOrCreateCartId;
289
+ private getCartId;
290
+ private setCartId;
291
+ private clearCartId;
292
+ private generateId;
293
+ }
294
+
188
295
  declare class Referrals {
189
296
  private client;
190
297
  constructor(client: HttpClient);
@@ -230,6 +337,7 @@ declare class Tolinku {
230
337
  static readonly VERSION = "0.1.0";
231
338
  private static client;
232
339
  private static analyticsInstance;
340
+ private static ecommerceInstance;
233
341
  private static referralsInstance;
234
342
  private static deferredInstance;
235
343
  private static _initialized;
@@ -259,9 +367,11 @@ declare class Tolinku {
259
367
  */
260
368
  static track(eventType: string, properties?: TrackProperties): Promise<void>;
261
369
  /**
262
- * Immediately flush all queued analytics events to the server.
370
+ * Immediately flush all queued analytics and ecommerce events to the server.
263
371
  */
264
372
  static flush(): Promise<void>;
373
+ /** Ecommerce: track purchases, carts, products, revenue */
374
+ static get ecommerce(): Ecommerce;
265
375
  /** Referrals: create, complete, milestone, leaderboard, claimReward */
266
376
  static get referrals(): Referrals;
267
377
  /** Deferred deep links: claimByToken, claimBySignals */
@@ -303,4 +413,4 @@ declare function TolinkuMessages({ trigger, triggerValue, onDismiss, onButtonPre
303
413
  */
304
414
  declare function isSafeUrl(url: string): boolean;
305
415
 
306
- export { type ClaimBySignalsOptions, type CompleteReferralOptions, type CompleteReferralResult, type CreateReferralOptions, type CreateReferralResult, type DeferredLink, type LeaderboardEntry, type Message, type MessageComponent, type MessageContent, type MilestoneOptions, type MilestoneResult, type ReferralInfo, type ResolvedTolinkuConfig, type ShowMessageOptions, Tolinku, type TolinkuConfig, TolinkuError, TolinkuMessages, type TrackProperties, isSafeUrl };
416
+ export { type AddPaymentInfoParams, type AddToCartParams, type AddToWishlistParams, type BeginCheckoutParams, type ClaimBySignalsOptions, type CompleteReferralOptions, type CompleteReferralResult, type CreateReferralOptions, type CreateReferralResult, type DeferredLink, type EcommerceItem, type LeaderboardEntry, type Message, type MessageComponent, type MessageContent, type MilestoneOptions, type MilestoneResult, type PurchaseParams, type RateParams, type ReferralInfo, type RefundParams, type RemoveFromCartParams, type ResolvedTolinkuConfig, type SearchParams, type ShareParams, type ShowMessageOptions, type SpendCreditsParams, Tolinku, type TolinkuConfig, TolinkuError, TolinkuMessages, type TrackProperties, type ViewItemParams, isSafeUrl };
package/dist/index.d.ts CHANGED
@@ -146,6 +146,78 @@ interface ShowMessageOptions {
146
146
  onDismiss?: (messageId: string) => void;
147
147
  onButtonPress?: (action: string, messageId: string) => void;
148
148
  }
149
+ interface EcommerceItem {
150
+ item_id: string;
151
+ item_name?: string;
152
+ item_category?: string;
153
+ item_brand?: string;
154
+ item_variant?: string;
155
+ item_list_name?: string;
156
+ item_list_id?: string;
157
+ item_image_url?: string;
158
+ price?: number;
159
+ quantity?: number;
160
+ currency?: string;
161
+ coupon_code?: string;
162
+ discount?: number;
163
+ }
164
+ interface PurchaseParams {
165
+ transaction_id: string;
166
+ revenue: number;
167
+ currency: string;
168
+ items?: EcommerceItem[];
169
+ cart_id?: string;
170
+ coupon_code?: string;
171
+ discount?: number;
172
+ shipping?: number;
173
+ tax?: number;
174
+ }
175
+ interface AddToCartParams {
176
+ items: EcommerceItem[];
177
+ cart_id?: string;
178
+ }
179
+ interface RemoveFromCartParams {
180
+ items: EcommerceItem[];
181
+ cart_id?: string;
182
+ }
183
+ interface AddToWishlistParams {
184
+ items: EcommerceItem[];
185
+ }
186
+ interface BeginCheckoutParams {
187
+ revenue?: number;
188
+ currency?: string;
189
+ cart_id?: string;
190
+ items?: EcommerceItem[];
191
+ }
192
+ interface RefundParams {
193
+ transaction_id: string;
194
+ revenue: number;
195
+ currency?: string;
196
+ items?: EcommerceItem[];
197
+ }
198
+ interface ViewItemParams {
199
+ items: EcommerceItem[];
200
+ }
201
+ interface SearchParams {
202
+ search_term: string;
203
+ }
204
+ interface AddPaymentInfoParams {
205
+ cart_id?: string;
206
+ }
207
+ interface ShareParams {
208
+ item_id?: string;
209
+ url?: string;
210
+ method?: string;
211
+ }
212
+ interface RateParams {
213
+ item_id: string;
214
+ rating: number;
215
+ max_rating?: number;
216
+ }
217
+ interface SpendCreditsParams {
218
+ revenue: number;
219
+ currency: string;
220
+ }
149
221
 
150
222
  declare class HttpClient {
151
223
  private baseUrl;
@@ -185,6 +257,41 @@ declare class TolinkuError extends Error {
185
257
  constructor(message: string, status: number, code?: string);
186
258
  }
187
259
 
260
+ declare class Ecommerce {
261
+ private client;
262
+ private queue;
263
+ private flushTimer;
264
+ private appStateSubscription;
265
+ private isFlushing;
266
+ private getUserId;
267
+ private memoryCartId;
268
+ constructor(client: HttpClient, getUserId: () => string | null);
269
+ viewItem(params: ViewItemParams): Promise<void>;
270
+ addToCart(params: AddToCartParams): Promise<void>;
271
+ removeFromCart(params: RemoveFromCartParams): Promise<void>;
272
+ addToWishlist(params: AddToWishlistParams): Promise<void>;
273
+ viewCart(): Promise<void>;
274
+ addPaymentInfo(params?: AddPaymentInfoParams): Promise<void>;
275
+ beginCheckout(params: BeginCheckoutParams): Promise<void>;
276
+ purchase(params: PurchaseParams): Promise<void>;
277
+ refund(params: RefundParams): Promise<void>;
278
+ search(params: SearchParams): Promise<void>;
279
+ share(params: ShareParams): Promise<void>;
280
+ rate(params: RateParams): Promise<void>;
281
+ spendCredits(params: SpendCreditsParams): Promise<void>;
282
+ flush(): Promise<void>;
283
+ destroy(): Promise<void>;
284
+ private enqueue;
285
+ private handleAppStateChange;
286
+ private startFlushTimer;
287
+ private cancelFlushTimer;
288
+ private getOrCreateCartId;
289
+ private getCartId;
290
+ private setCartId;
291
+ private clearCartId;
292
+ private generateId;
293
+ }
294
+
188
295
  declare class Referrals {
189
296
  private client;
190
297
  constructor(client: HttpClient);
@@ -230,6 +337,7 @@ declare class Tolinku {
230
337
  static readonly VERSION = "0.1.0";
231
338
  private static client;
232
339
  private static analyticsInstance;
340
+ private static ecommerceInstance;
233
341
  private static referralsInstance;
234
342
  private static deferredInstance;
235
343
  private static _initialized;
@@ -259,9 +367,11 @@ declare class Tolinku {
259
367
  */
260
368
  static track(eventType: string, properties?: TrackProperties): Promise<void>;
261
369
  /**
262
- * Immediately flush all queued analytics events to the server.
370
+ * Immediately flush all queued analytics and ecommerce events to the server.
263
371
  */
264
372
  static flush(): Promise<void>;
373
+ /** Ecommerce: track purchases, carts, products, revenue */
374
+ static get ecommerce(): Ecommerce;
265
375
  /** Referrals: create, complete, milestone, leaderboard, claimReward */
266
376
  static get referrals(): Referrals;
267
377
  /** Deferred deep links: claimByToken, claimBySignals */
@@ -303,4 +413,4 @@ declare function TolinkuMessages({ trigger, triggerValue, onDismiss, onButtonPre
303
413
  */
304
414
  declare function isSafeUrl(url: string): boolean;
305
415
 
306
- export { type ClaimBySignalsOptions, type CompleteReferralOptions, type CompleteReferralResult, type CreateReferralOptions, type CreateReferralResult, type DeferredLink, type LeaderboardEntry, type Message, type MessageComponent, type MessageContent, type MilestoneOptions, type MilestoneResult, type ReferralInfo, type ResolvedTolinkuConfig, type ShowMessageOptions, Tolinku, type TolinkuConfig, TolinkuError, TolinkuMessages, type TrackProperties, isSafeUrl };
416
+ export { type AddPaymentInfoParams, type AddToCartParams, type AddToWishlistParams, type BeginCheckoutParams, type ClaimBySignalsOptions, type CompleteReferralOptions, type CompleteReferralResult, type CreateReferralOptions, type CreateReferralResult, type DeferredLink, type EcommerceItem, type LeaderboardEntry, type Message, type MessageComponent, type MessageContent, type MilestoneOptions, type MilestoneResult, type PurchaseParams, type RateParams, type ReferralInfo, type RefundParams, type RemoveFromCartParams, type ResolvedTolinkuConfig, type SearchParams, type ShareParams, type ShowMessageOptions, type SpendCreditsParams, Tolinku, type TolinkuConfig, TolinkuError, TolinkuMessages, type TrackProperties, type ViewItemParams, isSafeUrl };
package/dist/index.js CHANGED
@@ -353,6 +353,215 @@ var Analytics = class {
353
353
  }
354
354
  }
355
355
  };
356
+ var BATCH_SIZE2 = 10;
357
+ var FLUSH_INTERVAL_MS2 = 5e3;
358
+ var MAX_QUEUE_SIZE2 = 500;
359
+ var CART_ID_STORAGE_KEY = "tolinku_ecom_cart_id";
360
+ var Ecommerce = class {
361
+ constructor(client, getUserId) {
362
+ this.queue = [];
363
+ this.flushTimer = null;
364
+ this.appStateSubscription = null;
365
+ this.isFlushing = false;
366
+ this.memoryCartId = null;
367
+ this.handleAppStateChange = (state) => {
368
+ if (state === "background" || state === "inactive") {
369
+ this.flush().catch(() => {
370
+ });
371
+ }
372
+ };
373
+ this.client = client;
374
+ this.getUserId = getUserId;
375
+ this.appStateSubscription = reactNative.AppState.addEventListener(
376
+ "change",
377
+ this.handleAppStateChange
378
+ );
379
+ }
380
+ // ─── Public methods (13 event types) ────────────────────
381
+ async viewItem(params) {
382
+ await this.enqueue({ event_type: "view_item", items: params.items });
383
+ }
384
+ async addToCart(params) {
385
+ const cartId = params.cart_id || await this.getOrCreateCartId();
386
+ await this.enqueue({ event_type: "add_to_cart", items: params.items, cart_id: cartId });
387
+ }
388
+ async removeFromCart(params) {
389
+ const cartId = params.cart_id || await this.getCartId();
390
+ await this.enqueue({ event_type: "remove_from_cart", items: params.items, cart_id: cartId });
391
+ }
392
+ async addToWishlist(params) {
393
+ await this.enqueue({ event_type: "add_to_wishlist", items: params.items });
394
+ }
395
+ async viewCart() {
396
+ const cartId = await this.getCartId();
397
+ await this.enqueue({ event_type: "view_cart", cart_id: cartId });
398
+ }
399
+ async addPaymentInfo(params) {
400
+ const cartId = params?.cart_id || await this.getCartId();
401
+ await this.enqueue({ event_type: "add_payment_info", cart_id: cartId });
402
+ }
403
+ async beginCheckout(params) {
404
+ const cartId = params.cart_id || await this.getCartId();
405
+ await this.enqueue({
406
+ event_type: "begin_checkout",
407
+ revenue: params.revenue,
408
+ currency: params.currency,
409
+ cart_id: cartId,
410
+ items: params.items
411
+ });
412
+ }
413
+ async purchase(params) {
414
+ const cartId = params.cart_id || await this.getCartId();
415
+ await this.enqueue({
416
+ event_type: "purchase",
417
+ transaction_id: params.transaction_id,
418
+ revenue: params.revenue,
419
+ currency: params.currency,
420
+ cart_id: cartId,
421
+ coupon_code: params.coupon_code,
422
+ discount: params.discount,
423
+ shipping: params.shipping,
424
+ tax: params.tax,
425
+ items: params.items
426
+ });
427
+ await this.clearCartId();
428
+ }
429
+ async refund(params) {
430
+ await this.enqueue({
431
+ event_type: "refund",
432
+ transaction_id: params.transaction_id,
433
+ revenue: params.revenue,
434
+ currency: params.currency,
435
+ items: params.items
436
+ });
437
+ }
438
+ async search(params) {
439
+ await this.enqueue({ event_type: "search", properties: { search_term: params.search_term } });
440
+ }
441
+ async share(params) {
442
+ const props = {};
443
+ if (params.item_id) props.item_id = params.item_id;
444
+ if (params.url) props.url = params.url;
445
+ if (params.method) props.method = params.method;
446
+ await this.enqueue({ event_type: "share", properties: props });
447
+ }
448
+ async rate(params) {
449
+ await this.enqueue({
450
+ event_type: "rate",
451
+ properties: {
452
+ item_id: params.item_id,
453
+ rating: String(params.rating),
454
+ ...params.max_rating != null ? { max_rating: String(params.max_rating) } : {}
455
+ }
456
+ });
457
+ }
458
+ async spendCredits(params) {
459
+ await this.enqueue({ event_type: "spend_credits", revenue: params.revenue, currency: params.currency });
460
+ }
461
+ // ─── Flush ─────────────────────────────────────────────
462
+ async flush() {
463
+ if (this.queue.length === 0 || this.isFlushing) return;
464
+ this.isFlushing = true;
465
+ const events = this.queue.splice(0);
466
+ this.cancelFlushTimer();
467
+ try {
468
+ debugLog(`Flushing ${events.length} ecommerce event(s)`);
469
+ const result = await this.client.post(
470
+ "/v1/api/analytics/ecommerce/batch",
471
+ { events }
472
+ );
473
+ if (result.errors && result.errors.length > 0) {
474
+ debugWarn(`Ecommerce batch partial failure: ${result.errors.join(", ")}`);
475
+ }
476
+ } catch (err) {
477
+ debugWarn(`Failed to flush ecommerce events: ${err.message}`);
478
+ const spaceLeft = MAX_QUEUE_SIZE2 - this.queue.length;
479
+ if (spaceLeft > 0) {
480
+ this.queue.unshift(...events.slice(0, spaceLeft));
481
+ }
482
+ } finally {
483
+ this.isFlushing = false;
484
+ }
485
+ }
486
+ async destroy() {
487
+ this.cancelFlushTimer();
488
+ this.appStateSubscription?.remove();
489
+ this.appStateSubscription = null;
490
+ try {
491
+ await this.flush();
492
+ } catch {
493
+ }
494
+ }
495
+ // ─── Private ───────────────────────────────────────────
496
+ async enqueue(event) {
497
+ const userId = this.getUserId();
498
+ if (userId) event.user_id = userId;
499
+ if (this.queue.length >= MAX_QUEUE_SIZE2) {
500
+ debugWarn(`Ecommerce queue full (${MAX_QUEUE_SIZE2}). Dropping oldest event.`);
501
+ this.queue.shift();
502
+ }
503
+ this.queue.push(event);
504
+ if (this.queue.length >= BATCH_SIZE2) {
505
+ await this.flush();
506
+ } else if (this.queue.length === 1) {
507
+ this.startFlushTimer();
508
+ }
509
+ }
510
+ startFlushTimer() {
511
+ this.cancelFlushTimer();
512
+ this.flushTimer = setTimeout(() => {
513
+ this.flush().catch((err) => {
514
+ debugWarn(`Ecommerce timer flush failed: ${err.message}`);
515
+ });
516
+ }, FLUSH_INTERVAL_MS2);
517
+ }
518
+ cancelFlushTimer() {
519
+ if (this.flushTimer !== null) {
520
+ clearTimeout(this.flushTimer);
521
+ this.flushTimer = null;
522
+ }
523
+ }
524
+ // ─── Cart ID lifecycle (AsyncStorage + memory fallback) ─
525
+ async getOrCreateCartId() {
526
+ const existing = await this.getCartId();
527
+ if (existing) return existing;
528
+ const cartId = this.generateId();
529
+ await this.setCartId(cartId);
530
+ return cartId;
531
+ }
532
+ async getCartId() {
533
+ try {
534
+ const stored = await AsyncStorage__default.default.getItem(CART_ID_STORAGE_KEY);
535
+ if (stored) return stored;
536
+ } catch {
537
+ }
538
+ return this.memoryCartId || void 0;
539
+ }
540
+ async setCartId(cartId) {
541
+ this.memoryCartId = cartId;
542
+ try {
543
+ await AsyncStorage__default.default.setItem(CART_ID_STORAGE_KEY, cartId);
544
+ } catch {
545
+ }
546
+ }
547
+ async clearCartId() {
548
+ this.memoryCartId = null;
549
+ try {
550
+ await AsyncStorage__default.default.removeItem(CART_ID_STORAGE_KEY);
551
+ } catch {
552
+ }
553
+ }
554
+ generateId() {
555
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
556
+ return crypto.randomUUID();
557
+ }
558
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
559
+ const r = Math.random() * 16 | 0;
560
+ const v = c === "x" ? r : r & 3 | 8;
561
+ return v.toString(16);
562
+ });
563
+ }
564
+ };
356
565
 
357
566
  // src/referrals.ts
358
567
  var Referrals = class {
@@ -568,6 +777,7 @@ var _Tolinku = class _Tolinku {
568
777
  setStorageNamespace(config.apiKey);
569
778
  _Tolinku.client = new HttpClient(resolvedConfig);
570
779
  _Tolinku.analyticsInstance = new Analytics(_Tolinku.client);
780
+ _Tolinku.ecommerceInstance = new Ecommerce(_Tolinku.client, () => _Tolinku._userId);
571
781
  _Tolinku.referralsInstance = new Referrals(_Tolinku.client);
572
782
  _Tolinku.deferredInstance = new Deferred(_Tolinku.client);
573
783
  _Tolinku._initialized = true;
@@ -608,13 +818,23 @@ var _Tolinku = class _Tolinku {
608
818
  return _Tolinku.analyticsInstance.track(eventType, mergedProps);
609
819
  }
610
820
  /**
611
- * Immediately flush all queued analytics events to the server.
821
+ * Immediately flush all queued analytics and ecommerce events to the server.
612
822
  */
613
823
  static async flush() {
614
824
  if (!_Tolinku.analyticsInstance) {
615
825
  throw new Error("Tolinku: SDK not initialized. Call Tolinku.init() first.");
616
826
  }
617
- return _Tolinku.analyticsInstance.flush();
827
+ await Promise.all([
828
+ _Tolinku.analyticsInstance.flush(),
829
+ _Tolinku.ecommerceInstance?.flush()
830
+ ]);
831
+ }
832
+ /** Ecommerce: track purchases, carts, products, revenue */
833
+ static get ecommerce() {
834
+ if (!_Tolinku.ecommerceInstance) {
835
+ throw new Error("Tolinku: SDK not initialized. Call Tolinku.init() first.");
836
+ }
837
+ return _Tolinku.ecommerceInstance;
618
838
  }
619
839
  /** Referrals: create, complete, milestone, leaderboard, claimReward */
620
840
  static get referrals() {
@@ -641,12 +861,16 @@ var _Tolinku = class _Tolinku {
641
861
  if (_Tolinku.analyticsInstance) {
642
862
  await _Tolinku.analyticsInstance.destroy();
643
863
  }
864
+ if (_Tolinku.ecommerceInstance) {
865
+ await _Tolinku.ecommerceInstance.destroy();
866
+ }
644
867
  if (_Tolinku.client) {
645
868
  _Tolinku.client.abort();
646
869
  }
647
870
  resetStorageNamespace();
648
871
  _Tolinku.client = null;
649
872
  _Tolinku.analyticsInstance = null;
873
+ _Tolinku.ecommerceInstance = null;
650
874
  _Tolinku.referralsInstance = null;
651
875
  _Tolinku.deferredInstance = null;
652
876
  _Tolinku._initialized = false;
@@ -657,6 +881,7 @@ var _Tolinku = class _Tolinku {
657
881
  _Tolinku.VERSION = SDK_VERSION;
658
882
  _Tolinku.client = null;
659
883
  _Tolinku.analyticsInstance = null;
884
+ _Tolinku.ecommerceInstance = null;
660
885
  _Tolinku.referralsInstance = null;
661
886
  _Tolinku.deferredInstance = null;
662
887
  _Tolinku._initialized = false;