@liquidcommercedev/rmn-sdk 1.5.0-beta.10 → 1.5.0-beta.11
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.cjs +496 -469
- package/dist/index.esm.js +496 -469
- package/dist/types/common/helpers/event-type.helper.d.ts +8 -0
- package/dist/types/common/helpers/index.d.ts +4 -0
- package/dist/types/common/helpers/utils.helper.d.ts +0 -13
- package/dist/types/enums.d.ts +2 -0
- package/package.json +1 -1
- package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
package/dist/index.esm.js
CHANGED
@@ -65,7 +65,9 @@ var RMN_SPOT_EVENT;
|
|
65
65
|
RMN_SPOT_EVENT["PURCHASE"] = "PURCHASE";
|
66
66
|
RMN_SPOT_EVENT["ADD_TO_CART"] = "ADD_TO_CART";
|
67
67
|
RMN_SPOT_EVENT["REMOVE_FROM_CART"] = "REMOVE_FROM_CART";
|
68
|
+
RMN_SPOT_EVENT["ADD_TO_CART_FROM_DETAILS"] = "ADD_TO_CART_FROM_DETAILS";
|
68
69
|
RMN_SPOT_EVENT["ADD_TO_WISHLIST"] = "ADD_TO_WISHLIST";
|
70
|
+
RMN_SPOT_EVENT["EXPAND_PRODUCT"] = "EXPAND_PRODUCT";
|
69
71
|
RMN_SPOT_EVENT["BUY_NOW"] = "BUY_NOW";
|
70
72
|
})(RMN_SPOT_EVENT || (RMN_SPOT_EVENT = {}));
|
71
73
|
var RMN_ENV;
|
@@ -6543,6 +6545,94 @@ axios.HttpStatusCode = HttpStatusCode;
|
|
6543
6545
|
|
6544
6546
|
axios.default = axios;
|
6545
6547
|
|
6548
|
+
/**
|
6549
|
+
* Keyword patterns for each RMN_SPOT_EVENT.
|
6550
|
+
* Each event type has required keywords that must be present and optional ones.
|
6551
|
+
*
|
6552
|
+
* Note: The order of checks matters - more specific patterns must be checked before general ones
|
6553
|
+
* to avoid incorrect matches.
|
6554
|
+
*/
|
6555
|
+
const EVENT_KEYWORDS = {
|
6556
|
+
[RMN_SPOT_EVENT.ADD_TO_CART_FROM_DETAILS]: {
|
6557
|
+
required: ['add', 'cart'],
|
6558
|
+
optional: ['details', 'detail', 'single', 'profile', 'page', 'pdp'],
|
6559
|
+
},
|
6560
|
+
[RMN_SPOT_EVENT.BUY_NOW]: {
|
6561
|
+
required: ['buy', 'now'],
|
6562
|
+
},
|
6563
|
+
[RMN_SPOT_EVENT.EXPAND_PRODUCT]: {
|
6564
|
+
required: ['product'],
|
6565
|
+
optional: ['details', 'expand', 'modal', 'popup', 'quickview', 'view'],
|
6566
|
+
},
|
6567
|
+
[RMN_SPOT_EVENT.ADD_TO_WISHLIST]: {
|
6568
|
+
required: ['add', 'wishlist'],
|
6569
|
+
},
|
6570
|
+
[RMN_SPOT_EVENT.REMOVE_FROM_CART]: {
|
6571
|
+
required: ['remove', 'cart'],
|
6572
|
+
},
|
6573
|
+
[RMN_SPOT_EVENT.PURCHASE]: {
|
6574
|
+
required: ['purchase'],
|
6575
|
+
},
|
6576
|
+
[RMN_SPOT_EVENT.ADD_TO_CART]: {
|
6577
|
+
required: ['add', 'cart'],
|
6578
|
+
},
|
6579
|
+
};
|
6580
|
+
/**
|
6581
|
+
* Normalizes an event name by converting to lowercase, removing special characters,
|
6582
|
+
* and splitting into words.
|
6583
|
+
*/
|
6584
|
+
function normalizeEventName(event) {
|
6585
|
+
return event
|
6586
|
+
.toLowerCase()
|
6587
|
+
.replace(/[^a-z0-9\s]+/g, ' ') // Replace special chars with spaces
|
6588
|
+
.split(/\s+/) // Split on whitespace
|
6589
|
+
.filter(Boolean); // Remove empty strings
|
6590
|
+
}
|
6591
|
+
/**
|
6592
|
+
* Checks if a word matches a keyword, considering word boundaries.
|
6593
|
+
* This prevents partial word matches (e.g., "card" shouldn't match "cart").
|
6594
|
+
*/
|
6595
|
+
function wordMatchesKeyword(word, keyword) {
|
6596
|
+
// Create a RegExp that matches the keyword as a whole word
|
6597
|
+
const keywordRegex = new RegExp(`^${keyword}s?$|${keyword}s?\\W|\\W${keyword}s?$|\\W${keyword}s?\\W`);
|
6598
|
+
return keywordRegex.test(` ${word} `); // Add spaces to handle word boundaries
|
6599
|
+
}
|
6600
|
+
/**
|
6601
|
+
* Checks if all required keywords and at least one optional keyword (if specified) are present.
|
6602
|
+
*/
|
6603
|
+
function matchesKeywordPattern(words, required, optional) {
|
6604
|
+
// Check if all required keywords are present as whole words
|
6605
|
+
const hasAllRequired = required.every((keyword) => words.some((word) => wordMatchesKeyword(word, keyword)));
|
6606
|
+
if (!hasAllRequired) {
|
6607
|
+
return false;
|
6608
|
+
}
|
6609
|
+
// If no optional keywords are specified, return true
|
6610
|
+
if (!(optional === null || optional === void 0 ? void 0 : optional.length)) {
|
6611
|
+
return true;
|
6612
|
+
}
|
6613
|
+
// If optional keywords exist, check if at least one matches as a whole word
|
6614
|
+
return optional.some((keyword) => words.some((word) => wordMatchesKeyword(word, keyword)));
|
6615
|
+
}
|
6616
|
+
/**
|
6617
|
+
* Determines the event type from a raw event string by checking for keyword patterns.
|
6618
|
+
*
|
6619
|
+
* @param {string} [event] - The raw event string to evaluate
|
6620
|
+
* @returns {RMN_SPOT_EVENT | null} - The corresponding RMN_SPOT_EVENT or null if no match
|
6621
|
+
*/
|
6622
|
+
function getEventTypeFromRawEvent(event) {
|
6623
|
+
if (!(event === null || event === void 0 ? void 0 : event.trim())) {
|
6624
|
+
return null;
|
6625
|
+
}
|
6626
|
+
const words = normalizeEventName(event);
|
6627
|
+
// Use Object.entries to maintain the exact order defined in EVENT_KEYWORDS
|
6628
|
+
for (const [eventType, { required, optional }] of Object.entries(EVENT_KEYWORDS)) {
|
6629
|
+
if (matchesKeywordPattern(words, required, optional)) {
|
6630
|
+
return eventType;
|
6631
|
+
}
|
6632
|
+
}
|
6633
|
+
return null;
|
6634
|
+
}
|
6635
|
+
|
6546
6636
|
class SingletonManager {
|
6547
6637
|
/**
|
6548
6638
|
* Retrieves an instance of the specified class using the provided instance creator function.
|
@@ -6701,12 +6791,319 @@ class ObjectHelper {
|
|
6701
6791
|
*
|
6702
6792
|
* @return {void} - This method does not return any value.
|
6703
6793
|
*/
|
6704
|
-
innerMerge(target, source) {
|
6705
|
-
for (const key of Object.keys(source)) {
|
6706
|
-
target[key] = this.mergeValue(target[key], source[key]);
|
6707
|
-
}
|
6794
|
+
innerMerge(target, source) {
|
6795
|
+
for (const key of Object.keys(source)) {
|
6796
|
+
target[key] = this.mergeValue(target[key], source[key]);
|
6797
|
+
}
|
6798
|
+
}
|
6799
|
+
}
|
6800
|
+
|
6801
|
+
/**
|
6802
|
+
* Recursively extracts ID values from a nested data structure.
|
6803
|
+
* Searches for specified property names and collects their primitive values (strings/numbers).
|
6804
|
+
*
|
6805
|
+
* @param data - The data structure to search through (can be nested objects/arrays)
|
6806
|
+
* @param propertyNames - Array of property names to look for
|
6807
|
+
* @returns Array of extracted ID values (strings/numbers only)
|
6808
|
+
*
|
6809
|
+
* @example
|
6810
|
+
* const data = {
|
6811
|
+
* id: [1, 2, 3],
|
6812
|
+
* nested: { id: 'abc' },
|
6813
|
+
* items: [{ id: 456 }]
|
6814
|
+
* };
|
6815
|
+
* extractDeepIds(data); // Returns [1, 2, 3, 'abc', 456]
|
6816
|
+
*/
|
6817
|
+
function extractDeepIds(data, propertyNames) {
|
6818
|
+
const ids = [];
|
6819
|
+
const defaulPropertyNames = [
|
6820
|
+
'id',
|
6821
|
+
'upc',
|
6822
|
+
'groupingId',
|
6823
|
+
'sku',
|
6824
|
+
'productId',
|
6825
|
+
'item_id',
|
6826
|
+
'isbn',
|
6827
|
+
'asin',
|
6828
|
+
'mpn',
|
6829
|
+
'model_number',
|
6830
|
+
'article_number',
|
6831
|
+
'variant_id',
|
6832
|
+
'item_number',
|
6833
|
+
'catalog_id',
|
6834
|
+
'reference_id',
|
6835
|
+
];
|
6836
|
+
// Set for faster property name lookups
|
6837
|
+
const propertySet = new Set(defaulPropertyNames);
|
6838
|
+
/**
|
6839
|
+
* Processes a value and extracts IDs if it matches criteria
|
6840
|
+
* @param value - The value to process
|
6841
|
+
* @param currentKey - The property name of the current value
|
6842
|
+
*/
|
6843
|
+
const processValue = (value, currentKey) => {
|
6844
|
+
// Early exit for null/undefined values
|
6845
|
+
if (value == null)
|
6846
|
+
return;
|
6847
|
+
// If current key matches our target properties
|
6848
|
+
if (currentKey && propertySet.has(currentKey)) {
|
6849
|
+
if (Array.isArray(value)) {
|
6850
|
+
// Filter and push valid array values in one pass
|
6851
|
+
ids.push(...value.filter((item) => typeof item === 'string' || typeof item === 'number'));
|
6852
|
+
}
|
6853
|
+
else if (typeof value === 'string' || typeof value === 'number') {
|
6854
|
+
ids.push(value);
|
6855
|
+
}
|
6856
|
+
return; // Stop processing this branch after handling the ID
|
6857
|
+
}
|
6858
|
+
// Recursively process nested structures
|
6859
|
+
if (Array.isArray(value)) {
|
6860
|
+
value.forEach((item) => processValue(item));
|
6861
|
+
}
|
6862
|
+
else if (typeof value === 'object') {
|
6863
|
+
// Process all enumerable properties
|
6864
|
+
for (const [key, val] of Object.entries(value)) {
|
6865
|
+
processValue(val, key);
|
6866
|
+
}
|
6867
|
+
}
|
6868
|
+
};
|
6869
|
+
processValue(data);
|
6870
|
+
return ids; // No need to filter nulls as we handle that during collection
|
6871
|
+
}
|
6872
|
+
// Fallback method using fetch if sendBeacon isn't available
|
6873
|
+
async function fallbackEventFire(url) {
|
6874
|
+
try {
|
6875
|
+
const racePromise = Promise.race([
|
6876
|
+
// Promise #1: The fetch request
|
6877
|
+
fetch(url, {
|
6878
|
+
method: 'POST',
|
6879
|
+
keepalive: true,
|
6880
|
+
}),
|
6881
|
+
// Promise #2: The timeout
|
6882
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Request timeout')), 2000)),
|
6883
|
+
]);
|
6884
|
+
/**
|
6885
|
+
* Prevent requests from hanging indefinitely
|
6886
|
+
* Improve user experience by failing fast
|
6887
|
+
* Handle slow network conditions gracefully
|
6888
|
+
* Ensure resources are freed up in a timely manner
|
6889
|
+
*/
|
6890
|
+
const response = await racePromise;
|
6891
|
+
return response.ok;
|
6892
|
+
}
|
6893
|
+
catch (_a) {
|
6894
|
+
return false;
|
6895
|
+
}
|
6896
|
+
}
|
6897
|
+
/**
|
6898
|
+
* Extracts and decodes a URL from a base64-encoded query parameter.
|
6899
|
+
*
|
6900
|
+
* @param {string} url - The URL containing the base64-encoded query parameter.
|
6901
|
+
* @returns {string | null} - The decoded URL or null if not found or invalid.
|
6902
|
+
*/
|
6903
|
+
function getRedirectUrlFromPayload(url) {
|
6904
|
+
try {
|
6905
|
+
const base64String = new URL(url).searchParams.get('e');
|
6906
|
+
if (!base64String) {
|
6907
|
+
return null;
|
6908
|
+
}
|
6909
|
+
const data = JSON.parse(atob(base64String));
|
6910
|
+
return data.ur || null;
|
6911
|
+
}
|
6912
|
+
catch (_a) {
|
6913
|
+
return null;
|
6914
|
+
}
|
6915
|
+
}
|
6916
|
+
/**
|
6917
|
+
* Fires an event using the navigator.sendBeacon method or a fallback method if sendBeacon is not available.
|
6918
|
+
* If the event is a click event and a redirect URL is found, it redirects the user to that URL.
|
6919
|
+
*
|
6920
|
+
* @param {IFireEventParams} params - The parameters for firing the event.
|
6921
|
+
* @param {RMN_SPOT_EVENT} params.event - The event type.
|
6922
|
+
* @param {string} params.eventUrl - The URL to which the event is sent.
|
6923
|
+
* @returns {Promise<void>} - A promise that resolves when the event is fired.
|
6924
|
+
*/
|
6925
|
+
async function fireEvent({ event, eventUrl }) {
|
6926
|
+
var _a;
|
6927
|
+
try {
|
6928
|
+
const didFireEvent = ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.sendBeacon) === null || _a === void 0 ? void 0 : _a.call(navigator, eventUrl)) || (await fallbackEventFire(eventUrl));
|
6929
|
+
if (!didFireEvent) {
|
6930
|
+
return;
|
6931
|
+
}
|
6932
|
+
if (event === RMN_SPOT_EVENT.CLICK) {
|
6933
|
+
const redirectUrl = getRedirectUrlFromPayload(eventUrl);
|
6934
|
+
if (redirectUrl) {
|
6935
|
+
window.location.href = redirectUrl;
|
6936
|
+
}
|
6937
|
+
}
|
6938
|
+
}
|
6939
|
+
catch (_b) {
|
6940
|
+
// Handle errors silently
|
6941
|
+
}
|
6942
|
+
}
|
6943
|
+
function calculateScaleFactor(elementScale) {
|
6944
|
+
// Step 1: Apply square root for non-linear scaling
|
6945
|
+
// This creates a more gradual scaling effect, especially for larger changes
|
6946
|
+
// For example:
|
6947
|
+
// - elementScale of 0.25 (1/4 size) becomes 0.5
|
6948
|
+
// - elementScale of 1 (unchanged) remains 1
|
6949
|
+
// - elementScale of 4 (4x size) becomes 2
|
6950
|
+
const baseFactor = Math.sqrt(elementScale);
|
6951
|
+
// Step 2: Apply additional dampening to further soften the scaling effect
|
6952
|
+
// The dampening factor (0.5) can be adjusted:
|
6953
|
+
// - Lower values (closer to 0) make scaling more subtle
|
6954
|
+
// - Higher values (closer to 1) make scaling more pronounced
|
6955
|
+
const dampening = 0.35;
|
6956
|
+
// Calculate the scaleFactor:
|
6957
|
+
// 1. (baseFactor - 1) represents the change from the original size
|
6958
|
+
// 2. Multiply by dampening to reduce the effect
|
6959
|
+
// 3. Add 1 to center the scaling around the original size
|
6960
|
+
// For example, if baseFactor is 2:
|
6961
|
+
// scaleFactor = 1 + (2 - 1) * 0.5 = 1.5
|
6962
|
+
const scaleFactor = 1 + (baseFactor - 1) * dampening;
|
6963
|
+
// Step 3: Define the allowed range for the scale factor
|
6964
|
+
// This ensures that the font size never changes too drastically
|
6965
|
+
const minScale = 0.35; // Font will never be smaller than 50% of original
|
6966
|
+
const maxScale = 1.5; // Font will never be larger than 150% of original
|
6967
|
+
// Step 4: Clamp the scale factor to the defined range
|
6968
|
+
// Math.min ensures the value doesn't exceed maxScale
|
6969
|
+
// Math.max ensures the value isn't less than minScale
|
6970
|
+
return Math.max(minScale, Math.min(maxScale, scaleFactor));
|
6971
|
+
}
|
6972
|
+
|
6973
|
+
class UniqueIdGenerator {
|
6974
|
+
/**
|
6975
|
+
* Initialize the generator with a node ID
|
6976
|
+
* @param nodeId Number between 0-1023 to identify this instance
|
6977
|
+
*/
|
6978
|
+
static initialize(nodeId = Math.floor(Math.random() * 1024)) {
|
6979
|
+
if (nodeId < 0 || nodeId >= 1 << this.nodeBits) {
|
6980
|
+
throw new Error(`Node ID must be between 0 and ${(1 << this.nodeBits) - 1}`);
|
6981
|
+
}
|
6982
|
+
this.nodeId = nodeId;
|
6983
|
+
}
|
6984
|
+
/**
|
6985
|
+
* Convert a number to base32 string with specified length
|
6986
|
+
*/
|
6987
|
+
static toBase32(num, length) {
|
6988
|
+
let result = '';
|
6989
|
+
while (num > 0) {
|
6990
|
+
result = this.base32Chars[Number(num % BigInt(32))] + result;
|
6991
|
+
// @ts-expect-error - TS doesn't support bigint division
|
6992
|
+
num = num / 32n;
|
6993
|
+
}
|
6994
|
+
return result.padStart(length, '0');
|
6995
|
+
}
|
6996
|
+
/**
|
6997
|
+
* Generate a cryptographically secure random number
|
6998
|
+
*/
|
6999
|
+
static getSecureRandom() {
|
7000
|
+
if (typeof crypto !== 'undefined') {
|
7001
|
+
const buffer = new Uint32Array(1);
|
7002
|
+
crypto.getRandomValues(buffer);
|
7003
|
+
return buffer[0];
|
7004
|
+
}
|
7005
|
+
return Math.floor(Math.random() * 0xffffffff);
|
7006
|
+
}
|
7007
|
+
/**
|
7008
|
+
* Wait until next millisecond
|
7009
|
+
*/
|
7010
|
+
static waitNextMillis(lastTimestamp) {
|
7011
|
+
let timestamp = Date.now();
|
7012
|
+
while (timestamp <= lastTimestamp) {
|
7013
|
+
timestamp = Date.now();
|
7014
|
+
}
|
7015
|
+
return timestamp;
|
7016
|
+
}
|
7017
|
+
/**
|
7018
|
+
* Generates a highly unique ID with the following format:
|
7019
|
+
* TTTTTTTTTTCCCCNNNNNRRRR
|
7020
|
+
* T: Timestamp (10 chars)
|
7021
|
+
* C: Counter (4 chars)
|
7022
|
+
* N: Node ID (5 chars)
|
7023
|
+
* R: Random (4 chars)
|
7024
|
+
*
|
7025
|
+
* Total length: 23 characters, always uppercase alphanumeric
|
7026
|
+
*/
|
7027
|
+
static generate() {
|
7028
|
+
if (this.nodeId === undefined) {
|
7029
|
+
this.initialize();
|
7030
|
+
}
|
7031
|
+
let timestamp = Date.now() - this.epoch;
|
7032
|
+
// Handle clock moving backwards or same millisecond
|
7033
|
+
if (timestamp < this.lastTimestamp) {
|
7034
|
+
throw new Error('Clock moved backwards. Refusing to generate ID.');
|
7035
|
+
}
|
7036
|
+
if (timestamp === this.lastTimestamp) {
|
7037
|
+
this.sequence = (this.sequence + 1) & ((1 << this.sequenceBits) - 1);
|
7038
|
+
if (this.sequence === 0) {
|
7039
|
+
timestamp = this.waitNextMillis(this.lastTimestamp);
|
7040
|
+
}
|
7041
|
+
}
|
7042
|
+
else {
|
7043
|
+
this.sequence = 0;
|
7044
|
+
}
|
7045
|
+
this.lastTimestamp = timestamp;
|
7046
|
+
// Generate random component
|
7047
|
+
const random = this.getSecureRandom() & 0xffff; // 16 bits of randomness
|
7048
|
+
// Combine all components into a BigInt
|
7049
|
+
// const id =
|
7050
|
+
// (BigInt(timestamp) << BigInt(this.nodeBits + this.sequenceBits + 16)) |
|
7051
|
+
// (BigInt(this.nodeId) << BigInt(this.sequenceBits + 16)) |
|
7052
|
+
// (BigInt(this.sequence) << BigInt(16)) |
|
7053
|
+
// BigInt(random);
|
7054
|
+
// Convert to base32 representation
|
7055
|
+
const timeComponent = this.toBase32(BigInt(timestamp), 10);
|
7056
|
+
const counterComponent = this.toBase32(BigInt(this.sequence), 4);
|
7057
|
+
const nodeComponent = this.toBase32(BigInt(this.nodeId), 5);
|
7058
|
+
const randomComponent = this.toBase32(BigInt(random), 4);
|
7059
|
+
return `${timeComponent}${counterComponent}${nodeComponent}${randomComponent}`;
|
7060
|
+
}
|
7061
|
+
/**
|
7062
|
+
* Validates if a string matches the expected ID format
|
7063
|
+
*/
|
7064
|
+
static isValid(id) {
|
7065
|
+
if (!/^[0-9A-HJ-NP-Z]{23}$/.test(id))
|
7066
|
+
return false;
|
7067
|
+
try {
|
7068
|
+
const timeComponent = id.slice(0, 10);
|
7069
|
+
const timestamp = this.decodeBase32(timeComponent);
|
7070
|
+
const now = Date.now() - this.epoch;
|
7071
|
+
return timestamp >= 0 && timestamp <= now;
|
7072
|
+
}
|
7073
|
+
catch (_a) {
|
7074
|
+
return false;
|
7075
|
+
}
|
7076
|
+
}
|
7077
|
+
/**
|
7078
|
+
* Decode base32 string to number
|
7079
|
+
*/
|
7080
|
+
static decodeBase32(str) {
|
7081
|
+
let result = 0;
|
7082
|
+
for (const char of str) {
|
7083
|
+
result = result * 32 + this.base32Chars.indexOf(char);
|
7084
|
+
}
|
7085
|
+
return result;
|
7086
|
+
}
|
7087
|
+
/**
|
7088
|
+
* Extract timestamp from ID
|
7089
|
+
*/
|
7090
|
+
static getTimestamp(id) {
|
7091
|
+
if (!this.isValid(id))
|
7092
|
+
throw new Error('Invalid ID format');
|
7093
|
+
const timeComponent = id.slice(0, 10);
|
7094
|
+
const timestamp = this.decodeBase32(timeComponent);
|
7095
|
+
return new Date(timestamp + this.epoch);
|
6708
7096
|
}
|
6709
7097
|
}
|
7098
|
+
// Constants for bit manipulation
|
7099
|
+
UniqueIdGenerator.epoch = 1577836800000; // 2020-01-01 as epoch
|
7100
|
+
UniqueIdGenerator.nodeBits = 10;
|
7101
|
+
UniqueIdGenerator.sequenceBits = 12;
|
7102
|
+
// Instance variables
|
7103
|
+
UniqueIdGenerator.lastTimestamp = -1;
|
7104
|
+
UniqueIdGenerator.sequence = 0;
|
7105
|
+
// Character set for base32 encoding (excluding similar looking characters)
|
7106
|
+
UniqueIdGenerator.base32Chars = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
6710
7107
|
|
6711
7108
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
6712
7109
|
|
@@ -15580,301 +15977,100 @@ class BaseApi extends BaseApiAbstract {
|
|
15580
15977
|
let timestamp = 0;
|
15581
15978
|
if ((response === null || response === void 0 ? void 0 : response.headers) &&
|
15582
15979
|
((_a = response === null || response === void 0 ? void 0 : response.headers) === null || _a === void 0 ? void 0 : _a.has) &&
|
15583
|
-
((_b = response === null || response === void 0 ? void 0 : response.headers) === null || _b === void 0 ? void 0 : _b.has(REQUEST_CLOUD_PROTECTED_KEY)) &&
|
15584
|
-
((_c = response === null || response === void 0 ? void 0 : response.headers) === null || _c === void 0 ? void 0 : _c.has(REQUEST_CLOUD_PROTECTED_TIMESTAMP)) &&
|
15585
|
-
((_d = response === null || response === void 0 ? void 0 : response.headers) === null || _d === void 0 ? void 0 : _d.get)) {
|
15586
|
-
isEncrypted = ((_e = response === null || response === void 0 ? void 0 : response.headers) === null || _e === void 0 ? void 0 : _e.get(REQUEST_CLOUD_PROTECTED_KEY)) === 'true';
|
15587
|
-
timestamp = ((_f = response === null || response === void 0 ? void 0 : response.headers) === null || _f === void 0 ? void 0 : _f.get(REQUEST_CLOUD_PROTECTED_TIMESTAMP))
|
15588
|
-
? Number((_g = response === null || response === void 0 ? void 0 : response.headers) === null || _g === void 0 ? void 0 : _g.get(REQUEST_CLOUD_PROTECTED_TIMESTAMP))
|
15589
|
-
: 0;
|
15590
|
-
}
|
15591
|
-
if (responseData &&
|
15592
|
-
isEncrypted &&
|
15593
|
-
this.objectHelper.includes(responseData, 't') &&
|
15594
|
-
timestamp > 0) {
|
15595
|
-
const { t: encryptedPayload } = responseData;
|
15596
|
-
const decryptedData = await this.encryptedApi.handleDecryption(encryptedPayload, timestamp);
|
15597
|
-
if (decryptedData === null || decryptedData === void 0 ? void 0 : decryptedData.payload) {
|
15598
|
-
delete decryptedData.payload.exp;
|
15599
|
-
delete decryptedData.payload.iat;
|
15600
|
-
responseData = decryptedData.payload;
|
15601
|
-
}
|
15602
|
-
}
|
15603
|
-
return { isOk: true, val: responseData, isErr: false };
|
15604
|
-
}
|
15605
|
-
/**
|
15606
|
-
* Creates a URL by concatenating the base URL with the provided path.
|
15607
|
-
*
|
15608
|
-
* @param {string | null} path - The path to be appended to the base URL.
|
15609
|
-
* @return {string} The concatenated URL.
|
15610
|
-
*/
|
15611
|
-
createURL(path) {
|
15612
|
-
const formattedPath = path && path[0] !== '/' ? `/${path}` : path;
|
15613
|
-
return `${this.baseUrl}/api${formattedPath}`;
|
15614
|
-
}
|
15615
|
-
}
|
15616
|
-
|
15617
|
-
const AUTH_API_PATH = '/auth';
|
15618
|
-
|
15619
|
-
class AuthService extends BaseApi {
|
15620
|
-
constructor(apiKey, env) {
|
15621
|
-
super({
|
15622
|
-
authenticated: false,
|
15623
|
-
apiKey,
|
15624
|
-
token: '',
|
15625
|
-
env,
|
15626
|
-
});
|
15627
|
-
}
|
15628
|
-
/**
|
15629
|
-
* Retrieves the singleton instance of the AuthService class.
|
15630
|
-
*
|
15631
|
-
* @param {string} apiKey - The API key used for authentication.
|
15632
|
-
* @param {RMN_ENV} env - The environment enum value.
|
15633
|
-
* @returns {AuthService} The singleton instance of the AuthService class.
|
15634
|
-
*/
|
15635
|
-
static getInstance(apiKey, env) {
|
15636
|
-
return SingletonManager.getInstance('AuthService', () => new AuthService(apiKey, env));
|
15637
|
-
}
|
15638
|
-
/**
|
15639
|
-
* Initializes the authentication process.
|
15640
|
-
*
|
15641
|
-
* @returns {Promise<IAuthCredentials>} A Promise that resolves to the authenticated credentials.
|
15642
|
-
* @throws {Error} If there is an error during authentication or the authentication response is unsuccessful.
|
15643
|
-
*/
|
15644
|
-
async initialize() {
|
15645
|
-
const { isOk, isErr, val } = await this.get(AUTH_API_PATH, {
|
15646
|
-
headers: {
|
15647
|
-
[SDK_CONFIG.apiHeader]: this.authInfo.apiKey,
|
15648
|
-
},
|
15649
|
-
});
|
15650
|
-
if (isErr) {
|
15651
|
-
throw new Error(`There was an error during authentication: (${isErr === null || isErr === void 0 ? void 0 : isErr.errorMessage})`);
|
15652
|
-
}
|
15653
|
-
if (isOk && (val === null || val === void 0 ? void 0 : val.data.token)) {
|
15654
|
-
this.authInfo.token = val.data.token;
|
15655
|
-
this.authInfo.authenticated = true;
|
15656
|
-
}
|
15657
|
-
else {
|
15658
|
-
throw new Error('Auth response was not successful');
|
15659
|
-
}
|
15660
|
-
return this.authInfo;
|
15661
|
-
}
|
15662
|
-
}
|
15663
|
-
|
15664
|
-
const SPOT_ELEMENT_TAG = 'spot-element';
|
15665
|
-
const CAROUSEL_ELEMENT_TAG = 'spot-carousel-element';
|
15666
|
-
const GFONT_PRECONNECT = `
|
15667
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
15668
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
15669
|
-
`;
|
15670
|
-
const GFONT_SOURCE_SANS_3 = `
|
15671
|
-
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap">
|
15672
|
-
`;
|
15673
|
-
const GFONT_CORMORANT = `
|
15674
|
-
<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">
|
15675
|
-
`;
|
15676
|
-
|
15677
|
-
/**
|
15678
|
-
* Determines the event type from a raw event string.
|
15679
|
-
*
|
15680
|
-
* @param {string} [event] - The raw event string to evaluate.
|
15681
|
-
* @returns {RMN_SPOT_EVENT | null} - The corresponding RMN_SPOT_EVENT or null if no match is found.
|
15682
|
-
*/
|
15683
|
-
function getEventTypeFromRawEvent(event) {
|
15684
|
-
if (!event) {
|
15685
|
-
return null;
|
15686
|
-
}
|
15687
|
-
if (event.includes('cart')) {
|
15688
|
-
if (event.includes('add')) {
|
15689
|
-
return RMN_SPOT_EVENT.ADD_TO_CART;
|
15690
|
-
}
|
15691
|
-
if (event.includes('remove')) {
|
15692
|
-
return RMN_SPOT_EVENT.REMOVE_FROM_CART;
|
15693
|
-
}
|
15694
|
-
}
|
15695
|
-
if (event.includes('purchase')) {
|
15696
|
-
return RMN_SPOT_EVENT.PURCHASE;
|
15697
|
-
}
|
15698
|
-
// if(event.includes('refund')) {
|
15699
|
-
// return RMN_SPOT_EVENT.REFUND;
|
15700
|
-
// }
|
15701
|
-
if (event.includes('wishlist') && event.includes('add')) {
|
15702
|
-
return RMN_SPOT_EVENT.ADD_TO_WISHLIST;
|
15703
|
-
}
|
15704
|
-
return null;
|
15705
|
-
}
|
15706
|
-
/**
|
15707
|
-
* Recursively extracts ID values from a nested data structure.
|
15708
|
-
* Searches for specified property names and collects their primitive values (strings/numbers).
|
15709
|
-
*
|
15710
|
-
* @param data - The data structure to search through (can be nested objects/arrays)
|
15711
|
-
* @param propertyNames - Array of property names to look for
|
15712
|
-
* @returns Array of extracted ID values (strings/numbers only)
|
15713
|
-
*
|
15714
|
-
* @example
|
15715
|
-
* const data = {
|
15716
|
-
* id: [1, 2, 3],
|
15717
|
-
* nested: { id: 'abc' },
|
15718
|
-
* items: [{ id: 456 }]
|
15719
|
-
* };
|
15720
|
-
* extractDeepIds(data); // Returns [1, 2, 3, 'abc', 456]
|
15721
|
-
*/
|
15722
|
-
function extractDeepIds(data, propertyNames) {
|
15723
|
-
const ids = [];
|
15724
|
-
const defaulPropertyNames = [
|
15725
|
-
'id',
|
15726
|
-
'upc',
|
15727
|
-
'groupingId',
|
15728
|
-
'sku',
|
15729
|
-
'productId',
|
15730
|
-
'item_id',
|
15731
|
-
'isbn',
|
15732
|
-
'asin',
|
15733
|
-
'mpn',
|
15734
|
-
'model_number',
|
15735
|
-
'article_number',
|
15736
|
-
'variant_id',
|
15737
|
-
'item_number',
|
15738
|
-
'catalog_id',
|
15739
|
-
'reference_id',
|
15740
|
-
];
|
15741
|
-
// Set for faster property name lookups
|
15742
|
-
const propertySet = new Set(defaulPropertyNames);
|
15743
|
-
/**
|
15744
|
-
* Processes a value and extracts IDs if it matches criteria
|
15745
|
-
* @param value - The value to process
|
15746
|
-
* @param currentKey - The property name of the current value
|
15747
|
-
*/
|
15748
|
-
const processValue = (value, currentKey) => {
|
15749
|
-
// Early exit for null/undefined values
|
15750
|
-
if (value == null)
|
15751
|
-
return;
|
15752
|
-
// If current key matches our target properties
|
15753
|
-
if (currentKey && propertySet.has(currentKey)) {
|
15754
|
-
if (Array.isArray(value)) {
|
15755
|
-
// Filter and push valid array values in one pass
|
15756
|
-
ids.push(...value.filter((item) => typeof item === 'string' || typeof item === 'number'));
|
15757
|
-
}
|
15758
|
-
else if (typeof value === 'string' || typeof value === 'number') {
|
15759
|
-
ids.push(value);
|
15760
|
-
}
|
15761
|
-
return; // Stop processing this branch after handling the ID
|
15762
|
-
}
|
15763
|
-
// Recursively process nested structures
|
15764
|
-
if (Array.isArray(value)) {
|
15765
|
-
value.forEach((item) => processValue(item));
|
15766
|
-
}
|
15767
|
-
else if (typeof value === 'object') {
|
15768
|
-
// Process all enumerable properties
|
15769
|
-
for (const [key, val] of Object.entries(value)) {
|
15770
|
-
processValue(val, key);
|
15771
|
-
}
|
15772
|
-
}
|
15773
|
-
};
|
15774
|
-
processValue(data);
|
15775
|
-
return ids; // No need to filter nulls as we handle that during collection
|
15776
|
-
}
|
15777
|
-
// Fallback method using fetch if sendBeacon isn't available
|
15778
|
-
async function fallbackEventFire(url) {
|
15779
|
-
try {
|
15780
|
-
const racePromise = Promise.race([
|
15781
|
-
// Promise #1: The fetch request
|
15782
|
-
fetch(url, {
|
15783
|
-
method: 'POST',
|
15784
|
-
keepalive: true,
|
15785
|
-
}),
|
15786
|
-
// Promise #2: The timeout
|
15787
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error('Request timeout')), 2000)),
|
15788
|
-
]);
|
15789
|
-
/**
|
15790
|
-
* Prevent requests from hanging indefinitely
|
15791
|
-
* Improve user experience by failing fast
|
15792
|
-
* Handle slow network conditions gracefully
|
15793
|
-
* Ensure resources are freed up in a timely manner
|
15794
|
-
*/
|
15795
|
-
const response = await racePromise;
|
15796
|
-
return response.ok;
|
15797
|
-
}
|
15798
|
-
catch (_a) {
|
15799
|
-
return false;
|
15800
|
-
}
|
15801
|
-
}
|
15802
|
-
/**
|
15803
|
-
* Extracts and decodes a URL from a base64-encoded query parameter.
|
15804
|
-
*
|
15805
|
-
* @param {string} url - The URL containing the base64-encoded query parameter.
|
15806
|
-
* @returns {string | null} - The decoded URL or null if not found or invalid.
|
15807
|
-
*/
|
15808
|
-
function getRedirectUrlFromPayload(url) {
|
15809
|
-
try {
|
15810
|
-
const base64String = new URL(url).searchParams.get('e');
|
15811
|
-
if (!base64String) {
|
15812
|
-
return null;
|
15813
|
-
}
|
15814
|
-
const data = JSON.parse(atob(base64String));
|
15815
|
-
return data.ur || null;
|
15816
|
-
}
|
15817
|
-
catch (_a) {
|
15818
|
-
return null;
|
15819
|
-
}
|
15820
|
-
}
|
15821
|
-
/**
|
15822
|
-
* Fires an event using the navigator.sendBeacon method or a fallback method if sendBeacon is not available.
|
15823
|
-
* If the event is a click event and a redirect URL is found, it redirects the user to that URL.
|
15824
|
-
*
|
15825
|
-
* @param {IFireEventParams} params - The parameters for firing the event.
|
15826
|
-
* @param {RMN_SPOT_EVENT} params.event - The event type.
|
15827
|
-
* @param {string} params.eventUrl - The URL to which the event is sent.
|
15828
|
-
* @returns {Promise<void>} - A promise that resolves when the event is fired.
|
15829
|
-
*/
|
15830
|
-
async function fireEvent({ event, eventUrl }) {
|
15831
|
-
var _a;
|
15832
|
-
try {
|
15833
|
-
const didFireEvent = ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.sendBeacon) === null || _a === void 0 ? void 0 : _a.call(navigator, eventUrl)) || (await fallbackEventFire(eventUrl));
|
15834
|
-
if (!didFireEvent) {
|
15835
|
-
return;
|
15980
|
+
((_b = response === null || response === void 0 ? void 0 : response.headers) === null || _b === void 0 ? void 0 : _b.has(REQUEST_CLOUD_PROTECTED_KEY)) &&
|
15981
|
+
((_c = response === null || response === void 0 ? void 0 : response.headers) === null || _c === void 0 ? void 0 : _c.has(REQUEST_CLOUD_PROTECTED_TIMESTAMP)) &&
|
15982
|
+
((_d = response === null || response === void 0 ? void 0 : response.headers) === null || _d === void 0 ? void 0 : _d.get)) {
|
15983
|
+
isEncrypted = ((_e = response === null || response === void 0 ? void 0 : response.headers) === null || _e === void 0 ? void 0 : _e.get(REQUEST_CLOUD_PROTECTED_KEY)) === 'true';
|
15984
|
+
timestamp = ((_f = response === null || response === void 0 ? void 0 : response.headers) === null || _f === void 0 ? void 0 : _f.get(REQUEST_CLOUD_PROTECTED_TIMESTAMP))
|
15985
|
+
? Number((_g = response === null || response === void 0 ? void 0 : response.headers) === null || _g === void 0 ? void 0 : _g.get(REQUEST_CLOUD_PROTECTED_TIMESTAMP))
|
15986
|
+
: 0;
|
15836
15987
|
}
|
15837
|
-
if (
|
15838
|
-
|
15839
|
-
|
15840
|
-
|
15988
|
+
if (responseData &&
|
15989
|
+
isEncrypted &&
|
15990
|
+
this.objectHelper.includes(responseData, 't') &&
|
15991
|
+
timestamp > 0) {
|
15992
|
+
const { t: encryptedPayload } = responseData;
|
15993
|
+
const decryptedData = await this.encryptedApi.handleDecryption(encryptedPayload, timestamp);
|
15994
|
+
if (decryptedData === null || decryptedData === void 0 ? void 0 : decryptedData.payload) {
|
15995
|
+
delete decryptedData.payload.exp;
|
15996
|
+
delete decryptedData.payload.iat;
|
15997
|
+
responseData = decryptedData.payload;
|
15841
15998
|
}
|
15842
15999
|
}
|
16000
|
+
return { isOk: true, val: responseData, isErr: false };
|
15843
16001
|
}
|
15844
|
-
|
15845
|
-
|
16002
|
+
/**
|
16003
|
+
* Creates a URL by concatenating the base URL with the provided path.
|
16004
|
+
*
|
16005
|
+
* @param {string | null} path - The path to be appended to the base URL.
|
16006
|
+
* @return {string} The concatenated URL.
|
16007
|
+
*/
|
16008
|
+
createURL(path) {
|
16009
|
+
const formattedPath = path && path[0] !== '/' ? `/${path}` : path;
|
16010
|
+
return `${this.baseUrl}/api${formattedPath}`;
|
15846
16011
|
}
|
15847
16012
|
}
|
15848
|
-
|
15849
|
-
|
15850
|
-
|
15851
|
-
|
15852
|
-
|
15853
|
-
|
15854
|
-
|
15855
|
-
|
15856
|
-
|
15857
|
-
|
15858
|
-
|
15859
|
-
|
15860
|
-
|
15861
|
-
|
15862
|
-
|
15863
|
-
|
15864
|
-
|
15865
|
-
|
15866
|
-
|
15867
|
-
|
15868
|
-
|
15869
|
-
|
15870
|
-
|
15871
|
-
|
15872
|
-
|
15873
|
-
|
15874
|
-
|
15875
|
-
|
16013
|
+
|
16014
|
+
const AUTH_API_PATH = '/auth';
|
16015
|
+
|
16016
|
+
class AuthService extends BaseApi {
|
16017
|
+
constructor(apiKey, env) {
|
16018
|
+
super({
|
16019
|
+
authenticated: false,
|
16020
|
+
apiKey,
|
16021
|
+
token: '',
|
16022
|
+
env,
|
16023
|
+
});
|
16024
|
+
}
|
16025
|
+
/**
|
16026
|
+
* Retrieves the singleton instance of the AuthService class.
|
16027
|
+
*
|
16028
|
+
* @param {string} apiKey - The API key used for authentication.
|
16029
|
+
* @param {RMN_ENV} env - The environment enum value.
|
16030
|
+
* @returns {AuthService} The singleton instance of the AuthService class.
|
16031
|
+
*/
|
16032
|
+
static getInstance(apiKey, env) {
|
16033
|
+
return SingletonManager.getInstance('AuthService', () => new AuthService(apiKey, env));
|
16034
|
+
}
|
16035
|
+
/**
|
16036
|
+
* Initializes the authentication process.
|
16037
|
+
*
|
16038
|
+
* @returns {Promise<IAuthCredentials>} A Promise that resolves to the authenticated credentials.
|
16039
|
+
* @throws {Error} If there is an error during authentication or the authentication response is unsuccessful.
|
16040
|
+
*/
|
16041
|
+
async initialize() {
|
16042
|
+
const { isOk, isErr, val } = await this.get(AUTH_API_PATH, {
|
16043
|
+
headers: {
|
16044
|
+
[SDK_CONFIG.apiHeader]: this.authInfo.apiKey,
|
16045
|
+
},
|
16046
|
+
});
|
16047
|
+
if (isErr) {
|
16048
|
+
throw new Error(`There was an error during authentication: (${isErr === null || isErr === void 0 ? void 0 : isErr.errorMessage})`);
|
16049
|
+
}
|
16050
|
+
if (isOk && (val === null || val === void 0 ? void 0 : val.data.token)) {
|
16051
|
+
this.authInfo.token = val.data.token;
|
16052
|
+
this.authInfo.authenticated = true;
|
16053
|
+
}
|
16054
|
+
else {
|
16055
|
+
throw new Error('Auth response was not successful');
|
16056
|
+
}
|
16057
|
+
return this.authInfo;
|
16058
|
+
}
|
15876
16059
|
}
|
15877
16060
|
|
16061
|
+
const SPOT_ELEMENT_TAG = 'spot-element';
|
16062
|
+
const CAROUSEL_ELEMENT_TAG = 'spot-carousel-element';
|
16063
|
+
const GFONT_PRECONNECT = `
|
16064
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
16065
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
16066
|
+
`;
|
16067
|
+
const GFONT_SOURCE_SANS_3 = `
|
16068
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap">
|
16069
|
+
`;
|
16070
|
+
const GFONT_CORMORANT = `
|
16071
|
+
<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">
|
16072
|
+
`;
|
16073
|
+
|
15878
16074
|
class IntersectionObserverService {
|
15879
16075
|
constructor(defaultOptions = {}) {
|
15880
16076
|
this.observers = new Map();
|
@@ -16865,141 +17061,6 @@ class ElementService {
|
|
16865
17061
|
}
|
16866
17062
|
}
|
16867
17063
|
|
16868
|
-
class UniqueIdGenerator {
|
16869
|
-
/**
|
16870
|
-
* Initialize the generator with a node ID
|
16871
|
-
* @param nodeId Number between 0-1023 to identify this instance
|
16872
|
-
*/
|
16873
|
-
static initialize(nodeId = Math.floor(Math.random() * 1024)) {
|
16874
|
-
if (nodeId < 0 || nodeId >= 1 << this.nodeBits) {
|
16875
|
-
throw new Error(`Node ID must be between 0 and ${(1 << this.nodeBits) - 1}`);
|
16876
|
-
}
|
16877
|
-
this.nodeId = nodeId;
|
16878
|
-
}
|
16879
|
-
/**
|
16880
|
-
* Convert a number to base32 string with specified length
|
16881
|
-
*/
|
16882
|
-
static toBase32(num, length) {
|
16883
|
-
let result = '';
|
16884
|
-
while (num > 0) {
|
16885
|
-
result = this.base32Chars[Number(num % BigInt(32))] + result;
|
16886
|
-
// @ts-expect-error - TS doesn't support bigint division
|
16887
|
-
num = num / 32n;
|
16888
|
-
}
|
16889
|
-
return result.padStart(length, '0');
|
16890
|
-
}
|
16891
|
-
/**
|
16892
|
-
* Generate a cryptographically secure random number
|
16893
|
-
*/
|
16894
|
-
static getSecureRandom() {
|
16895
|
-
if (typeof crypto !== 'undefined') {
|
16896
|
-
const buffer = new Uint32Array(1);
|
16897
|
-
crypto.getRandomValues(buffer);
|
16898
|
-
return buffer[0];
|
16899
|
-
}
|
16900
|
-
return Math.floor(Math.random() * 0xffffffff);
|
16901
|
-
}
|
16902
|
-
/**
|
16903
|
-
* Wait until next millisecond
|
16904
|
-
*/
|
16905
|
-
static waitNextMillis(lastTimestamp) {
|
16906
|
-
let timestamp = Date.now();
|
16907
|
-
while (timestamp <= lastTimestamp) {
|
16908
|
-
timestamp = Date.now();
|
16909
|
-
}
|
16910
|
-
return timestamp;
|
16911
|
-
}
|
16912
|
-
/**
|
16913
|
-
* Generates a highly unique ID with the following format:
|
16914
|
-
* TTTTTTTTTTCCCCNNNNNRRRR
|
16915
|
-
* T: Timestamp (10 chars)
|
16916
|
-
* C: Counter (4 chars)
|
16917
|
-
* N: Node ID (5 chars)
|
16918
|
-
* R: Random (4 chars)
|
16919
|
-
*
|
16920
|
-
* Total length: 23 characters, always uppercase alphanumeric
|
16921
|
-
*/
|
16922
|
-
static generate() {
|
16923
|
-
if (this.nodeId === undefined) {
|
16924
|
-
this.initialize();
|
16925
|
-
}
|
16926
|
-
let timestamp = Date.now() - this.epoch;
|
16927
|
-
// Handle clock moving backwards or same millisecond
|
16928
|
-
if (timestamp < this.lastTimestamp) {
|
16929
|
-
throw new Error('Clock moved backwards. Refusing to generate ID.');
|
16930
|
-
}
|
16931
|
-
if (timestamp === this.lastTimestamp) {
|
16932
|
-
this.sequence = (this.sequence + 1) & ((1 << this.sequenceBits) - 1);
|
16933
|
-
if (this.sequence === 0) {
|
16934
|
-
timestamp = this.waitNextMillis(this.lastTimestamp);
|
16935
|
-
}
|
16936
|
-
}
|
16937
|
-
else {
|
16938
|
-
this.sequence = 0;
|
16939
|
-
}
|
16940
|
-
this.lastTimestamp = timestamp;
|
16941
|
-
// Generate random component
|
16942
|
-
const random = this.getSecureRandom() & 0xffff; // 16 bits of randomness
|
16943
|
-
// Combine all components into a BigInt
|
16944
|
-
// const id =
|
16945
|
-
// (BigInt(timestamp) << BigInt(this.nodeBits + this.sequenceBits + 16)) |
|
16946
|
-
// (BigInt(this.nodeId) << BigInt(this.sequenceBits + 16)) |
|
16947
|
-
// (BigInt(this.sequence) << BigInt(16)) |
|
16948
|
-
// BigInt(random);
|
16949
|
-
// Convert to base32 representation
|
16950
|
-
const timeComponent = this.toBase32(BigInt(timestamp), 10);
|
16951
|
-
const counterComponent = this.toBase32(BigInt(this.sequence), 4);
|
16952
|
-
const nodeComponent = this.toBase32(BigInt(this.nodeId), 5);
|
16953
|
-
const randomComponent = this.toBase32(BigInt(random), 4);
|
16954
|
-
return `${timeComponent}${counterComponent}${nodeComponent}${randomComponent}`;
|
16955
|
-
}
|
16956
|
-
/**
|
16957
|
-
* Validates if a string matches the expected ID format
|
16958
|
-
*/
|
16959
|
-
static isValid(id) {
|
16960
|
-
if (!/^[0-9A-HJ-NP-Z]{23}$/.test(id))
|
16961
|
-
return false;
|
16962
|
-
try {
|
16963
|
-
const timeComponent = id.slice(0, 10);
|
16964
|
-
const timestamp = this.decodeBase32(timeComponent);
|
16965
|
-
const now = Date.now() - this.epoch;
|
16966
|
-
return timestamp >= 0 && timestamp <= now;
|
16967
|
-
}
|
16968
|
-
catch (_a) {
|
16969
|
-
return false;
|
16970
|
-
}
|
16971
|
-
}
|
16972
|
-
/**
|
16973
|
-
* Decode base32 string to number
|
16974
|
-
*/
|
16975
|
-
static decodeBase32(str) {
|
16976
|
-
let result = 0;
|
16977
|
-
for (const char of str) {
|
16978
|
-
result = result * 32 + this.base32Chars.indexOf(char);
|
16979
|
-
}
|
16980
|
-
return result;
|
16981
|
-
}
|
16982
|
-
/**
|
16983
|
-
* Extract timestamp from ID
|
16984
|
-
*/
|
16985
|
-
static getTimestamp(id) {
|
16986
|
-
if (!this.isValid(id))
|
16987
|
-
throw new Error('Invalid ID format');
|
16988
|
-
const timeComponent = id.slice(0, 10);
|
16989
|
-
const timestamp = this.decodeBase32(timeComponent);
|
16990
|
-
return new Date(timestamp + this.epoch);
|
16991
|
-
}
|
16992
|
-
}
|
16993
|
-
// Constants for bit manipulation
|
16994
|
-
UniqueIdGenerator.epoch = 1577836800000; // 2020-01-01 as epoch
|
16995
|
-
UniqueIdGenerator.nodeBits = 10;
|
16996
|
-
UniqueIdGenerator.sequenceBits = 12;
|
16997
|
-
// Instance variables
|
16998
|
-
UniqueIdGenerator.lastTimestamp = -1;
|
16999
|
-
UniqueIdGenerator.sequence = 0;
|
17000
|
-
// Character set for base32 encoding (excluding similar looking characters)
|
17001
|
-
UniqueIdGenerator.base32Chars = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
17002
|
-
|
17003
17064
|
function convertHexToRgba(hex, opacity = 1) {
|
17004
17065
|
// Remove # if present
|
17005
17066
|
const cleanHex = hex.replace('#', '');
|
@@ -18882,7 +18943,7 @@ class MonitorService {
|
|
18882
18943
|
this.implementedMonitor.start();
|
18883
18944
|
}
|
18884
18945
|
async matchAndFireEvent(eventData, spots) {
|
18885
|
-
var _a, _b
|
18946
|
+
var _a, _b;
|
18886
18947
|
if (!spots)
|
18887
18948
|
return;
|
18888
18949
|
const eventProductIds = new Set(eventData.productIds);
|
@@ -18891,47 +18952,13 @@ class MonitorService {
|
|
18891
18952
|
continue;
|
18892
18953
|
const hasCommonProductIds = spot.productIds.find((productId) => eventProductIds.has(productId));
|
18893
18954
|
if (hasCommonProductIds) {
|
18894
|
-
|
18895
|
-
|
18896
|
-
|
18897
|
-
|
18898
|
-
|
18899
|
-
|
18900
|
-
|
18901
|
-
});
|
18902
|
-
break;
|
18903
|
-
case RMN_SPOT_EVENT.REMOVE_FROM_CART:
|
18904
|
-
await this.fireAndPublishSpotEvent({
|
18905
|
-
spotEvent: RMN_SPOT_EVENT.REMOVE_FROM_CART,
|
18906
|
-
eventUrl: (_d = (_c = spot.events.find((event) => event.event === RMN_SPOT_EVENT.REMOVE_FROM_CART)) === null || _c === void 0 ? void 0 : _c.url) !== null && _d !== void 0 ? _d : '',
|
18907
|
-
placementId: spot.placementId,
|
18908
|
-
spotId: spot.spotId,
|
18909
|
-
});
|
18910
|
-
break;
|
18911
|
-
case RMN_SPOT_EVENT.PURCHASE:
|
18912
|
-
await this.fireAndPublishSpotEvent({
|
18913
|
-
spotEvent: RMN_SPOT_EVENT.PURCHASE,
|
18914
|
-
eventUrl: (_f = (_e = spot.events.find((event) => event.event === RMN_SPOT_EVENT.PURCHASE)) === null || _e === void 0 ? void 0 : _e.url) !== null && _f !== void 0 ? _f : '',
|
18915
|
-
placementId: spot.placementId,
|
18916
|
-
spotId: spot.spotId,
|
18917
|
-
});
|
18918
|
-
break;
|
18919
|
-
case RMN_SPOT_EVENT.ADD_TO_WISHLIST:
|
18920
|
-
await this.fireAndPublishSpotEvent({
|
18921
|
-
spotEvent: RMN_SPOT_EVENT.ADD_TO_WISHLIST,
|
18922
|
-
eventUrl: (_h = (_g = spot.events.find((event) => event.event === RMN_SPOT_EVENT.ADD_TO_WISHLIST)) === null || _g === void 0 ? void 0 : _g.url) !== null && _h !== void 0 ? _h : '',
|
18923
|
-
placementId: spot.placementId,
|
18924
|
-
spotId: spot.spotId,
|
18925
|
-
});
|
18926
|
-
break;
|
18927
|
-
case RMN_SPOT_EVENT.BUY_NOW:
|
18928
|
-
await this.fireAndPublishSpotEvent({
|
18929
|
-
spotEvent: RMN_SPOT_EVENT.BUY_NOW,
|
18930
|
-
eventUrl: (_k = (_j = spot.events.find((event) => event.event === RMN_SPOT_EVENT.BUY_NOW)) === null || _j === void 0 ? void 0 : _j.url) !== null && _k !== void 0 ? _k : '',
|
18931
|
-
placementId: spot.placementId,
|
18932
|
-
spotId: spot.spotId,
|
18933
|
-
});
|
18934
|
-
break;
|
18955
|
+
if (Object.values(RMN_SPOT_EVENT).includes(eventData.event)) {
|
18956
|
+
await this.fireAndPublishSpotEvent({
|
18957
|
+
spotEvent: eventData.event,
|
18958
|
+
eventUrl: (_b = (_a = spot.events.find((event) => event.event === eventData.event)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
18959
|
+
placementId: spot.placementId,
|
18960
|
+
spotId: spot.spotId,
|
18961
|
+
});
|
18935
18962
|
}
|
18936
18963
|
}
|
18937
18964
|
}
|
@@ -19109,7 +19136,7 @@ class EventService {
|
|
19109
19136
|
spotId: spot.id,
|
19110
19137
|
spotType: spot.spot,
|
19111
19138
|
events: spot.events,
|
19112
|
-
productIds: (_c = spot.productIds) !== null && _c !== void 0 ? _c : [],
|
19139
|
+
productIds: (_c = spot.productIds) !== null && _c !== void 0 ? _c : [1, 2, 3],
|
19113
19140
|
});
|
19114
19141
|
}
|
19115
19142
|
handleIntersectionObserver(placementId, _spot, spotElement) {
|