@chordcommerce/analytics 1.19.0 → 1.21.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,4 @@
1
- import type { AnyAnalytics, EventProperties, Options, ValidateResult, ChordAnalyticsOptions, AnyOptions, CartViewedInput, IdentifyTraits, CheckoutStartedInput, CheckoutStepCompletedInput, CheckoutStepViewedInput, EmailCapturedInput, ProductListViewedInput, ProductListFilteredInput, ProductAddedInput, ProductClickedInput, VariantClickedInput, ProductRemovedInput, ProductViewedInput, ProductsSearchedInput, CouponAppliedInput, CouponDeniedInput, CouponEnteredInput, CouponRemovedInput, SignedInInput, SignedOutInput, SignedUpInput, LoginStartedInput, ObjectTypes, SubscriptionCancelledInput, NavigationClickedInput, PaymentInfoEnteredInput } from '../types/index.js';
1
+ import type { AnyAnalytics, EventProperties, Options, ValidateResult, ChordAnalyticsOptions, AnyOptions, CartViewedInput, IdentifyTraits, CheckoutStartedInput, CheckoutStepCompletedInput, CheckoutStepViewedInput, EmailCapturedInput, ProductListViewedInput, ProductListFilteredInput, ProductAddedInput, ProductClickedInput, VariantClickedInput, ProductRemovedInput, ProductViewedInput, ProductsSearchedInput, CouponAppliedInput, CouponDeniedInput, CouponEnteredInput, CouponRemovedInput, SignedInInput, SignedOutInput, SignedUpInput, LoginStartedInput, ObjectTypes, OrderCompletedInput, SubscriptionCancelledInput, NavigationClickedInput, PaymentInfoEnteredInput } from '../types/index.js';
2
2
  import { AnalyticsMiddleware } from '../types/client.js';
