@searchspring/snap-tracker 0.63.5 → 0.65.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,19 @@
1
1
  "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
2
17
  var __assign = (this && this.__assign) || function () {
3
18
  __assign = Object.assign || function(t) {
4
19
  for (var s, i = 1, n = arguments.length; i < n; i++) {
@@ -10,220 +25,98 @@ var __assign = (this && this.__assign) || function () {
10
25
  };
11
26
  return __assign.apply(this, arguments);
12
27
  };
13
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
14
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
15
- if (ar || !(i in from)) {
16
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
17
- ar[i] = from[i];
18
- }
19
- }
20
- return to.concat(ar || Array.prototype.slice.call(from));
21
- };
22
28
  var __importDefault = (this && this.__importDefault) || function (mod) {
23
29
  return (mod && mod.__esModule) ? mod : { "default": mod };
24
30
  };
25
31
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.Tracker = exports.MAX_VIEWED_COUNT = exports.BATCH_TIMEOUT = void 0;
32
+ exports.Tracker = void 0;
27
33
  var deepmerge_1 = __importDefault(require("deepmerge"));
28
- var uuid_1 = require("uuid");
29
34
  var snap_store_mobx_1 = require("@searchspring/snap-store-mobx");
30
35
  var snap_toolbox_1 = require("@searchspring/snap-toolbox");
31
36
  var snap_toolbox_2 = require("@searchspring/snap-toolbox");
32
- var TrackEvent_1 = require("./TrackEvent");
33
- var PixelEvent_1 = require("./PixelEvent");
37
+ var beacon_1 = require("@searchspring/beacon");
34
38
  var BeaconEvent_1 = require("./BeaconEvent");
35
39
  var types_1 = require("./types");
36
- exports.BATCH_TIMEOUT = 200;
37
- var LEGACY_USERID_COOKIE_NAME = '_isuid';
38
- var USERID_COOKIE_NAME = 'ssUserId';
39
- var SHOPPERID_COOKIE_NAME = 'ssShopperId';
40
- var COOKIE_EXPIRATION = 31536000000; // 1 year
41
- var VIEWED_COOKIE_EXPIRATION = 220752000000; // 7 years
42
- var COOKIE_SAMESITE = 'Lax';
43
- var COOKIE_DOMAIN = (typeof window !== 'undefined' && window.location.hostname && '.' + window.location.hostname.replace(/^www\./, '')) || undefined;
44
- var SESSIONID_STORAGE_NAME = 'ssSessionIdNamespace';
45
- var LOCALSTORAGE_BEACON_POOL_NAME = 'ssBeaconPool';
46
- var CART_PRODUCTS = 'ssCartProducts';
47
- var VIEWED_PRODUCTS = 'ssViewedProducts';
48
- exports.MAX_VIEWED_COUNT = 20;
49
40
  var MAX_PARENT_LEVELS = 3;
50
41
  var defaultConfig = {
51
42
  id: 'track',
52
43
  framework: 'snap',
53
44
  mode: snap_toolbox_2.AppMode.production,
54
45
  };
