@tolinku/web-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
@@ -84,6 +84,32 @@ await tolinku.referrals.claimReward(referral_code);
84
84
  const { leaderboard } = await tolinku.referrals.leaderboard(10);
85
85
  ```
86
86
 
87
+ ### Ecommerce
88
+
89
+ Track purchases, cart activity, and product events with built-in revenue analytics. Available on paid plans.
90
+
91
+ ```typescript
92
+ tolinku.setUserId('user_123');
93
+
94
+ // Track a product view
95
+ await tolinku.ecommerce.viewItem({
96
+ items: [{ item_id: 'sku_1', item_name: 'T-Shirt', price: 24.99 }]
97
+ });
98
+
99
+ // Track a purchase
100
+ await tolinku.ecommerce.purchase({
101
+ transaction_id: 'order_456',
102
+ revenue: 49.99,
103
+ currency: 'USD',
104
+ items: [{ item_id: 'sku_1', item_name: 'T-Shirt', price: 24.99, quantity: 2 }]
105
+ });
106
+
107
+ // Flush ecommerce events
108
+ await tolinku.ecommerce.flush();
109
+ ```
110
+
111
+ The SDK supports 13 event types: `viewItem`, `addToCart`, `removeFromCart`, `addToWishlist`, `viewCart`, `addPaymentInfo`, `beginCheckout`, `purchase`, `refund`, `search`, `share`, `rate`, and `spendCredits`. Cart IDs are managed automatically via `sessionStorage` and cleared after purchase.
112
+
87
113
  ### Deferred Deep Links
88
114
 
89
115
  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.
@@ -175,6 +201,25 @@ tolinku.setUserId('user_123');
175
201
  | `claimReward(code)` | Claim a referral reward |
176
202
  | `leaderboard(limit?)` | Fetch the referral leaderboard |
177
203
 
204
+ ### `tolinku.ecommerce`
205
+
206
+ | Method | Description |
207
+ |--------|-------------|
208
+ | `viewItem(params)` | Track a product view |
209
+ | `addToCart(params)` | Track item added to cart |
210
+ | `removeFromCart(params)` | Track item removed from cart |
211
+ | `addToWishlist(params)` | Track item added to wishlist |
212
+ | `viewCart()` | Track cart view |
213
+ | `addPaymentInfo()` | Track payment info entered |
214
+ | `beginCheckout(params?)` | Track checkout started |
215
+ | `purchase(params)` | Track a purchase |
216
+ | `refund(params)` | Track a refund |
217
+ | `search(params)` | Track a product search |
218
+ | `share(params)` | Track a product share |
219
+ | `rate(params)` | Track a product rating |
220
+ | `spendCredits(params)` | Track loyalty credits spent |
221
+ | `flush()` | Send all queued ecommerce events |
222
+
178
223
  ### `tolinku.deferred`
179
224
 
180
225
  | Method | Description |
package/dist/index.d.mts CHANGED
@@ -160,6 +160,78 @@ interface ShowMessageOptions {
160
160
  onDismiss?: (messageId: string) => void;
161
161
  onButtonPress?: (action: string, messageId: string) => void;
162
162
  }
163
+ interface EcommerceItem {
164
+ item_id: string;
165
+ item_name?: string;
166
+ item_category?: string;
167
+ item_brand?: string;
168
+ item_variant?: string;
169
+ item_list_name?: string;
170
+ item_list_id?: string;
171
+ item_image_url?: string;
172
+ price?: number;
173
+ quantity?: number;
174
+ currency?: string;
175
+ coupon_code?: string;
176
+ discount?: number;
177
+ }
178
+ interface PurchaseParams {
179
+ transaction_id: string;
180
+ revenue: number;
181
+ currency: string;
182
+ items?: EcommerceItem[];
183
+ cart_id?: string;
184
+ coupon_code?: string;
185
+ discount?: number;
186
+ shipping?: number;
187
+ tax?: number;
188
+ }
189
+ interface AddToCartParams {
190
+ items: EcommerceItem[];
191
+ cart_id?: string;
192
+ }
193
+ interface RemoveFromCartParams {
194
+ items: EcommerceItem[];
195
+ cart_id?: string;
196
+ }
197
+ interface AddToWishlistParams {
198
+ items: EcommerceItem[];
199
+ }
200
+ interface BeginCheckoutParams {
201
+ revenue?: number;
202
+ currency?: string;
203
+ cart_id?: string;
204
+ items?: EcommerceItem[];
205
+ }
206
+ interface RefundParams {
207
+ transaction_id: string;
208
+ revenue: number;
209
+ currency?: string;
210
+ items?: EcommerceItem[];
211
+ }
212
+ interface ViewItemParams {
213
+ items: EcommerceItem[];
214
+ }
215
+ interface SearchParams {
216
+ search_term: string;
217
+ }
218
+ interface AddPaymentInfoParams {
219
+ cart_id?: string;
220
+ }
221
+ interface ShareParams {
222
+ item_id?: string;
223
+ url?: string;
224
+ method?: string;
225
+ }
226
+ interface RateParams {
227
+ item_id: string;
228
+ rating: number;
229
+ max_rating?: number;
230
+ }
231
+ interface SpendCreditsParams {
232
+ revenue: number;
233
+ currency: string;
234
+ }
163
235
 
164
236
  declare class HttpClient {
165
237
  private _baseUrl;
@@ -225,6 +297,38 @@ declare class Analytics {
225
297
  destroy(): void;
226
298
  }
227
299
 
300
+ declare class Ecommerce {
301
+ private client;
302
+ private queue;
303
+ private flushTimer;
304
+ private unloadHandler;
305
+ private getUserId;
306
+ private memoryCartId;
307
+ constructor(client: HttpClient, getUserId: () => string | null);
308
+ viewItem(params: ViewItemParams): Promise<void>;
309
+ addToCart(params: AddToCartParams): Promise<void>;
310
+ removeFromCart(params: RemoveFromCartParams): Promise<void>;
311
+ addToWishlist(params: AddToWishlistParams): Promise<void>;
312
+ viewCart(): Promise<void>;
313
+ addPaymentInfo(params?: AddPaymentInfoParams): Promise<void>;
314
+ beginCheckout(params: BeginCheckoutParams): Promise<void>;
315
+ purchase(params: PurchaseParams): Promise<void>;
316
+ refund(params: RefundParams): Promise<void>;
317
+ search(params: SearchParams): Promise<void>;
318
+ share(params: ShareParams): Promise<void>;
319
+ rate(params: RateParams): Promise<void>;
320
+ spendCredits(params: SpendCreditsParams): Promise<void>;
321
+ flush(): Promise<void>;
322
+ destroy(): void;
323
+ private enqueue;
324
+ private flushBeacon;
325
+ private getOrCreateCartId;
326
+ private getCartId;
327
+ private setCartId;
328
+ private clearCartId;
329
+ private generateId;
330
+ }
331
+
228
332
  declare class Referrals {
229
333
  private client;
230
334
  constructor(client: HttpClient);
@@ -261,6 +365,8 @@ declare class Tolinku {
261
365
  private client;
262
366
  /** Analytics: track custom events */
263
367
  readonly analytics: Analytics;
368
+ /** Ecommerce: track purchases, carts, products, revenue */
369
+ readonly ecommerce: Ecommerce;
264
370
  /** Referrals: create, complete, milestone, leaderboard */
265
371
  readonly referrals: Referrals;
266
372
  /** Deferred deep links: claim by token or signals */
@@ -289,10 +395,10 @@ declare class Tolinku {
289
395
  showMessage(options?: ShowMessageOptions): Promise<void>;
290
396
  /** Dismiss the currently visible in-app message */
291
397
  dismissMessage(): void;
292
- /** Flush any queued analytics events immediately */
398
+ /** Flush any queued analytics and ecommerce events immediately */
293
399
  flush(): Promise<void>;
294
400
  /** Clean up all DOM elements, flush events, and cancel in-flight requests (e.g. before unmounting in SPAs) */
295
401
  destroy(): void;
296
402
  }
297
403
 
298
- export { type BannerConfig, type BannerItem, 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 ShowBannerOptions, type ShowMessageOptions, Tolinku, type TolinkuConfig, TolinkuError, type TrackProperties };
404
+ export { type AddPaymentInfoParams, type AddToCartParams, type AddToWishlistParams, type BannerConfig, type BannerItem, 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 SearchParams, type ShareParams, type ShowBannerOptions, type ShowMessageOptions, type SpendCreditsParams, Tolinku, type TolinkuConfig, TolinkuError, type TrackProperties, type ViewItemParams };
package/dist/index.d.ts CHANGED
@@ -160,6 +160,78 @@ interface ShowMessageOptions {
160
160
  onDismiss?: (messageId: string) => void;
161
161
  onButtonPress?: (action: string, messageId: string) => void;
162
162
  }
163
+ interface EcommerceItem {
164
+ item_id: string;
165
+ item_name?: string;
166
+ item_category?: string;
167
+ item_brand?: string;
168
+ item_variant?: string;
169
+ item_list_name?: string;
170
+ item_list_id?: string;
171
+ item_image_url?: string;
172
+ price?: number;
173
+ quantity?: number;
174
+ currency?: string;
175
+ coupon_code?: string;
176
+ discount?: number;
177
+ }
178
+ interface PurchaseParams {
179
+ transaction_id: string;
180
+ revenue: number;
181
+ currency: string;
182
+ items?: EcommerceItem[];
183
+ cart_id?: string;
184
+ coupon_code?: string;
185
+ discount?: number;
186
+ shipping?: number;
187
+ tax?: number;
188
+ }
189
+ interface AddToCartParams {
190
+ items: EcommerceItem[];
191
+ cart_id?: string;
192
+ }
193
+ interface RemoveFromCartParams {
194
+ items: EcommerceItem[];
195
+ cart_id?: string;
196
+ }
197
+ interface AddToWishlistParams {
198
+ items: EcommerceItem[];
199
+ }
200
+ interface BeginCheckoutParams {
201
+ revenue?: number;
202
+ currency?: string;
203
+ cart_id?: string;
204
+ items?: EcommerceItem[];
205
+ }
206
+ interface RefundParams {
207
+ transaction_id: string;
208
+ revenue: number;
209
+ currency?: string;
210
+ items?: EcommerceItem[];
211
+ }
212
+ interface ViewItemParams {
213
+ items: EcommerceItem[];
214
+ }
215
+ interface SearchParams {
216
+ search_term: string;
217
+ }
218
+ interface AddPaymentInfoParams {
219
+ cart_id?: string;
220
+ }
221
+ interface ShareParams {
222
+ item_id?: string;
223
+ url?: string;
224
+ method?: string;
225
+ }
226
+ interface RateParams {
227
+ item_id: string;
228
+ rating: number;
229
+ max_rating?: number;
230
+ }
231
+ interface SpendCreditsParams {
232
+ revenue: number;
233
+ currency: string;
234
+ }
163
235
 
164
236
  declare class HttpClient {
165
237
  private _baseUrl;
@@ -225,6 +297,38 @@ declare class Analytics {
225
297
  destroy(): void;
226
298
  }
227
299
 
300
+ declare class Ecommerce {
301
+ private client;
302
+ private queue;
303
+ private flushTimer;
304
+ private unloadHandler;
305
+ private getUserId;
306
+ private memoryCartId;
307
+ constructor(client: HttpClient, getUserId: () => string | null);
308
+ viewItem(params: ViewItemParams): Promise<void>;
309
+ addToCart(params: AddToCartParams): Promise<void>;
310
+ removeFromCart(params: RemoveFromCartParams): Promise<void>;
311
+ addToWishlist(params: AddToWishlistParams): Promise<void>;
312
+ viewCart(): Promise<void>;
313
+ addPaymentInfo(params?: AddPaymentInfoParams): Promise<void>;
314
+ beginCheckout(params: BeginCheckoutParams): Promise<void>;
315
+ purchase(params: PurchaseParams): Promise<void>;
316
+ refund(params: RefundParams): Promise<void>;
317
+ search(params: SearchParams): Promise<void>;
318
+ share(params: ShareParams): Promise<void>;
319
+ rate(params: RateParams): Promise<void>;
320
+ spendCredits(params: SpendCreditsParams): Promise<void>;
321
+ flush(): Promise<void>;
322
+ destroy(): void;
323
+ private enqueue;
324
+ private flushBeacon;
325
+ private getOrCreateCartId;
326
+ private getCartId;
327
+ private setCartId;
328
+ private clearCartId;
329
+ private generateId;
330
+ }
331
+
228
332
  declare class Referrals {
229
333
  private client;
230
334
  constructor(client: HttpClient);
@@ -261,6 +365,8 @@ declare class Tolinku {
261
365
  private client;
262
366
  /** Analytics: track custom events */
263
367
  readonly analytics: Analytics;
368
+ /** Ecommerce: track purchases, carts, products, revenue */
369
+ readonly ecommerce: Ecommerce;
264
370
  /** Referrals: create, complete, milestone, leaderboard */
265
371
  readonly referrals: Referrals;
266
372
  /** Deferred deep links: claim by token or signals */
@@ -289,10 +395,10 @@ declare class Tolinku {
289
395
  showMessage(options?: ShowMessageOptions): Promise<void>;
290
396
  /** Dismiss the currently visible in-app message */
291
397
  dismissMessage(): void;
292
- /** Flush any queued analytics events immediately */
398
+ /** Flush any queued analytics and ecommerce events immediately */
293
399
  flush(): Promise<void>;
294
400
  /** Clean up all DOM elements, flush events, and cancel in-flight requests (e.g. before unmounting in SPAs) */
295
401
  destroy(): void;
296
402
  }
297
403
 
298
- export { type BannerConfig, type BannerItem, 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 ShowBannerOptions, type ShowMessageOptions, Tolinku, type TolinkuConfig, TolinkuError, type TrackProperties };
404
+ export { type AddPaymentInfoParams, type AddToCartParams, type AddToWishlistParams, type BannerConfig, type BannerItem, 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 SearchParams, type ShareParams, type ShowBannerOptions, type ShowMessageOptions, type SpendCreditsParams, Tolinku, type TolinkuConfig, TolinkuError, type TrackProperties, type ViewItemParams };
package/dist/index.js CHANGED
@@ -277,6 +277,208 @@ var Analytics = class {
277
277
  }
278
278
  };
279
279
 
280
+ // src/ecommerce.ts
281
+ var BATCH_SIZE2 = 10;
282
+ var FLUSH_INTERVAL_MS2 = 5e3;
283
+ var MAX_QUEUE_SIZE2 = 500;
284
+ var CART_ID_KEY = "tolk_cart_id";
285
+ var Ecommerce = class {
286
+ // fallback when sessionStorage unavailable
287
+ constructor(client, getUserId) {
288
+ this.client = client;
289
+ this.queue = [];
290
+ this.flushTimer = null;
291
+ this.unloadHandler = null;
292
+ this.memoryCartId = null;
293
+ this.getUserId = getUserId;
294
+ if (typeof window !== "undefined") {
295
+ this.unloadHandler = () => this.flushBeacon();
296
+ window.addEventListener("beforeunload", this.unloadHandler);
297
+ }
298
+ }
299
+ // ─── Public methods (13 event types) ────────────────────
300
+ async viewItem(params) {
301
+ await this.enqueue({ event_type: "view_item", items: params.items });
302
+ }
303
+ async addToCart(params) {
304
+ const cartId = params.cart_id || this.getOrCreateCartId();
305
+ await this.enqueue({ event_type: "add_to_cart", items: params.items, cart_id: cartId });
306
+ }
307
+ async removeFromCart(params) {
308
+ await this.enqueue({ event_type: "remove_from_cart", items: params.items, cart_id: params.cart_id || this.getCartId() });
309
+ }
310
+ async addToWishlist(params) {
311
+ await this.enqueue({ event_type: "add_to_wishlist", items: params.items });
312
+ }
313
+ async viewCart() {
314
+ await this.enqueue({ event_type: "view_cart", cart_id: this.getCartId() });
315
+ }
316
+ async addPaymentInfo(params) {
317
+ await this.enqueue({ event_type: "add_payment_info", cart_id: params?.cart_id || this.getCartId() });
318
+ }
319
+ async beginCheckout(params) {
320
+ await this.enqueue({
321
+ event_type: "begin_checkout",
322
+ revenue: params.revenue,
323
+ currency: params.currency,
324
+ cart_id: params.cart_id || this.getCartId(),
325
+ items: params.items
326
+ });
327
+ }
328
+ async purchase(params) {
329
+ const cartId = params.cart_id || this.getCartId();
330
+ await this.enqueue({
331
+ event_type: "purchase",
332
+ transaction_id: params.transaction_id,
333
+ revenue: params.revenue,
334
+ currency: params.currency,
335
+ cart_id: cartId,
336
+ coupon_code: params.coupon_code,
337
+ discount: params.discount,
338
+ shipping: params.shipping,
339
+ tax: params.tax,
340
+ items: params.items
341
+ });
342
+ this.clearCartId();
343
+ }
344
+ async refund(params) {
345
+ await this.enqueue({
346
+ event_type: "refund",
347
+ transaction_id: params.transaction_id,
348
+ revenue: params.revenue,
349
+ currency: params.currency,
350
+ items: params.items
351
+ });
352
+ }
353
+ async search(params) {
354
+ await this.enqueue({ event_type: "search", properties: { search_term: params.search_term } });
355
+ }
356
+ async share(params) {
357
+ const props = {};
358
+ if (params.item_id) props.item_id = params.item_id;
359
+ if (params.url) props.url = params.url;
360
+ if (params.method) props.method = params.method;
361
+ await this.enqueue({ event_type: "share", properties: props });
362
+ }
363
+ async rate(params) {
364
+ await this.enqueue({
365
+ event_type: "rate",
366
+ properties: {
367
+ item_id: params.item_id,
368
+ rating: String(params.rating),
369
+ ...params.max_rating != null ? { max_rating: String(params.max_rating) } : {}
370
+ }
371
+ });
372
+ }
373
+ async spendCredits(params) {
374
+ await this.enqueue({ event_type: "spend_credits", revenue: params.revenue, currency: params.currency });
375
+ }
376
+ // ─── Flush ─────────────────────────────────────────────
377
+ async flush() {
378
+ if (this.flushTimer) {
379
+ clearTimeout(this.flushTimer);
380
+ this.flushTimer = null;
381
+ }
382
+ if (this.queue.length === 0) return;
383
+ const events = this.queue.splice(0);
384
+ try {
385
+ const result = await this.client.post(
386
+ "/v1/api/analytics/ecommerce/batch",
387
+ { events }
388
+ );
389
+ if (result.errors && result.errors.length > 0) {
390
+ console.warn("[TolinkuSDK] Ecommerce batch partial failure:", result.errors);
391
+ }
392
+ } catch {
393
+ this.queue.unshift(...events);
394
+ if (this.queue.length > MAX_QUEUE_SIZE2) {
395
+ this.queue.splice(0, this.queue.length - MAX_QUEUE_SIZE2);
396
+ }
397
+ }
398
+ }
399
+ destroy() {
400
+ this.flushBeacon();
401
+ if (this.flushTimer) {
402
+ clearTimeout(this.flushTimer);
403
+ this.flushTimer = null;
404
+ }
405
+ if (typeof window !== "undefined" && this.unloadHandler) {
406
+ window.removeEventListener("beforeunload", this.unloadHandler);
407
+ this.unloadHandler = null;
408
+ }
409
+ }
410
+ // ─── Private ───────────────────────────────────────────
411
+ async enqueue(event) {
412
+ const userId = this.getUserId();
413
+ if (userId) event.user_id = userId;
414
+ this.queue.push(event);
415
+ if (this.queue.length === 1 && !this.flushTimer) {
416
+ this.flushTimer = setTimeout(() => {
417
+ this.flushTimer = null;
418
+ this.flush();
419
+ }, FLUSH_INTERVAL_MS2);
420
+ }
421
+ if (this.queue.length >= BATCH_SIZE2) {
422
+ await this.flush();
423
+ }
424
+ }
425
+ flushBeacon() {
426
+ if (this.queue.length === 0) return;
427
+ const events = this.queue.splice(0);
428
+ const url = this.client.baseUrl + "/v1/api/analytics/ecommerce/batch";
429
+ const body = JSON.stringify({ events, apiKey: this.client.key });
430
+ if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
431
+ navigator.sendBeacon(url, new Blob([body], { type: "application/json" }));
432
+ }
433
+ }
434
+ // ─── Cart ID lifecycle ─────────────────────────────────
435
+ getOrCreateCartId() {
436
+ const existing = this.getCartId();
437
+ if (existing) return existing;
438
+ const cartId = this.generateId();
439
+ this.setCartId(cartId);
440
+ return cartId;
441
+ }
442
+ getCartId() {
443
+ try {
444
+ if (typeof sessionStorage !== "undefined") {
445
+ const stored = sessionStorage.getItem(CART_ID_KEY);
446
+ if (stored) return stored;
447
+ }
448
+ } catch {
449
+ }
450
+ return this.memoryCartId || void 0;
451
+ }
452
+ setCartId(cartId) {
453
+ this.memoryCartId = cartId;
454
+ try {
455
+ if (typeof sessionStorage !== "undefined") {
456
+ sessionStorage.setItem(CART_ID_KEY, cartId);
457
+ }
458
+ } catch {
459
+ }
460
+ }
461
+ clearCartId() {
462
+ this.memoryCartId = null;
463
+ try {
464
+ if (typeof sessionStorage !== "undefined") {
465
+ sessionStorage.removeItem(CART_ID_KEY);
466
+ }
467
+ } catch {
468
+ }
469
+ }
470
+ generateId() {
471
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
472
+ return crypto.randomUUID();
473
+ }
474
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
475
+ const r = Math.random() * 16 | 0;
476
+ const v = c === "x" ? r : r & 3 | 8;
477
+ return v.toString(16);
478
+ });
479
+ }
480
+ };
481
+
280
482
  // src/referrals.ts
281
483
  var Referrals = class {
282
484
  constructor(client) {
@@ -857,6 +1059,7 @@ var Tolinku = class {
857
1059
  }
858
1060
  this.client = new HttpClient(resolvedConfig);
859
1061
  this.analytics = new Analytics(this.client);
1062
+ this.ecommerce = new Ecommerce(this.client, () => this._userId);
860
1063
  this.referrals = new Referrals(this.client);
861
1064
  this.deferred = new Deferred(this.client);
862
1065
  this.banners = new Banners(this.client);
@@ -894,13 +1097,14 @@ var Tolinku = class {
894
1097
  dismissMessage() {
895
1098
  this.messages.dismiss();
896
1099
  }
897
- /** Flush any queued analytics events immediately */
1100
+ /** Flush any queued analytics and ecommerce events immediately */
898
1101
  async flush() {
899
- return this.analytics.flush();
1102
+ await Promise.all([this.analytics.flush(), this.ecommerce.flush()]);
900
1103
  }
901
1104
  /** Clean up all DOM elements, flush events, and cancel in-flight requests (e.g. before unmounting in SPAs) */
902
1105
  destroy() {
903
1106
  this.analytics.destroy();
1107
+ this.ecommerce.destroy();
904
1108
  this.client.abort();
905
1109
  this.banners.dismiss();
906
1110
  this.messages.dismiss();