3
3
  export interface ChordAnalyticsSnippet {
4
4
  _loadOptions: ChordAnalyticsOptions<ObjectTypes>;
@@ -45,6 +45,20 @@ export declare class ChordAnalytics<T extends ObjectTypes = ObjectTypes> {
45
45
  */
46
46
  private consentReadyPromise;
47
47
  constructor(options: ChordAnalyticsOptions<T>);
48
+ /**
49
+ * Persist the consent event queue to sessionStorage for recovery on instance recreation.
50
+ * Validates queue size before storing to prevent QuotaExceededError.
51
+ */
52
+ private persistQueueToStorage;
53
+ /**
54
+ * Restore pending events from sessionStorage (keeps events less than 5 min old).
55
+ * Called on new instance initialization.
56
+ */
57
+ private restoreQueueFromStorage;
58
+ /**
59
+ * Clear the persisted queue from sessionStorage after successful flush.
60
+ */
61
+ private clearQueueFromStorage;
48
62
  /**
49
63
  * Initialize CDP snippet and wait for it to be ready.
50
64
  * Fires initial consent track event after CDP is fully initialized to avoid circular await.
@@ -66,6 +80,7 @@ export declare class ChordAnalytics<T extends ObjectTypes = ObjectTypes> {
66
80
  private waitForConsent;
67
81
  /**
68
82
  * Queue an event to be sent when consent is ready.
83
+ * Persists to sessionStorage for recovery on instance recreation.
69
84
  * Starts a consent watcher if not already active.
70
85
  */
71
86
  private queueEventForConsent;
@@ -75,6 +90,7 @@ export declare class ChordAnalytics<T extends ObjectTypes = ObjectTypes> {
75
90
  private watchForConsentAndFlush;
76
91
  /**
77
92
  * Flush all queued events now that consent is ready.
93
+ * Clears sessionStorage after successful flush.
78
94
  */
79
95
  private flushConsentQueue;
80
96
  /**
@@ -159,4 +175,5 @@ export declare class ChordAnalytics<T extends ObjectTypes = ObjectTypes> {
159
175
  trackSubscriptionCancelled: (props: SubscriptionCancelledInput, options?: AnyOptions) => Promise<void>;
160
176
  trackNavigationClicked: (props: NavigationClickedInput, options?: AnyOptions) => Promise<void>;
161
177
  trackPaymentInfoEntered: (props: PaymentInfoEnteredInput, options?: AnyOptions) => Promise<void>;
178
+ trackOrderCompleted: (props: OrderCompletedInput, options?: AnyOptions) => Promise<void>;
162
179
  }
@@ -62,6 +62,10 @@ var index_js_1 = require("./consent/index.js");
62
62
  var index_js_2 = require("../validators/index.js");
63
63
  var utils_js_1 = require("../utils.js");
64
64
  var DEBUG_MODE_STORAGE_KEY = 'chordcommerce/analytics/debug';
65
+ var CONSENT_QUEUE_STORAGE_KEY = 'chordcommerce/analytics/consent-queue';
66
+ var CONSENT_QUEUE_TTL_MS = 5 * 60 * 1000; // 5 minutes
67
+ var CONSENT_QUEUE_MAX_SIZE_BYTES = 100 * 1024; // 100KB max queue size
68
+ var CONSENT_QUEUE_MAX_EVENTS = 50; // Max number of events to queue
65
69
  var ChordAnalytics = /** @class */ (function () {
66
70
  function ChordAnalytics(options) {
67
71
  var _this = this;
@@ -96,6 +100,123 @@ var ChordAnalytics = /** @class */ (function () {
96
100
  * Promise that resolves when consent is ready (shared across all queued events)
97
101
  */
98
102
  this.consentReadyPromise = null;
103
+ /**
104
+ * Persist the consent event queue to sessionStorage for recovery on instance recreation.
105
+ * Validates queue size before storing to prevent QuotaExceededError.
106
+ */
107
+ this.persistQueueToStorage = function () {
108
+ if (typeof window === 'undefined' || !window.sessionStorage)
109
+ return;
110
+ try {
111
+ // Limit number of events to prevent unbounded queue growth
112
+ var eventsToStore = _this.consentEventQueue.slice(-CONSENT_QUEUE_MAX_EVENTS);
113
+ var persistedEvents = eventsToStore.map(function (item) { return ({
114
+ type: item.type,
115
+ args: item.args,
116
+ timestamp: item.timestamp,
117
+ }); });
118
+ var serialized = JSON.stringify(persistedEvents);
119
+ // Check serialized size before attempting to store
120
+ var sizeInBytes = new Blob([serialized]).size;
121
+ if (sizeInBytes > CONSENT_QUEUE_MAX_SIZE_BYTES) {
122
+ _this.logger("[Chord Analytics]: Consent queue too large (".concat(Math.round(sizeInBytes / 1024), "KB), skipping persistence"));
123
+ return;
124
+ }
125
+ window.sessionStorage.setItem(CONSENT_QUEUE_STORAGE_KEY, serialized);
126
+ }
127
+ catch (error) {
128
+ _this.logger('[Chord Analytics]: Error persisting queue to storage:', error);
129
+ }
130
+ };
131
+ /**
132
+ * Restore pending events from sessionStorage (keeps events less than 5 min old).
133
+ * Called on new instance initialization.
134
+ */
135
+ this.restoreQueueFromStorage = function () {
136
+ if (typeof window === 'undefined' || !window.sessionStorage)
137
+ return;
138
+ try {
139
+ var stored = window.sessionStorage.getItem(CONSENT_QUEUE_STORAGE_KEY);
140
+ if (!stored)
141
+ return;
142
+ var persistedEvents = void 0;
143
+ try {
144
+ persistedEvents = JSON.parse(stored);
145
+ }
146
+ catch (parseError) {
147
+ _this.logger('[Chord Analytics]: Invalid JSON in stored consent queue, clearing storage:', parseError);
148
+ window.sessionStorage.removeItem(CONSENT_QUEUE_STORAGE_KEY);
149
+ return;
150
+ }
151
+ // Validate that parsed data is an array
152
+ if (!Array.isArray(persistedEvents)) {
153
+ _this.logger('[Chord Analytics]: Stored consent queue is not an array, clearing storage');
154
+ window.sessionStorage.removeItem(CONSENT_QUEUE_STORAGE_KEY);
155
+ return;
156
+ }
157
+ var now_1 = Date.now();
158
+ // Filter out expired events and events with invalid structure
159
+ var validEvents = persistedEvents.filter(function (event) {
160
+ // Validate event structure
161
+ if (typeof event !== 'object' || event === null)
162
+ return false;
163
+ if (!['track', 'page', 'identify'].includes(event.type))
164
+ return false;
165
+ if (!Array.isArray(event.args))
166
+ return false;
167
+ if (typeof event.timestamp !== 'number')
168
+ return false;
169
+ // Filter out expired events
170
+ return now_1 - event.timestamp < CONSENT_QUEUE_TTL_MS;
171
+ });
172
+ if (validEvents.length === 0) {
173
+ window.sessionStorage.removeItem(CONSENT_QUEUE_STORAGE_KEY);
174
+ return;
175
+ }
176
+ if (_this.options.enableLogging && _this.options.debug) {
177
+ // eslint-disable-next-line no-console
178
+ console.log("[Chord Analytics DEBUG]: Restoring ".concat(validEvents.length, " events from sessionStorage"));
179
+ }
180
+ // Add restored events to the queue
181
+ validEvents.forEach(function (event) {
182
+ _this.consentEventQueue.push({
183
+ type: event.type,
184
+ args: event.args,
185
+ timestamp: event.timestamp,
186
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
187
+ resolve: function () { },
188
+ });
189
+ });
190
+ // Start watching for consent if we restored events
191
+ if (validEvents.length > 0 && !_this.consentWatcherActive) {
192
+ _this.consentWatcherActive = true;
193
+ _this.watchForConsentAndFlush();
194
+ }
195
+ }
196
+ catch (error) {
197
+ _this.logger('[Chord Analytics]: Error restoring queue from storage:', error);
198
+ // Clear corrupted storage
199
+ try {
200
+ window.sessionStorage.removeItem(CONSENT_QUEUE_STORAGE_KEY);
201
+ }
202
+ catch (_a) {
203
+ // Ignore cleanup errors
204
+ }
205
+ }
206
+ };
207
+ /**
208
+ * Clear the persisted queue from sessionStorage after successful flush.
209
+ */
210
+ this.clearQueueFromStorage = function () {
211
+ if (typeof window === 'undefined' || !window.sessionStorage)
212
+ return;
213
+ try {
214
+ window.sessionStorage.removeItem(CONSENT_QUEUE_STORAGE_KEY);
215
+ }
216
+ catch (error) {
217
+ _this.logger('[Chord Analytics]: Error clearing queue from storage:', error);
218
+ }
219
+ };
99
220
  /**
100
221
  * Set debug mode for Chord Analytics
101
222
  * @param enabled - Whether debug mode should be enabled
@@ -180,11 +301,19 @@ var ChordAnalytics = /** @class */ (function () {
180
301
  }); };
181
302
  /**
182
303
  * Queue an event to be sent when consent is ready.
304
+ * Persists to sessionStorage for recovery on instance recreation.
183
305
  * Starts a consent watcher if not already active.
184
306
  */
185
307
  this.queueEventForConsent = function (type, args) {
186
308
  return new Promise(function (resolve) {
187
- _this.consentEventQueue.push({ type: type, args: args, resolve: resolve });
309
+ _this.consentEventQueue.push({
310
+ type: type,
311
+ args: args,
312
+ timestamp: Date.now(),
313
+ resolve: resolve,
314
+ });
315
+ // Persist queue to sessionStorage for recovery on instance recreation
316
+ _this.persistQueueToStorage();
188
317
  // Start watching for consent if not already
189
318
  if (!_this.consentWatcherActive) {
190
319
  _this.consentWatcherActive = true;
@@ -211,6 +340,7 @@ var ChordAnalytics = /** @class */ (function () {
211
340
  }); };
212
341
  /**
213
342
  * Flush all queued events now that consent is ready.
343
+ * Clears sessionStorage after successful flush.
214
344
  */
215
345
  this.flushConsentQueue = function () { return __awaiter(_this, void 0, void 0, function () {
216
346
  var queue, sendPromises;
@@ -220,6 +350,12 @@ var ChordAnalytics = /** @class */ (function () {
220
350
  case 0:
221
351
  queue = __spreadArray([], this.consentEventQueue, true);
222
352
  this.consentEventQueue = [];
353
+ // Clear persisted queue from storage since we're processing them now
354
+ this.clearQueueFromStorage();
355
+ if (this.options.enableLogging && this.options.debug) {
356
+ // eslint-disable-next-line no-console
357
+ console.log("[Chord Analytics DEBUG]: Flushing ".concat(queue.length, " queued events"));
358
+ }
223
359
  sendPromises = queue.map(function (item) { return __awaiter(_this, void 0, void 0, function () {
224
360
  var _a, error_1;
225
361
  return __generator(this, function (_b) {
@@ -425,12 +561,7 @@ var ChordAnalytics = /** @class */ (function () {
425
561
  }));
426
562
  }
427
563
  if (cdpPromises.length > 0) {
428
- Promise.allSettled(cdpPromises)
429
- .then(function () { return resolve(); })
430
- .catch(function (error) {
431
- _this.logger(error);
432
- resolve();
433
- });
564
+ Promise.allSettled(cdpPromises).then(function () { return resolve(); });
434
565
  }
435
566
  else {
436
567
  resolve();
@@ -564,34 +695,50 @@ var ChordAnalytics = /** @class */ (function () {
564
695
  this.sendPageEvent = function (options, props) {
565
696
  if (props === void 0) { props = {}; }
566
697
  return __awaiter(_this, void 0, void 0, function () {
567
- var pagePromises, a_3, b_3;
568
698
  var _this = this;
569
699
  return __generator(this, function (_a) {
570
- // Configure CDP with fresh consent before sending
571
- this.configureConsentOnCdp();
572
- try {
573
- pagePromises = [];
574
- a_3 = this.ccdp();
575
- if (a_3 && typeof a_3.page === 'function') {
576
- pagePromises.push(new Promise(function (resolve) {
577
- a_3.page(__assign(__assign({}, props), { meta: _this.meta() }), options, function () { return resolve(); });
578
- }));
579
- }
580
- b_3 = this.cdp();
581
- if (b_3 && typeof b_3.page === 'function') {
582
- pagePromises.push(new Promise(function (resolve) {
583
- b_3.page(__assign(__assign({}, props), { meta: _this.meta() }), options, function () { return resolve(); });
584
- }));
585
- }
586
- // We don't return the promise to maintain the void return type
587
- Promise.allSettled(pagePromises).then(function (results) {
588
- _this.logger('page event sent', results);
589
- });
590
- }
591
- catch (error) {
592
- this.logger(error);
700
+ switch (_a.label) {
701
+ case 0:
702
+ // Configure CDP with fresh consent before sending
703
+ this.configureConsentOnCdp();
704
+ return [4 /*yield*/, new Promise(function (resolve) {
705
+ var pagePromises = [];
706
+ try {
707
+ var a_3 = _this.ccdp();
708
+ if (a_3 && typeof a_3.page === 'function') {
709
+ pagePromises.push(new Promise(function (cdpResolve) {
710
+ a_3.page(__assign(__assign({}, props), { meta: _this.meta() }), options, function () {
711
+ return cdpResolve();
712
+ });
713
+ }));
714
+ }
715
+ var b_3 = _this.cdp();
716
+ if (b_3 && typeof b_3.page === 'function') {
717
+ pagePromises.push(new Promise(function (cdpResolve) {
718
+ b_3.page(__assign(__assign({}, props), { meta: _this.meta() }), options, function () {
719
+ return cdpResolve();
720
+ });
721
+ }));
722
+ }
723
+ if (pagePromises.length > 0) {
724
+ Promise.allSettled(pagePromises).then(function (results) {
725
+ _this.logger('page event sent', results);
726
+ resolve();
727
+ });
728
+ }
729
+ else {
730
+ resolve();
731
+ }
732
+ }
733
+ catch (error) {
734
+ _this.logger(error);
735
+ resolve();
736
+ }
737
+ })];
738
+ case 1:
739
+ _a.sent();
740
+ return [2 /*return*/];
593
741
  }
594
- return [2 /*return*/];
595
742
  });
596
743
  });
597
744
  };
@@ -1101,6 +1248,85 @@ var ChordAnalytics = /** @class */ (function () {
1101
1248
  return [2 /*return*/, this.track('Payment Info Entered', payload, options)];
1102
1249
  });
1103
1250
  }); };
1251
+ this.trackOrderCompleted = function (props, options) { return __awaiter(_this, void 0, void 0, function () {
1252
+ var formatter, payload, formattedPayload;
1253
+ var _a, _b, _c, _d;
1254
+ return __generator(this, function (_e) {
1255
+ formatter = (_c = (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.formatters) === null || _b === void 0 ? void 0 : _b.events) === null || _c === void 0 ? void 0 : _c.orderCompleted;
1256
+ payload = {
1257
+ affiliation: props === null || props === void 0 ? void 0 : props.affiliation,
1258
+ campaign_id: props === null || props === void 0 ? void 0 : props.campaignId,
1259
+ category: props === null || props === void 0 ? void 0 : props.category,
1260
+ channel: props === null || props === void 0 ? void 0 : props.channel,
1261
+ checkout_id: props === null || props === void 0 ? void 0 : props.checkoutId,
1262
+ checkout_type: props === null || props === void 0 ? void 0 : props.checkoutType,
1263
+ coupon: props === null || props === void 0 ? void 0 : props.coupon,
1264
+ currency: props === null || props === void 0 ? void 0 : props.currency,
1265
+ discount: props === null || props === void 0 ? void 0 : props.discount,
1266
+ email: props === null || props === void 0 ? void 0 : props.email,
1267
+ first_name: props === null || props === void 0 ? void 0 : props.firstName,
1268
+ has_subscription: props === null || props === void 0 ? void 0 : props.hasSubscription,
1269
+ is_recurring: props === null || props === void 0 ? void 0 : props.isRecurring,
1270
+ last_name: props === null || props === void 0 ? void 0 : props.lastName,
1271
+ metadata: props === null || props === void 0 ? void 0 : props.metadata,
1272
+ order_date: props === null || props === void 0 ? void 0 : props.orderDate,
1273
+ order_id: props === null || props === void 0 ? void 0 : props.orderId,
1274
+ phone: props === null || props === void 0 ? void 0 : props.phone,
1275
+ products: (_d = props === null || props === void 0 ? void 0 : props.products) === null || _d === void 0 ? void 0 : _d.map(function (p, i) {
1276
+ var _a;
1277
+ return ({
1278
+ affiliation: p === null || p === void 0 ? void 0 : p.affiliation,
1279
+ brand: p === null || p === void 0 ? void 0 : p.brand,
1280
+ bundle: p === null || p === void 0 ? void 0 : p.bundle,
1281
+ bundle_size: p === null || p === void 0 ? void 0 : p.bundleSize,
1282
+ category: p === null || p === void 0 ? void 0 : p.category,
1283
+ coupon: p === null || p === void 0 ? void 0 : p.coupon,
1284
+ cross_sold_quantity: p === null || p === void 0 ? void 0 : p.crossSoldQuantity,
1285
+ description: p === null || p === void 0 ? void 0 : p.description,
1286
+ image_url: p === null || p === void 0 ? void 0 : p.imageUrl,
1287
+ line_item_id: p === null || p === void 0 ? void 0 : p.lineItemId,
1288
+ name: p === null || p === void 0 ? void 0 : p.name,
1289
+ option_values: p === null || p === void 0 ? void 0 : p.optionValues,
1290
+ position: (_a = p === null || p === void 0 ? void 0 : p.position) !== null && _a !== void 0 ? _a : i + 1,
1291
+ price: p === null || p === void 0 ? void 0 : p.price,
1292
+ product_id: p === null || p === void 0 ? void 0 : p.productId,
1293
+ quantity: p === null || p === void 0 ? void 0 : p.quantity,
1294
+ revenue: p === null || p === void 0 ? void 0 : p.revenue,
1295
+ sku: p === null || p === void 0 ? void 0 : p.sku,
1296
+ slug: p === null || p === void 0 ? void 0 : p.slug,
1297
+ url: p === null || p === void 0 ? void 0 : p.url,
1298
+ variant: p === null || p === void 0 ? void 0 : p.variant,
1299
+ variant_metadata: p === null || p === void 0 ? void 0 : p.variantMetadata,
1300
+ });
1301
+ }),
1302
+ purl_link: props === null || props === void 0 ? void 0 : props.purlLink,
1303
+ referral_identifier_id: props === null || props === void 0 ? void 0 : props.referralIdentifierId,
1304
+ repeat: props === null || props === void 0 ? void 0 : props.repeat,
1305
+ revenue: props === null || props === void 0 ? void 0 : props.revenue,
1306
+ shipping: props === null || props === void 0 ? void 0 : props.shipping,
1307
+ shipping_city: props === null || props === void 0 ? void 0 : props.shippingCity,
1308
+ shipping_country: props === null || props === void 0 ? void 0 : props.shippingCountry,
1309
+ shipping_method_details: (props === null || props === void 0 ? void 0 : props.shippingMethodDetails)
1310
+ ? {
1311
+ shipping_code: props.shippingMethodDetails.shippingCode,
1312
+ shipping_method: props.shippingMethodDetails.shippingMethod,
1313
+ }
1314
+ : undefined,
1315
+ shipping_state: props === null || props === void 0 ? void 0 : props.shippingState,
1316
+ shipping_zipcode: props === null || props === void 0 ? void 0 : props.shippingZipcode,
1317
+ subtotal: props === null || props === void 0 ? void 0 : props.subtotal,
1318
+ tax: props === null || props === void 0 ? void 0 : props.tax,
1319
+ template_id: props === null || props === void 0 ? void 0 : props.templateId,
1320
+ total: props === null || props === void 0 ? void 0 : props.total,
1321
+ tracking_ids: props === null || props === void 0 ? void 0 : props.trackingIds,
1322
+ };
1323
+ if (typeof formatter === 'function') {
1324
+ formattedPayload = formatter(props, payload);
1325
+ return [2 /*return*/, this.track('Order Completed', formattedPayload, options)];
1326
+ }
1327
+ return [2 /*return*/, this.track('Order Completed', payload, options)];
1328
+ });
1329
+ }); };
1104
1330
  var debug = ((_a = window === null || window === void 0 ? void 0 : window.localStorage) === null || _a === void 0 ? void 0 : _a.getItem(DEBUG_MODE_STORAGE_KEY)) === 'true';
1105
1331
  var defaults = {
1106
1332
  debug: debug,
@@ -1113,6 +1339,8 @@ var ChordAnalytics = /** @class */ (function () {
1113
1339
  var consentManager = (0, index_js_1.addCdpConsent)(this.options);
1114
1340
  this.consentConfig = consentManager.getConsentConfig() || null;
1115
1341
  }
1342
+ // Restore any pending events from sessionStorage (survives instance recreation)
1343
+ this.restoreQueueFromStorage();
1116
1344
  if (((_b = this.options) === null || _b === void 0 ? void 0 : _b.cdpDomain) && ((_c = this.options) === null || _c === void 0 ? void 0 : _c.cdpWriteKey) && window) {
1117
1345
  window[this.options.namespace] = (window === null || window === void 0 ? void 0 : window[this.options.namespace]) || this;
1118
1346
  this.initializeCdp();
@@ -4,3 +4,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  var globals_1 = require("@jest/globals");
5
5
  // Make jest available globally
6
6
  globalThis.jest = globals_1.jest;
7
+ // Mock sessionStorage for tests
8
+ var sessionStorageMock = (function () {
9
+ var store = {};
10
+ return {
11
+ getItem: function (key) { return store[key] || null; },
12
+ setItem: function (key, value) {
13
+ store[key] = value;
14
+ },
15
+ removeItem: function (key) {
16
+ delete store[key];
17
+ },
18
+ clear: function () {
19
+ store = {};
20
+ },
21
+ };
22
+ })();
23
+ Object.defineProperty(window, 'sessionStorage', {
24
+ value: sessionStorageMock,
25
+ });
26
+ // Clear sessionStorage before each test to ensure test isolation
27
+ beforeEach(function () {
28
+ sessionStorageMock.clear();
29
+ });
@@ -1,6 +1,6 @@
1
- import type { CartViewed, CheckoutStarted, CheckoutStepCompleted, CheckoutStepViewed, ProductAdded, ProductClicked, VariantClicked, ProductViewed, ProductListViewed, CouponApplied, CouponDenied, CouponEntered, CouponRemoved, EmailCaptured, ProductListFiltered, ProductRemoved, ProductsSearched, SignedIn, SignedOut, SignedUp, LoginStarted, SubscriptionCancelled, NavigationClicked, PaymentInfoEntered } from './typewriter.js';
1
+ import type { CartViewed, CheckoutStarted, CheckoutStepCompleted, CheckoutStepViewed, ProductAdded, ProductClicked, VariantClicked, ProductViewed, ProductListViewed, CouponApplied, CouponDenied, CouponEntered, CouponRemoved, EmailCaptured, ProductListFiltered, ProductRemoved, ProductsSearched, SignedIn, SignedOut, SignedUp, LoginStarted, OrderCompleted, SubscriptionCancelled, NavigationClicked, PaymentInfoEntered } from './typewriter.js';
2
2
  import type { Cart, Checkout, LineItem, Product } from './objects.js';
3
- import type { CartInput, CheckoutInput, CheckoutStepCompletedInput, CheckoutStepViewedInput, LineItemInput, ProductInput, CartViewedInput, CheckoutStartedInput, ProductAddedInput, ProductClickedInput, VariantClickedInput, ProductViewedInput, ProductListViewedInput, ProductListFilteredInput, ProductRemovedInput, CouponAppliedInput, CouponDeniedInput, CouponEnteredInput, CouponRemovedInput, EmailCapturedInput, ProductsSearchedInput, SignedInInput, SignedOutInput, SignedUpInput, LoginStartedInput, SubscriptionCancelledInput, NavigationClickedInput, PaymentInfoEnteredInput } from './input.js';
3
+ import type { CartInput, CheckoutInput, CheckoutStepCompletedInput, CheckoutStepViewedInput, LineItemInput, ProductInput, CartViewedInput, CheckoutStartedInput, ProductAddedInput, ProductClickedInput, VariantClickedInput, ProductViewedInput, ProductListViewedInput, ProductListFilteredInput, ProductRemovedInput, CouponAppliedInput, CouponDeniedInput, CouponEnteredInput, CouponRemovedInput, EmailCapturedInput, ProductsSearchedInput, SignedInInput, SignedOutInput, SignedUpInput, LoginStartedInput, OrderCompletedInput, SubscriptionCancelledInput, NavigationClickedInput, PaymentInfoEnteredInput } from './input.js';
4
4
  import type { ObjectTypes } from './client.js';
5
5
  export type CartFormatter<T = ObjectTypes['Cart']> = (props: CartInput<T>) => Cart;
6
6
  export type CheckoutFormatter<T = ObjectTypes['Checkout']> = (props: CheckoutInput<T>) => Checkout;
@@ -78,6 +78,9 @@ export interface NavigationClickedFormatter {
78
78
  export interface PaymentInfoEnteredFormatter {
79
79
  (props: PaymentInfoEnteredInput, event: PaymentInfoEntered): PaymentInfoEntered;
80
80
  }
81
+ export interface OrderCompletedFormatter {
82
+ (props: OrderCompletedInput, event: OrderCompleted): OrderCompleted;
83
+ }
81
84
  export interface ChordAnalyticsFormatters<T extends ObjectTypes = ObjectTypes> {
82
85
  events?: {
83
86
  cartViewed?: CartViewedFormatter<T>;
@@ -104,6 +107,7 @@ export interface ChordAnalyticsFormatters<T extends ObjectTypes = ObjectTypes> {
104
107
  subscriptionCancelled?: SubscriptionCancelledFormatter;
105
108
  navigationClicked?: NavigationClickedFormatter;
106
109
  paymentInfoEntered?: PaymentInfoEnteredFormatter;
110
+ orderCompleted?: OrderCompletedFormatter;
107
111
  };
108
112
  objects: {
109
113
  cart: CartFormatter<T['Cart']>;