@liquidcommercedev/rmn-sdk 1.5.0-beta.4 → 1.5.0-beta.6
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.cjs +253 -16
- package/dist/index.esm.js +253 -16
- package/dist/types/enums.d.ts +1 -0
- package/dist/types/modules/event/event.interface.d.ts +5 -0
- package/dist/types/modules/event/helpers/datalayer.monitor.d.ts +21 -0
- package/dist/types/modules/event/helpers/index.d.ts +1 -0
- package/dist/types/modules/event/helpers/localstorage.service.d.ts +28 -4
- package/dist/types/modules/event/helpers/utils.d.ts +24 -0
- package/dist/types/modules/event/index.d.ts +1 -0
- package/dist/types/modules/event/pubsub.d.ts +7 -7
- package/dist/types/modules/event/user.monitor.d.ts +14 -0
- package/dist/types/types.d.ts +1 -1
- package/package.json +1 -1
- package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
package/dist/index.cjs
CHANGED
@@ -62,6 +62,7 @@ exports.RMN_SPOT_EVENT = void 0;
|
|
62
62
|
RMN_SPOT_EVENT["CLICK"] = "CLICK";
|
63
63
|
RMN_SPOT_EVENT["PURCHASE"] = "PURCHASE";
|
64
64
|
RMN_SPOT_EVENT["ADD_TO_CART"] = "ADD_TO_CART";
|
65
|
+
RMN_SPOT_EVENT["REMOVE_FROM_CART"] = "REMOVE_FROM_CART";
|
65
66
|
RMN_SPOT_EVENT["ADD_TO_WISHLIST"] = "ADD_TO_WISHLIST";
|
66
67
|
RMN_SPOT_EVENT["BUY_NOW"] = "BUY_NOW";
|
67
68
|
})(exports.RMN_SPOT_EVENT || (exports.RMN_SPOT_EVENT = {}));
|
@@ -15166,6 +15167,132 @@ const GFONT_CORMORANT = `
|
|
15166
15167
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Cormorant:ital,wght@0,300..700;1,300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap">
|
15167
15168
|
`;
|
15168
15169
|
|
15170
|
+
function getEventTypeFromRawEvent(event) {
|
15171
|
+
if (!event) {
|
15172
|
+
return null;
|
15173
|
+
}
|
15174
|
+
if (event.includes('cart')) {
|
15175
|
+
if (event.includes('add')) {
|
15176
|
+
return exports.RMN_SPOT_EVENT.ADD_TO_CART;
|
15177
|
+
}
|
15178
|
+
if (event.includes('remove')) {
|
15179
|
+
return exports.RMN_SPOT_EVENT.REMOVE_FROM_CART;
|
15180
|
+
}
|
15181
|
+
}
|
15182
|
+
if (event.includes('purchase')) {
|
15183
|
+
return exports.RMN_SPOT_EVENT.PURCHASE;
|
15184
|
+
}
|
15185
|
+
// if(event.includes('refund')) {
|
15186
|
+
// return RMN_SPOT_EVENT.REFUND;
|
15187
|
+
// }
|
15188
|
+
if (event.includes('wishlist') && event.includes('add')) {
|
15189
|
+
return exports.RMN_SPOT_EVENT.ADD_TO_WISHLIST;
|
15190
|
+
}
|
15191
|
+
return null;
|
15192
|
+
}
|
15193
|
+
/**
|
15194
|
+
* Recursively extracts ID values from a nested data structure.
|
15195
|
+
* Searches for specified property names and collects their primitive values (strings/numbers).
|
15196
|
+
*
|
15197
|
+
* @param data - The data structure to search through (can be nested objects/arrays)
|
15198
|
+
* @param propertyNames - Array of property names to look for (defaults to ['id', 'upc', 'groupingId', 'sku', 'productId'])
|
15199
|
+
* @returns Array of extracted ID values (strings/numbers only)
|
15200
|
+
*
|
15201
|
+
* @example
|
15202
|
+
* const data = {
|
15203
|
+
* id: [1, 2, 3],
|
15204
|
+
* nested: { id: 'abc' },
|
15205
|
+
* items: [{ id: 456 }]
|
15206
|
+
* };
|
15207
|
+
* extractDeepIds(data); // Returns [1, 2, 3, 'abc', 456]
|
15208
|
+
*/
|
15209
|
+
function extractDeepIds(data, propertyNames = ['id', 'upc', 'groupingId', 'sku', 'productId']) {
|
15210
|
+
const ids = [];
|
15211
|
+
// Set for faster property name lookups
|
15212
|
+
const propertySet = new Set(propertyNames);
|
15213
|
+
/**
|
15214
|
+
* Processes a value and extracts IDs if it matches criteria
|
15215
|
+
* @param value - The value to process
|
15216
|
+
* @param currentKey - The property name of the current value
|
15217
|
+
*/
|
15218
|
+
const processValue = (value, currentKey) => {
|
15219
|
+
// Early exit for null/undefined values
|
15220
|
+
if (value == null)
|
15221
|
+
return;
|
15222
|
+
// If current key matches our target properties
|
15223
|
+
if (currentKey && propertySet.has(currentKey)) {
|
15224
|
+
if (Array.isArray(value)) {
|
15225
|
+
// Filter and push valid array values in one pass
|
15226
|
+
ids.push(...value.filter((item) => typeof item === 'string' || typeof item === 'number'));
|
15227
|
+
}
|
15228
|
+
else if (typeof value === 'string' || typeof value === 'number') {
|
15229
|
+
ids.push(value);
|
15230
|
+
}
|
15231
|
+
return; // Stop processing this branch after handling the ID
|
15232
|
+
}
|
15233
|
+
// Recursively process nested structures
|
15234
|
+
if (Array.isArray(value)) {
|
15235
|
+
value.forEach((item) => processValue(item));
|
15236
|
+
}
|
15237
|
+
else if (typeof value === 'object') {
|
15238
|
+
// Process all enumerable properties
|
15239
|
+
for (const [key, val] of Object.entries(value)) {
|
15240
|
+
processValue(val, key);
|
15241
|
+
}
|
15242
|
+
}
|
15243
|
+
};
|
15244
|
+
processValue(data);
|
15245
|
+
return ids; // No need to filter nulls as we handle that during collection
|
15246
|
+
}
|
15247
|
+
|
15248
|
+
class DataLayerMonitor {
|
15249
|
+
constructor() {
|
15250
|
+
if (!window.dataLayer) {
|
15251
|
+
return;
|
15252
|
+
}
|
15253
|
+
this.originalPush = window.dataLayer.push;
|
15254
|
+
}
|
15255
|
+
static getInstance() {
|
15256
|
+
if (!DataLayerMonitor.instance) {
|
15257
|
+
DataLayerMonitor.instance = new DataLayerMonitor();
|
15258
|
+
}
|
15259
|
+
return DataLayerMonitor.instance;
|
15260
|
+
}
|
15261
|
+
setListener(listener) {
|
15262
|
+
this.listener = listener;
|
15263
|
+
}
|
15264
|
+
start() {
|
15265
|
+
window.dataLayer.push = (...args) => {
|
15266
|
+
const result = this.originalPush.apply(window.dataLayer, args);
|
15267
|
+
const pushedEvent = args[0];
|
15268
|
+
if (this.listener) {
|
15269
|
+
const normalizedData = this.cleanEventData(pushedEvent);
|
15270
|
+
if (normalizedData) {
|
15271
|
+
this.listener(normalizedData);
|
15272
|
+
}
|
15273
|
+
}
|
15274
|
+
return result;
|
15275
|
+
};
|
15276
|
+
}
|
15277
|
+
cleanEventData(data) {
|
15278
|
+
const eventName = getEventTypeFromRawEvent(data.event);
|
15279
|
+
if (!eventName) {
|
15280
|
+
return null;
|
15281
|
+
}
|
15282
|
+
const productIds = extractDeepIds(data.value);
|
15283
|
+
return {
|
15284
|
+
event: eventName,
|
15285
|
+
productIds,
|
15286
|
+
};
|
15287
|
+
}
|
15288
|
+
stop() {
|
15289
|
+
if (this.originalPush) {
|
15290
|
+
window.dataLayer.push = this.originalPush;
|
15291
|
+
}
|
15292
|
+
this.listener = undefined;
|
15293
|
+
}
|
15294
|
+
}
|
15295
|
+
|
15169
15296
|
class IntersectionObserverService {
|
15170
15297
|
constructor(defaultOptions = {}) {
|
15171
15298
|
this.observers = new Map();
|
@@ -15206,6 +15333,14 @@ class IntersectionObserverService {
|
|
15206
15333
|
}
|
15207
15334
|
}
|
15208
15335
|
|
15336
|
+
var ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX;
|
15337
|
+
(function (ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX) {
|
15338
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["SPOT_ID"] = 0] = "SPOT_ID";
|
15339
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["SPOT_TYPE"] = 1] = "SPOT_TYPE";
|
15340
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["EVENTS"] = 2] = "EVENTS";
|
15341
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["PRODUCT_IDS"] = 3] = "PRODUCT_IDS";
|
15342
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["CREATED_AT"] = 4] = "CREATED_AT";
|
15343
|
+
})(ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX || (ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX = {}));
|
15209
15344
|
class LocalStorage {
|
15210
15345
|
constructor() {
|
15211
15346
|
if (typeof window.localStorage === 'undefined') {
|
@@ -15231,7 +15366,11 @@ class LocalStorage {
|
|
15231
15366
|
try {
|
15232
15367
|
const parsedData = JSON.parse(localStorageData);
|
15233
15368
|
if (parsedData && typeof parsedData === 'object') {
|
15234
|
-
|
15369
|
+
const data = {};
|
15370
|
+
for (const [key, value] of Object.entries(parsedData)) {
|
15371
|
+
data[key] = this.arrayToObject(value);
|
15372
|
+
}
|
15373
|
+
this.spots = this.objectToMap(data);
|
15235
15374
|
}
|
15236
15375
|
else {
|
15237
15376
|
this.clearLocalStorage();
|
@@ -15244,26 +15383,34 @@ class LocalStorage {
|
|
15244
15383
|
}
|
15245
15384
|
}
|
15246
15385
|
setSpot(spotId, data) {
|
15247
|
-
|
15248
|
-
return;
|
15386
|
+
var _a;
|
15249
15387
|
data.createdAt = Date.now();
|
15250
|
-
this.spots.set(spotId, data);
|
15388
|
+
(_a = this.spots) === null || _a === void 0 ? void 0 : _a.set(spotId, data);
|
15251
15389
|
this.updateLocalStorage();
|
15252
15390
|
}
|
15253
|
-
getSpot(spotId) {
|
15254
|
-
var _a;
|
15255
|
-
return (_a = this.spots) === null || _a === void 0 ? void 0 : _a.get(spotId);
|
15256
|
-
}
|
15257
15391
|
removeSpot(spotId) {
|
15258
15392
|
var _a;
|
15259
15393
|
(_a = this.spots) === null || _a === void 0 ? void 0 : _a.delete(spotId);
|
15260
15394
|
this.updateLocalStorage();
|
15261
15395
|
}
|
15396
|
+
getSpot(spotId) {
|
15397
|
+
var _a;
|
15398
|
+
return (_a = this.spots) === null || _a === void 0 ? void 0 : _a.get(spotId);
|
15399
|
+
}
|
15400
|
+
getSpots() {
|
15401
|
+
if (!this.spots)
|
15402
|
+
return undefined;
|
15403
|
+
return this.mapToObject(this.spots);
|
15404
|
+
}
|
15262
15405
|
updateLocalStorage() {
|
15263
15406
|
if (!this.spots)
|
15264
|
-
return;
|
15265
|
-
const data = this.
|
15266
|
-
|
15407
|
+
return undefined;
|
15408
|
+
const data = this.mapToObject(this.spots);
|
15409
|
+
const dataArray = {};
|
15410
|
+
for (const [key, value] of Object.entries(data)) {
|
15411
|
+
dataArray[key] = this.objectToArray(value);
|
15412
|
+
}
|
15413
|
+
window.localStorage.setItem(LocalStorage.localStorageKey, JSON.stringify(dataArray));
|
15267
15414
|
}
|
15268
15415
|
clearLocalStorage() {
|
15269
15416
|
window.localStorage.removeItem(LocalStorage.localStorageKey);
|
@@ -15279,12 +15426,24 @@ class LocalStorage {
|
|
15279
15426
|
});
|
15280
15427
|
this.updateLocalStorage();
|
15281
15428
|
}
|
15282
|
-
|
15429
|
+
mapToObject(map) {
|
15283
15430
|
return Object.fromEntries(map);
|
15284
15431
|
}
|
15285
|
-
|
15432
|
+
objectToMap(obj) {
|
15286
15433
|
return new Map(Object.entries(obj));
|
15287
15434
|
}
|
15435
|
+
objectToArray(obj) {
|
15436
|
+
return [obj.spotId, obj.spotType, obj.events, obj.productIds, obj.createdAt];
|
15437
|
+
}
|
15438
|
+
arrayToObject(arr) {
|
15439
|
+
return {
|
15440
|
+
spotId: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.SPOT_ID],
|
15441
|
+
spotType: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.SPOT_TYPE],
|
15442
|
+
events: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.EVENTS],
|
15443
|
+
productIds: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.PRODUCT_IDS],
|
15444
|
+
createdAt: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.CREATED_AT],
|
15445
|
+
};
|
15446
|
+
}
|
15288
15447
|
}
|
15289
15448
|
LocalStorage.localStorageKey = 'lc_rmn';
|
15290
15449
|
LocalStorage.spotExpirationTime = 1000 * 60 * 60 * 24 * 7; // 7 days
|
@@ -17978,7 +18137,7 @@ const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
|
|
17978
18137
|
/**
|
17979
18138
|
* PubSub class
|
17980
18139
|
* Manages event subscriptions and publications
|
17981
|
-
* @template
|
18140
|
+
* @template IRmnEventMap A record type defining the structure of events and their data
|
17982
18141
|
*/
|
17983
18142
|
class PubSub {
|
17984
18143
|
constructor() {
|
@@ -18032,12 +18191,12 @@ class PubSub {
|
|
18032
18191
|
/**
|
18033
18192
|
* Usage Example:
|
18034
18193
|
*
|
18035
|
-
* interface
|
18194
|
+
* interface IRmnEventMap {
|
18036
18195
|
* userLogin: { username: string; timestamp: number };
|
18037
18196
|
* pageView: { url: string; timestamp: number };
|
18038
18197
|
* }
|
18039
18198
|
*
|
18040
|
-
* const pubSub = new PubSub<
|
18199
|
+
* const pubSub = new PubSub<IRmnEventMap>();
|
18041
18200
|
*
|
18042
18201
|
* // Subscribe to events
|
18043
18202
|
* const unsubscribeLogin = pubSub.subscribe('userLogin', (data) => {
|
@@ -18056,6 +18215,78 @@ class PubSub {
|
|
18056
18215
|
* unsubscribeLogin();
|
18057
18216
|
*/
|
18058
18217
|
|
18218
|
+
// @TODO: Add support for user to push events to our own data layer, if they don't use any analytics tool.
|
18219
|
+
// window.rmnDataLayer = window.rmnDataLayer || [];
|
18220
|
+
// For the moment, we will only focus on sites that use Google Analytics,
|
18221
|
+
// but we will add support for other analytics tools in the future.
|
18222
|
+
var AnalyticsTool;
|
18223
|
+
(function (AnalyticsTool) {
|
18224
|
+
AnalyticsTool["GoogleAnalytics"] = "google-analytics";
|
18225
|
+
AnalyticsTool["Other"] = "Other";
|
18226
|
+
})(AnalyticsTool || (AnalyticsTool = {}));
|
18227
|
+
class UserMonitor {
|
18228
|
+
constructor() {
|
18229
|
+
const analyticsTool = this.detectAnalyticsTool();
|
18230
|
+
switch (analyticsTool) {
|
18231
|
+
case AnalyticsTool.GoogleAnalytics:
|
18232
|
+
this.implementedMonitor = DataLayerMonitor.getInstance();
|
18233
|
+
break;
|
18234
|
+
case AnalyticsTool.Other:
|
18235
|
+
default:
|
18236
|
+
console.warn('This site uses an unsupported analytics tool.');
|
18237
|
+
break;
|
18238
|
+
}
|
18239
|
+
if (analyticsTool === AnalyticsTool.Other) {
|
18240
|
+
return;
|
18241
|
+
}
|
18242
|
+
this.localStorage = LocalStorage.getInstance();
|
18243
|
+
}
|
18244
|
+
static getInstance() {
|
18245
|
+
if (!UserMonitor.instance) {
|
18246
|
+
UserMonitor.instance = new UserMonitor();
|
18247
|
+
}
|
18248
|
+
return UserMonitor.instance;
|
18249
|
+
}
|
18250
|
+
start() {
|
18251
|
+
if (!this.implementedMonitor)
|
18252
|
+
return;
|
18253
|
+
this.implementedMonitor.setListener((eventData) => {
|
18254
|
+
var _a;
|
18255
|
+
this.matchAndFireEvent(eventData, (_a = this.localStorage) === null || _a === void 0 ? void 0 : _a.getSpots());
|
18256
|
+
});
|
18257
|
+
this.implementedMonitor.start();
|
18258
|
+
}
|
18259
|
+
matchAndFireEvent(
|
18260
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
18261
|
+
_eventData,
|
18262
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
18263
|
+
_spots) {
|
18264
|
+
// console.info({ eventData, spots });
|
18265
|
+
}
|
18266
|
+
detectAnalyticsTool() {
|
18267
|
+
let analyticsTool = AnalyticsTool.Other;
|
18268
|
+
// Check for Google Analytics
|
18269
|
+
if (typeof window.ga !== 'undefined') {
|
18270
|
+
analyticsTool = AnalyticsTool.GoogleAnalytics;
|
18271
|
+
}
|
18272
|
+
// Check for Google Analytics 4
|
18273
|
+
if (typeof window.gtag !== 'undefined') {
|
18274
|
+
analyticsTool = AnalyticsTool.GoogleAnalytics;
|
18275
|
+
}
|
18276
|
+
// Check for Google Tag Manager
|
18277
|
+
if (typeof window.google_tag_manager !== 'undefined') {
|
18278
|
+
analyticsTool = AnalyticsTool.GoogleAnalytics;
|
18279
|
+
}
|
18280
|
+
// @TODO: Add support for other analytics tools
|
18281
|
+
// Check for Heap Analytics
|
18282
|
+
// Check for Mixpanel
|
18283
|
+
// Check for Woopra
|
18284
|
+
// Check for Segment
|
18285
|
+
// Check for Amplitude
|
18286
|
+
return analyticsTool;
|
18287
|
+
}
|
18288
|
+
}
|
18289
|
+
|
18059
18290
|
class EventService {
|
18060
18291
|
constructor() {
|
18061
18292
|
this.pubSub = PubSub.getInstance();
|
@@ -18063,6 +18294,8 @@ class EventService {
|
|
18063
18294
|
this.activeSpots = new Map();
|
18064
18295
|
this.spotStates = new Map();
|
18065
18296
|
this.intersectionObserver = new IntersectionObserverService();
|
18297
|
+
// Start the user monitor, which will track and check user interactions
|
18298
|
+
UserMonitor.getInstance().start();
|
18066
18299
|
}
|
18067
18300
|
static getInstance() {
|
18068
18301
|
if (!EventService.instance) {
|
@@ -18507,6 +18740,10 @@ class LiquidCommerceRmnClient {
|
|
18507
18740
|
*/
|
18508
18741
|
async injectSpotElement(params) {
|
18509
18742
|
var _a;
|
18743
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
18744
|
+
console.warn('LiquidCommerce Rmn Sdk: Methods which create elements are only available in browser environments.');
|
18745
|
+
return;
|
18746
|
+
}
|
18510
18747
|
const config = params.config;
|
18511
18748
|
let inject = params.inject;
|
18512
18749
|
if (!inject.length) {
|