55
- var Tracker = /** @class */ (function () {
46
+ var Tracker = /** @class */ (function (_super) {
47
+ __extends(Tracker, _super);
56
48
  function Tracker(globals, config) {
57
49
  var _this = this;
58
- var _a, _b;
59
- this.mode = snap_toolbox_2.AppMode.production;
60
- this.targeters = [];
61
- this.track = {
62
- event: function (payload) {
63
- var event = {
64
- type: (payload === null || payload === void 0 ? void 0 : payload.type) || types_1.BeaconType.CUSTOM,
65
- category: (payload === null || payload === void 0 ? void 0 : payload.category) || types_1.BeaconCategory.CUSTOM,
66
- context: (payload === null || payload === void 0 ? void 0 : payload.context) ? (0, deepmerge_1.default)(_this.context, payload.context) : _this.context,
67
- event: payload.event,
68
- pid: (payload === null || payload === void 0 ? void 0 : payload.pid) || undefined,
69
- };
70
- var doNotTrack = _this.doNotTrack.find(function (entry) { return entry.type === event.type && entry.category === event.category; });
71
- if (doNotTrack) {
72
- return;
73
- }
74
- var beaconEvent = new BeaconEvent_1.BeaconEvent(event, _this.config);
75
- _this.sendEvents([beaconEvent]);
76
- return beaconEvent;
77
- },
50
+ var _a;
51
+ config = (0, deepmerge_1.default)(defaultConfig, config || {});
52
+ config.initiator = "searchspring/".concat(config.framework, "/").concat(snap_toolbox_1.version);
53
+ _this = _super.call(this, globals, config) || this;
54
+ _this.targeters = [];
55
+ _this.track = {
56
+ // TODO: search where this is used and remove unwanted fields from type
78
57
  error: function (data, siteId) {
79
58
  var _a;
59
+ if (((_a = _this.doNotTrack) === null || _a === void 0 ? void 0 : _a.includes('error')) || _this.mode === snap_toolbox_2.AppMode.development) {
60
+ return;
61
+ }
80
62
  if (!(data === null || data === void 0 ? void 0 : data.stack) && !(data === null || data === void 0 ? void 0 : data.message)) {
81
63
  // no console log
82
64
  return;
83
65
  }
84
- var context = _this.context;
85
- if (siteId) {
86
- context = (0, deepmerge_1.default)(context, {
87
- context: {
88
- website: {
89
- trackingCode: siteId,
90
- },
91
- },
92
- });
66
+ var stack = data.stack, message = data.message, details = data.details;
67
+ var pageUrl = _this.getContext().pageUrl;
68
+ // prevent sending of errors when on localhost or CDN
69
+ if ((message === null || message === void 0 ? void 0 : message.includes('Profile is currently paused')) || pageUrl.includes('//localhost') || pageUrl.includes('//snapui.searchspring.io/')) {
70
+ return;
93
71
  }
94
- var href = data.href, filename = data.filename, stack = data.stack, message = data.message, colno = data.colno, lineno = data.lineno, errortimestamp = data.errortimestamp, details = data.details;
95
- var payload = {
96
- type: types_1.BeaconType.ERROR,
97
- category: types_1.BeaconCategory.RUNTIME,
98
- context: context,
99
- event: {
100
- href: href || window.location.href,
101
- filename: filename,
72
+ _this.events.error.snap({
73
+ data: {
74
+ message: message || 'unknown',
102
75
  stack: stack,
103
- message: message,
104
- colno: colno,
105
- lineno: lineno,
106
- errortimestamp: errortimestamp,
107
76
  details: details,
108
- context: data.context,
109
77
  },
110
- };
111
- // prevent sending of errors when on localhost or CDN
112
- if (((_a = payload.event.message) === null || _a === void 0 ? void 0 : _a.includes('Profile is currently paused')) ||
113
- !payload.event.href ||
114
- payload.event.href.includes('//localhost') ||
115
- payload.event.href.includes('//snapui.searchspring.io/')) {
116
- return;
117
- }
118
- return _this.track.event(payload);
78
+ siteId: siteId,
79
+ });
119
80
  },
120
81
  shopper: {
121
82
  login: function (data, siteId) {
122
- // sets shopperid if logged in
123
- if (!(0, snap_toolbox_1.getFlags)().cookies()) {
83
+ var _a;
84
+ if ((_a = _this.doNotTrack) === null || _a === void 0 ? void 0 : _a.includes('shopper.login')) {
124
85
  return;
125
86
  }
126
- if (!data.id) {
127
- console.error('tracker.shopper.login event: requires a valid shopper ID parameter. Example: tracker.shopper.login({ id: "1234" })');
128
- return;
129
- }
130
- data.id = "".concat(data.id);
131
- var context = _this.context;
132
- if (siteId) {
133
- context = (0, deepmerge_1.default)(context, {
134
- context: {
135
- website: {
136
- trackingCode: siteId,
137
- },
138
- },
139
- });
140
- context.shopperId = data.id;
141
- }
142
- var storedShopperId = _this.getShopperId();
143
- if (storedShopperId != data.id) {
144
- // user's logged in id has changed, update shopperId cookie send login event
145
- snap_toolbox_1.cookies.set(SHOPPERID_COOKIE_NAME, data.id, COOKIE_SAMESITE, COOKIE_EXPIRATION, COOKIE_DOMAIN);
146
- _this.context.shopperId = data.id;
147
- _this.sendPreflight();
148
- var payload = {
149
- type: types_1.BeaconType.LOGIN,
150
- category: types_1.BeaconCategory.PERSONALIZATION,
151
- context: context,
152
- event: {
153
- userId: _this.context.userId,
154
- shopperId: data.id,
155
- },
156
- };
157
- return _this.track.event(payload);
158
- }
87
+ _this.events.shopper.login({ data: { id: data.id }, siteId: siteId });
159
88
  },
160
89
  },
161
90
  product: {
162
91
  view: function (data, siteId) {
163
- if (!(data === null || data === void 0 ? void 0 : data.uid) && !(data === null || data === void 0 ? void 0 : data.sku) && !(data === null || data === void 0 ? void 0 : data.childUid) && !(data === null || data === void 0 ? void 0 : data.childSku)) {
164
- console.error('track.product.view event: requires a valid uid, sku and/or childUid, childSku. \nExample: track.product.view({ uid: "123", sku: "product123", childUid: "123_a", childSku: "product123_a" })');
92
+ var _a;
93
+ if ((_a = _this.doNotTrack) === null || _a === void 0 ? void 0 : _a.includes('product.view')) {
165
94
  return;
166
95
  }
167
- var context = _this.context;
168
- if (siteId) {
169
- context = (0, deepmerge_1.default)(context, {
170
- context: {
171
- website: {
172
- trackingCode: siteId,
173
- },
174
- },
175
- });
176
- }
177
- var payload = {
178
- type: types_1.BeaconType.PRODUCT,
179
- category: types_1.BeaconCategory.PAGEVIEW,
180
- context: context,
181
- event: {
182
- uid: (data === null || data === void 0 ? void 0 : data.uid) ? "".concat(data.uid) : undefined,
183
- sku: (data === null || data === void 0 ? void 0 : data.sku) ? "".concat(data.sku) : undefined,
184
- childUid: (data === null || data === void 0 ? void 0 : data.childUid) ? "".concat(data.childUid) : undefined,
185
- childSku: (data === null || data === void 0 ? void 0 : data.childSku) ? "".concat(data.childSku) : undefined,
186
- },
187
- };
188
- var event = _this.track.event(payload);
189
- if (event) {
190
- // save recently viewed products to cookie
191
- var sku = (data === null || data === void 0 ? void 0 : data.childSku) || (data === null || data === void 0 ? void 0 : data.childUid) || (data === null || data === void 0 ? void 0 : data.sku) || (data === null || data === void 0 ? void 0 : data.uid);
192
- if (sku) {
193
- var lastViewedProducts = _this.cookies.viewed.get();
194
- var uniqueCartItems = Array.from(new Set(__spreadArray([sku], lastViewedProducts, true))).map(function (item) { return "".concat(item).trim(); });
195
- snap_toolbox_1.cookies.set(VIEWED_PRODUCTS, uniqueCartItems.slice(0, exports.MAX_VIEWED_COUNT).join(','), COOKIE_SAMESITE, VIEWED_COOKIE_EXPIRATION, COOKIE_DOMAIN);
196
- if (!lastViewedProducts.includes(sku)) {
197
- _this.sendPreflight();
198
- }
199
- }
200
- // legacy tracking
201
- if (data === null || data === void 0 ? void 0 : data.sku) {
202
- // only send sku to pixel tracker if present (don't send childSku)
203
- new PixelEvent_1.PixelEvent(__assign(__assign({}, payload), { event: {
204
- sku: data.sku,
205
- id: data.uid,
206
- } }));
207
- }
208
- return event;
96
+ var result = data;
97
+ if (!data.uid && data.sku) {
98
+ result = __assign(__assign({}, data), { uid: data.sku });
209
99
  }
100
+ _this.events.product.pageView({ data: { result: result }, siteId: siteId });
210
101
  },
102
+ /**
103
+ * @deprecated tracker.track.product.click() is deprecated and will be removed. Use tracker.events['search' | 'category'].clickThrough() instead
104
+ */
211
105
  click: function (data, siteId) {
106
+ // Controllers will send product click events through tracker.beacon
107
+ // For legacy support if someone calls this, continute to 1.0 beacon just like is.js
108
+ // TODO: remove after 1.0 deprecation period
109
+ var _a;
110
+ if ((_a = _this.doNotTrack) === null || _a === void 0 ? void 0 : _a.includes('product.click')) {
111
+ return;
112
+ }
212
113
  if (!(data === null || data === void 0 ? void 0 : data.intellisuggestData) || !(data === null || data === void 0 ? void 0 : data.intellisuggestSignature)) {
213
114
  console.error("track.product.click event: object parameter requires a valid intellisuggestData and intellisuggestSignature. \nExample: track.click.product({ intellisuggestData: \"eJwrTs4tNM9jYCjKTM8oYXDWdQ3TDTfUDbIwMDVjMARCYwMQSi_KTAEA9IQKWA\", intellisuggestSignature: \"9e46f9fd3253c267fefc298704e39084a6f8b8e47abefdee57277996b77d8e70\" })");
214
115
  return;
215
116
  }
216
- var context = _this.context;
217
- if (siteId) {
218
- context = (0, deepmerge_1.default)(context, {
219
- context: {
220
- website: {
221
- trackingCode: siteId,
222
- },
223
- },
224
- });
225
- }
226
- var payload = {
117
+ var beaconContext = _this.getContext();
118
+ var context = transformToLegacyContext(beaconContext, siteId || _this.globals.siteId);
119
+ var event = {
227
120
  type: types_1.BeaconType.CLICK,
228
121
  category: types_1.BeaconCategory.INTERACTION,
229
122
  context: context,
@@ -233,365 +126,115 @@ var Tracker = /** @class */ (function () {
233
126
  href: (data === null || data === void 0 ? void 0 : data.href) ? "".concat(data.href) : undefined,
234
127
  },
235
128
  };
236
- // legacy tracking
237
- new TrackEvent_1.TrackEvent(payload);
238
- return _this.track.event(payload);
129
+ var beaconEvent = new BeaconEvent_1.BeaconEvent(event, _this.config);
130
+ var beaconEventData = beaconEvent.send();
131
+ return beaconEventData;
239
132
  },
240
133
  },
241
134
  cart: {
242
135
  view: function (data, siteId) {
243
- if (!Array.isArray(data === null || data === void 0 ? void 0 : data.items) || !(data === null || data === void 0 ? void 0 : data.items.length)) {
244
- console.error('track.view.cart event: parameter must be an array of cart items. \nExample: track.view.cart({ items: [{ id: "123", sku: "product123", childSku: "product123_a", qty: "1", price: "9.99" }] })');
136
+ var _a;
137
+ if ((_a = _this.doNotTrack) === null || _a === void 0 ? void 0 : _a.includes('cart.view')) {
245
138
  return;
246
139
  }
247
- var context = _this.context;
248
- if (siteId) {
249
- context = (0, deepmerge_1.default)(context, {
250
- context: {
251
- website: {
252
- trackingCode: siteId,
253
- },
254
- },
255
- });
256
- }
257
- var items = data.items.map(function (item, index) {
258
- if (!(item === null || item === void 0 ? void 0 : item.qty) || !(item === null || item === void 0 ? void 0 : item.price) || (!(item === null || item === void 0 ? void 0 : item.uid) && !(item === null || item === void 0 ? void 0 : item.sku) && !(item === null || item === void 0 ? void 0 : item.childUid) && !(item === null || item === void 0 ? void 0 : item.childSku))) {
259
- console.error("track.view.cart event: item at index ".concat(index, " requires a valid qty, price, and (uid and/or sku and/or childUid and/or childSku.) \nExample: track.view.cart({ items: [{ uid: \"123\", sku: \"product123\", childUid: \"123_a\", childSku: \"product123_a\", qty: \"1\", price: \"9.99\" }] })"));
260
- return;
261
- }
262
- var product = {
263
- qty: "".concat(item.qty),
264
- price: "".concat(item.price),
265
- };
266
- if (item === null || item === void 0 ? void 0 : item.uid) {
267
- product.uid = "".concat(item.uid);
268
- }
269
- if (item === null || item === void 0 ? void 0 : item.sku) {
270
- product.sku = "".concat(item.sku);
140
+ // uid can be optional in legacy payload but required in 2.0 spec - use sku as fallback
141
+ var results = data.items
142
+ .map(function (item) {
143
+ if (!item.uid && item.sku) {
144
+ return __assign(__assign({}, item), { uid: item.sku });
271
145
  }
272
- if (item === null || item === void 0 ? void 0 : item.childUid) {
273
- product.childUid = "".concat(item.childUid);
146
+ else {
147
+ return item;
274
148
  }
275
- if (item === null || item === void 0 ? void 0 : item.childSku) {
276
- product.childSku = "".concat(item.childSku);
277
- }
278
- return product;
149
+ })
150
+ .map(function (item) {
151
+ // convert to Product[] - ensure qty and price are numbers
152
+ return __assign(__assign({}, item), { qty: Number(item.qty), price: Number(item.price) });
279
153
  });
280
- var payload = {
281
- type: types_1.BeaconType.CART,
282
- category: types_1.BeaconCategory.CARTVIEW,
283
- context: context,
284
- event: { items: items },
285
- };
286
- var event = _this.track.event(payload);
287
- if (event) {
288
- // save cart items to cookie
289
- if (items.length) {
290
- var products = items.map(function (item) { return (item === null || item === void 0 ? void 0 : item.childSku) || (item === null || item === void 0 ? void 0 : item.childUid) || (item === null || item === void 0 ? void 0 : item.sku) || (item === null || item === void 0 ? void 0 : item.uid) || ''; }).filter(function (sku) { return sku; });
291
- _this.cookies.cart.add(products);
292
- }
293
- // legacy tracking
294
- new PixelEvent_1.PixelEvent(payload);
295
- return event;
296
- }
154
+ _this.events.cart.view({ data: { results: results }, siteId: siteId });
297
155
  },
298
156
  },
299
157
  order: {
300
158
  transaction: function (data, siteId) {
301
- var _a, _b, _c, _d, _e, _f;
302
- if (!(data === null || data === void 0 ? void 0 : data.items) || !Array.isArray(data.items) || !data.items.length) {
303
- console.error('track.order.transaction event: object parameter must contain `items` array of cart items. \nExample: order.transaction({ order: { id: "1001", total: "10.71", transactionTotal: "9.99", city: "Los Angeles", state: "CA", country: "US" }, items: [{ uid: "123", sku: "product123", childUid: "123_a", childSku: "product123_a", qty: "1", price: "9.99" }] })');
159
+ var _a;
160
+ if ((_a = _this.doNotTrack) === null || _a === void 0 ? void 0 : _a.includes('order.transaction')) {
304
161
  return;
305
162
  }
306
- var context = _this.context;
307
- if (siteId) {
308
- context = (0, deepmerge_1.default)(context, {
309
- context: {
310
- website: {
311
- trackingCode: siteId,
312
- },
313
- },
314
- });
315
- }
316
- var items = data.items.map(function (item, index) {
317
- if (!(item === null || item === void 0 ? void 0 : item.qty) || !(item === null || item === void 0 ? void 0 : item.price) || (!(item === null || item === void 0 ? void 0 : item.uid) && !(item === null || item === void 0 ? void 0 : item.sku) && !(item === null || item === void 0 ? void 0 : item.childUid) && !(item === null || item === void 0 ? void 0 : item.childSku))) {
318
- console.error("track.order.transaction event: object parameter `items`: item at index ".concat(index, " requires a valid qty, price, and (id or sku and/or childSku.) \nExample: order.view({ items: [{ uid: \"123\", sku: \"product123\", childUid: \"123_a\", childSku: \"product123_a\", qty: \"1\", price: \"9.99\" }] })"));
319
- return;
320
- }
321
- var product = {
322
- qty: "".concat(item.qty),
323
- price: "".concat(item.price),
324
- };
325
- if (item === null || item === void 0 ? void 0 : item.uid) {
326
- product.uid = "".concat(item.uid);
327
- }
328
- if (item === null || item === void 0 ? void 0 : item.sku) {
329
- product.sku = "".concat(item.sku);
330
- }
331
- if (item === null || item === void 0 ? void 0 : item.childUid) {
332
- product.childUid = "".concat(item.childUid);
333
- }
334
- if (item === null || item === void 0 ? void 0 : item.childSku) {
335
- product.childSku = "".concat(item.childSku);
336
- }
337
- return product;
338
- });
339
- var eventPayload = {
340
- orderId: ((_a = data === null || data === void 0 ? void 0 : data.order) === null || _a === void 0 ? void 0 : _a.id) ? "".concat(data.order.id) : undefined,
341
- total: ((_b = data === null || data === void 0 ? void 0 : data.order) === null || _b === void 0 ? void 0 : _b.total) ? "".concat(data.order.total) : undefined,
342
- transactionTotal: ((_c = data === null || data === void 0 ? void 0 : data.order) === null || _c === void 0 ? void 0 : _c.transactionTotal) ? "".concat(data.order.transactionTotal) : undefined,
343
- city: ((_d = data === null || data === void 0 ? void 0 : data.order) === null || _d === void 0 ? void 0 : _d.city) ? "".concat(data.order.city) : undefined,
344
- state: ((_e = data === null || data === void 0 ? void 0 : data.order) === null || _e === void 0 ? void 0 : _e.state) ? "".concat(data.order.state) : undefined,
345
- country: ((_f = data === null || data === void 0 ? void 0 : data.order) === null || _f === void 0 ? void 0 : _f.country) ? "".concat(data.order.country) : undefined,
346
- items: items,
347
- };
348
- var payload = {
349
- type: types_1.BeaconType.ORDER,
350
- category: types_1.BeaconCategory.ORDERVIEW,
351
- context: context,
352
- event: eventPayload,
163
+ var order = data.order;
164
+ var items = data.items;
165
+ var orderTransactionData = {
166
+ orderId: "".concat((order === null || order === void 0 ? void 0 : order.id) || ''),
167
+ transactionTotal: Number((order === null || order === void 0 ? void 0 : order.transactionTotal) || 0),
168
+ total: Number((order === null || order === void 0 ? void 0 : order.total) || 0),
169
+ city: order === null || order === void 0 ? void 0 : order.city,
170
+ state: order === null || order === void 0 ? void 0 : order.state,
171
+ country: order === null || order === void 0 ? void 0 : order.country,
172
+ results: items.map(function (item) {
173
+ return {
174
+ // uid is required - fallback to get most relevant
175
+ uid: item.uid || item.sku || '',
176
+ childUid: item.childUid,
177
+ sku: item.sku,
178
+ childSku: item.childSku,
179
+ qty: Number(item.qty),
180
+ price: Number(item.price),
181
+ };
182
+ }),
353
183
  };
354
- var event = _this.track.event(payload);
355
- if (event) {
356
- // clear cart items from cookie when order is placed
357
- _this.cookies.cart.clear();
358
- // legacy tracking
359
- new PixelEvent_1.PixelEvent(payload);
360
- return event;
361
- }
184
+ _this.events.order.transaction({ data: orderTransactionData, siteId: siteId });
362
185
  },
363
186
  },
364
187
  };
365
- this.updateContext = function (key, value) {
366
- if (value) {
367
- _this.context[key] = value;
368
- }
369
- };
370
- this.setCurrency = function (currency) {
371
- if (!(currency === null || currency === void 0 ? void 0 : currency.code)) {
372
- return;
373
- }
374
- _this.context.currency = currency;
375
- };
376
- this.getUserId = function () {
377
- var userId;
378
- try {
379
- // use cookies if available, fallback to localstorage
380
- if ((0, snap_toolbox_1.getFlags)().cookies()) {
381
- userId = snap_toolbox_1.cookies.get(LEGACY_USERID_COOKIE_NAME) || snap_toolbox_1.cookies.get(USERID_COOKIE_NAME) || (0, uuid_1.v4)();
382
- snap_toolbox_1.cookies.set(USERID_COOKIE_NAME, userId, COOKIE_SAMESITE, COOKIE_EXPIRATION, COOKIE_DOMAIN);
383
- snap_toolbox_1.cookies.set(LEGACY_USERID_COOKIE_NAME, userId, COOKIE_SAMESITE, COOKIE_EXPIRATION, COOKIE_DOMAIN);
384
- }
385
- else if ((0, snap_toolbox_1.getFlags)().storage()) {
386
- userId = window.localStorage.getItem(USERID_COOKIE_NAME) || (0, uuid_1.v4)();
387
- window.localStorage.setItem(USERID_COOKIE_NAME, userId);
388
- }
389
- else {
390
- throw 'unsupported features';
391
- }
392
- }
393
- catch (e) {
394
- console.error('Failed to persist user id to cookie or local storage:', e);
395
- }
396
- return userId;
397
- };
398
- this.getSessionId = function () {
399
- var sessionId;
400
- if ((0, snap_toolbox_1.getFlags)().storage()) {
401
- try {
402
- sessionId = window.sessionStorage.getItem(SESSIONID_STORAGE_NAME) || (0, uuid_1.v4)();
403
- window.sessionStorage.setItem(SESSIONID_STORAGE_NAME, sessionId);
404
- (0, snap_toolbox_1.getFlags)().cookies() && snap_toolbox_1.cookies.set(SESSIONID_STORAGE_NAME, sessionId, COOKIE_SAMESITE, 0, COOKIE_DOMAIN); //session cookie
405
- }
406
- catch (e) {
407
- console.error('Failed to persist session id to session storage:', e);
408
- }
409
- }
410
- else if ((0, snap_toolbox_1.getFlags)().cookies()) {
411
- // use cookies if sessionStorage is not enabled and only reset cookie if new session to keep expiration
412
- sessionId = snap_toolbox_1.cookies.get(SESSIONID_STORAGE_NAME);
413
- if (!sessionId) {
414
- sessionId = (0, uuid_1.v4)();
415
- snap_toolbox_1.cookies.set(SESSIONID_STORAGE_NAME, sessionId, COOKIE_SAMESITE, 0, COOKIE_DOMAIN);
416
- }
417
- }
418
- return sessionId;
419
- };
420
- this.getShopperId = function () {
421
- var shopperId = snap_toolbox_1.cookies.get(SHOPPERID_COOKIE_NAME);
422
- if (!shopperId) {
423
- return;
424
- }
425
- return shopperId;
426
- };
427
- this.sendPreflight = function () {
428
- var _a, _b;
429
- var userId = _this.getUserId();
430
- var siteId = _this.context.website.trackingCode;
431
- var shopper = _this.getShopperId();
432
- var cart = _this.cookies.cart.get();
433
- var lastViewed = _this.cookies.viewed.get();
434
- if (userId && typeof userId == 'string' && siteId && (shopper || cart.length || lastViewed.length)) {
435
- var preflightParams = {
436
- userId: userId,
437
- siteId: siteId,
438
- };
439
- var queryStringParams = "?userId=".concat(encodeURIComponent(userId), "&siteId=").concat(encodeURIComponent(siteId));
440
- if (shopper) {
441
- preflightParams.shopper = shopper;
442
- queryStringParams += "&shopper=".concat(encodeURIComponent(shopper));
443
- }
444
- if (cart.length) {
445
- preflightParams.cart = cart;
446
- queryStringParams += cart.map(function (item) { return "&cart=".concat(encodeURIComponent(item)); }).join('');
447
- }
448
- if (lastViewed.length) {
449
- preflightParams.lastViewed = lastViewed;
450
- queryStringParams += lastViewed.map(function (item) { return "&lastViewed=".concat(encodeURIComponent(item)); }).join('');
451
- }
452
- var origin_1 = ((_b = (_a = _this.config.requesters) === null || _a === void 0 ? void 0 : _a.personalization) === null || _b === void 0 ? void 0 : _b.origin) || "https://".concat(siteId, ".a.searchspring.io");
453
- var endpoint = "".concat(origin_1, "/api/personalization/preflightCache");
454
- var xhr = new XMLHttpRequest();
455
- if ((0, snap_toolbox_1.charsParams)(preflightParams) > 1024) {
456
- xhr.open('POST', endpoint);
457
- xhr.setRequestHeader('Content-Type', 'application/json');
458
- xhr.send(JSON.stringify(preflightParams));
459
- }
460
- else {
461
- xhr.open('GET', endpoint + queryStringParams);
462
- xhr.send();
463
- }
464
- }
465
- };
466
- this.cookies = {
188
+ _this.cookies = {
467
189
  cart: {
468
190
  get: function () {
469
- var items = snap_toolbox_1.cookies.get(CART_PRODUCTS);
470
- if (!items) {
471
- return [];
472
- }
473
- return items.split(',');
191
+ var data = _this.storage.cart.get();
192
+ return data.map(function (item) { return _this.getProductId(item); });
474
193
  },
475
194
  set: function (items) {
476
- if (items.length) {
477
- var cartItems = items.map(function (item) { return "".concat(item).trim(); });
478
- var uniqueCartItems = Array.from(new Set(cartItems));
479
- snap_toolbox_1.cookies.set(CART_PRODUCTS, uniqueCartItems.join(','), COOKIE_SAMESITE, 0, COOKIE_DOMAIN);
480
- var itemsHaveChanged = cartItems.filter(function (item) { return items.includes(item); }).length !== items.length;
481
- if (itemsHaveChanged) {
482
- _this.sendPreflight();
483
- }
484
- }
195
+ var cartItems = items.map(function (item) { return "".concat(item).trim(); });
196
+ var uniqueCartItems = Array.from(new Set(cartItems)).map(function (uid) { return ({ uid: uid, sku: uid, price: 0, qty: 1 }); });
197
+ _this.storage.cart.set(uniqueCartItems);
485
198
  },
486
199
  add: function (items) {
487
200
  if (items.length) {
488
- var currentCartItems = _this.cookies.cart.get();
489
- var itemsToAdd_1 = items.map(function (item) { return "".concat(item).trim(); });
490
- var uniqueCartItems = Array.from(new Set(__spreadArray(__spreadArray([], currentCartItems, true), itemsToAdd_1, true)));
491
- snap_toolbox_1.cookies.set(CART_PRODUCTS, uniqueCartItems.join(','), COOKIE_SAMESITE, 0, COOKIE_DOMAIN);
492
- var itemsHaveChanged = currentCartItems.filter(function (item) { return itemsToAdd_1.includes(item); }).length !== itemsToAdd_1.length;
493
- if (itemsHaveChanged) {
494
- _this.sendPreflight();
495
- }
201
+ var itemsToAdd = items.map(function (item) { return "".concat(item).trim(); }).map(function (uid) { return ({ uid: uid, sku: uid, price: 0, qty: 1 }); });
202
+ _this.storage.cart.add(itemsToAdd);
496
203
  }
497
204
  },
498
205
  remove: function (items) {
499
206
  if (items.length) {
500
- var currentCartItems = _this.cookies.cart.get();
501
- var itemsToRemove_1 = items.map(function (item) { return "".concat(item).trim(); });
502
- var updatedItems = currentCartItems.filter(function (item) { return !itemsToRemove_1.includes(item); });
503
- snap_toolbox_1.cookies.set(CART_PRODUCTS, updatedItems.join(','), COOKIE_SAMESITE, 0, COOKIE_DOMAIN);
504
- var itemsHaveChanged = currentCartItems.length !== updatedItems.length;
505
- if (itemsHaveChanged) {
506
- _this.sendPreflight();
507
- }
207
+ var itemsToRemove = items.map(function (item) { return "".concat(item).trim(); }).map(function (uid) { return ({ uid: uid, sku: uid, price: 0, qty: 1 }); });
208
+ _this.storage.cart.remove(itemsToRemove);
508
209
  }
509
210
  },
510
211
  clear: function () {
511
- if (_this.cookies.cart.get().length) {
512
- snap_toolbox_1.cookies.unset(CART_PRODUCTS, COOKIE_DOMAIN);
513
- _this.sendPreflight();
514
- }
212
+ _this.storage.cart.clear();
515
213
  },
516
214
  },
517
215
  viewed: {
518
216
  get: function () {
519
- var items = snap_toolbox_1.cookies.get(VIEWED_PRODUCTS);
520
- if (!items) {
521
- return [];
522
- }
523
- return items.split(',');
217
+ var viewedItems = _this.storage.viewed.get();
218
+ return viewedItems.map(function (item) { return _this.getProductId(item); });
524
219
  },
525
220
  },
526
221
  };
527
- this.sendEvents = function (eventsToSend) {
528
- if (_this.mode !== snap_toolbox_2.AppMode.production) {
529
- return;
530
- }
531
- var savedEvents = JSON.parse(_this.localStorage.get(LOCALSTORAGE_BEACON_POOL_NAME) || '[]');
532
- if (eventsToSend) {
533
- var eventsClone_1 = [];
534
- savedEvents.forEach(function (_event, idx) {
535
- // using Object.assign since we are not modifying nested properties
536
- eventsClone_1.push(Object.assign({}, _event));
537
- delete eventsClone_1[idx].id;
538
- delete eventsClone_1[idx].pid;
539
- });
540
- var stringyEventsClone_1 = JSON.stringify(eventsClone_1);
541
- // de-dupe events
542
- eventsToSend.forEach(function (event, idx) {
543
- var newEvent = Object.assign({}, event);
544
- delete newEvent.id;
545
- delete newEvent.pid;
546
- if (stringyEventsClone_1.indexOf(JSON.stringify(newEvent)) == -1) {
547
- savedEvents.push(__assign({}, eventsToSend[idx]));
548
- }
549
- });
550
- // save the beacon pool with de-duped events
551
- _this.localStorage.set(LOCALSTORAGE_BEACON_POOL_NAME, JSON.stringify(savedEvents));
552
- }
553
- clearTimeout(_this.isSending);
554
- _this.isSending = window.setTimeout(function () {
555
- var _a, _b;
556
- if (savedEvents.length) {
557
- var xhr = new XMLHttpRequest();
558
- var origin_2 = ((_b = (_a = _this.config.requesters) === null || _a === void 0 ? void 0 : _a.beacon) === null || _b === void 0 ? void 0 : _b.origin) || 'https://beacon.searchspring.io';
559
- xhr.open('POST', "".concat(origin_2, "/beacon"));
560
- xhr.setRequestHeader('Content-Type', 'application/json');
561
- xhr.send(JSON.stringify(savedEvents.length == 1 ? savedEvents[0] : savedEvents));
562
- }
563
- _this.localStorage.set(LOCALSTORAGE_BEACON_POOL_NAME, JSON.stringify([]));
564
- }, exports.BATCH_TIMEOUT);
565
- };
566
222
  if (typeof globals != 'object' || typeof globals.siteId != 'string') {
567
223
  throw new Error("Invalid config passed to tracker. The \"siteId\" attribute must be provided.");
568
224
  }
569
- this.config = (0, deepmerge_1.default)(defaultConfig, config || {});
570
- this.doNotTrack = this.config.doNotTrack || [];
571
- if (Object.values(snap_toolbox_2.AppMode).includes(this.config.mode)) {
572
- this.mode = this.config.mode;
225
+ _this.config = config;
226
+ _this.doNotTrack = _this.config.doNotTrack || [];
227
+ if (Object.values(snap_toolbox_2.AppMode).includes(_this.config.mode)) {
228
+ _this.mode = _this.config.mode;
573
229
  }
574
- this.globals = globals;
575
- this.localStorage = new snap_store_mobx_1.StorageStore({
230
+ _this.localStorage = new snap_store_mobx_1.StorageStore({
576
231
  type: 'local',
577
- key: "ss-".concat(this.config.id),
232
+ key: "ss-".concat(_this.config.id),
578
233
  });
579
- this.localStorage.set('siteId', this.globals.siteId);
580
- this.context = {
581
- userId: this.getUserId() || '',
582
- sessionId: this.getSessionId(),
583
- shopperId: this.getShopperId(),
584
- pageLoadId: (0, uuid_1.v4)(),
585
- website: {
586
- trackingCode: this.globals.siteId,
587
- },
588
- };
589
- if ((_a = this.globals.currency) === null || _a === void 0 ? void 0 : _a.code) {
590
- this.context.currency = this.globals.currency;
591
- }
592
- if (!((_b = window.searchspring) === null || _b === void 0 ? void 0 : _b.tracker)) {
234
+ _this.localStorage.set('siteId', _this.globals.siteId);
235
+ if (!((_a = window.searchspring) === null || _a === void 0 ? void 0 : _a.tracker)) {
593
236
  window.searchspring = window.searchspring || {};
594
- window.searchspring.tracker = this;
237
+ window.searchspring.tracker = _this;
595
238
  window.searchspring.version = snap_toolbox_1.version;
596
239
  }
597
240
  // since this is in the constructor, setTimeout is required for jest.spyOn
@@ -690,19 +333,49 @@ var Tracker = /** @class */ (function () {
690
333
  });
691
334
  }
692
335
  });
693
- this.sendEvents();
336
+ return _this;
694
337
  }
695
338
  Tracker.prototype.getGlobals = function () {
696
339
  return JSON.parse(JSON.stringify(this.globals));
697
340
  };
698
- Tracker.prototype.getContext = function () {
699
- return JSON.parse(JSON.stringify(this.context));
700
- };
701
341
  Tracker.prototype.retarget = function () {
702
342
  this.targeters.forEach(function (target) {
703
343
  target.retarget();
704
344
  });
705
345
  };
706
346
  return Tracker;
707
- }());
347
+ }(beacon_1.Beacon));
708
348
  exports.Tracker = Tracker;
349
+ function transformToLegacyContext(_context, siteId) {
350
+ var _a;
351
+ var context = __assign({}, _context);
352
+ if (context.userAgent) {
353
+ delete context.userAgent;
354
+ }
355
+ if (context.timestamp) {
356
+ // @ts-ignore - property not optional
357
+ delete context.timestamp;
358
+ }
359
+ if (context.initiator) {
360
+ // @ts-ignore - property not optional
361
+ delete context.initiator;
362
+ }
363
+ if (context.dev) {
364
+ delete context.dev;
365
+ }
366
+ var attribution;
367
+ if ((_a = context.attribution) === null || _a === void 0 ? void 0 : _a.length) {
368
+ attribution = {
369
+ type: context.attribution[0].type,
370
+ id: context.attribution[0].id,
371
+ };
372
+ delete context.attribution;
373
+ }
374
+ var beaconContext = __assign(__assign({}, context), { website: {
375
+ trackingCode: siteId,
376
+ } });
377
+ if (attribution) {
378
+ beaconContext.attribution = attribution;
379
+ }
380
+ return beaconContext;
381
+ }