@shoppexio/storefront 1.0.103 → 1.0.104
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/{chunk-ESI3HWQF.js → chunk-BW2EO2WP.js} +23 -1
- package/dist/{chunk-ESI3HWQF.js.map → chunk-BW2EO2WP.js.map} +1 -1
- package/dist/customer.cjs +22 -0
- package/dist/customer.cjs.map +1 -1
- package/dist/customer.js +1 -1
- package/dist/index.cjs +1065 -984
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -2
- package/dist/index.d.ts +24 -2
- package/dist/index.js +1043 -987
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -48,6 +48,7 @@ __export(src_exports, {
|
|
|
48
48
|
createTicket: () => createTicket,
|
|
49
49
|
dashboard: () => dashboard,
|
|
50
50
|
default: () => src_default,
|
|
51
|
+
discardTicketImage: () => discardTicketImage,
|
|
51
52
|
emailPreferences: () => emailPreferences,
|
|
52
53
|
enrollAsReseller: () => enrollAsReseller,
|
|
53
54
|
ensureCartLineId: () => ensureCartLineId,
|
|
@@ -115,11 +116,13 @@ __export(src_exports, {
|
|
|
115
116
|
touchStorefrontPresence: () => touchStorefrontPresence,
|
|
116
117
|
trackCartActivity: () => trackCartActivity,
|
|
117
118
|
trackPageView: () => trackPageView,
|
|
119
|
+
trackProductView: () => trackProductView,
|
|
118
120
|
undoSubscriptionCancel: () => undoSubscriptionCancel,
|
|
119
121
|
updateAvatar: () => updateAvatar,
|
|
120
122
|
updateEmailPreferences: () => updateEmailPreferences,
|
|
121
123
|
updateNotificationPreferences: () => updateNotificationPreferences,
|
|
122
124
|
updateProfile: () => updateProfile,
|
|
125
|
+
uploadTicketImage: () => uploadTicketImage,
|
|
123
126
|
validateStorefrontCustomFieldValue: () => validateStorefrontCustomFieldValue,
|
|
124
127
|
verifyOtp: () => verifyOtp,
|
|
125
128
|
warranties: () => warranties
|
|
@@ -962,1101 +965,1141 @@ async function captureAffiliateFromUrl(param = "ref") {
|
|
|
962
965
|
return holdsOtherCode ? held.code : code;
|
|
963
966
|
}
|
|
964
967
|
|
|
965
|
-
// ../
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
968
|
+
// ../contracts/src/storefront-consent-choice.ts
|
|
969
|
+
var COOKIE_CONSENT_VERSION = 1;
|
|
970
|
+
var COOKIE_CONSENT_COOKIE = "shoppex_consent";
|
|
971
|
+
var COOKIE_CONSENT_CHECKOUT_HASH_KEY = "shoppex_consent";
|
|
972
|
+
var COOKIE_CONSENT_VALUE = new RegExp(`^v${COOKIE_CONSENT_VERSION}\\.f([01])\\.a([01])\\.m([01])$`);
|
|
973
|
+
function parseCookieConsentValue(value) {
|
|
974
|
+
const match = value ? COOKIE_CONSENT_VALUE.exec(value) : null;
|
|
975
|
+
return match ? { functional: match[1] === "1", analytics: match[2] === "1", marketing: match[3] === "1" } : null;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
// ../sdk/src/core/analytics-session.ts
|
|
979
|
+
var ANALYTICS_SESSION_IDLE_MS = 30 * 60 * 1e3;
|
|
980
|
+
var ANALYTICS_VISITS_WINDOW_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
981
|
+
var ANALYTICS_VISITS_MAX = 20;
|
|
982
|
+
var MAX_ENGAGED_MS_PER_PAGE = 30 * 60 * 1e3;
|
|
983
|
+
var UTM_STORAGE_PREFIX = "shoppex:utm:";
|
|
984
|
+
var analyticsSessionKey = (storeSlug) => `analytics_session_${storeSlug}`;
|
|
985
|
+
var analyticsVisitsKey = (storeSlug) => `analytics_visits_${storeSlug}`;
|
|
986
|
+
function pageLanding() {
|
|
987
|
+
let r = "";
|
|
988
|
+
try {
|
|
989
|
+
r = document.referrer ? new URL(document.referrer).hostname : "";
|
|
990
|
+
} catch {
|
|
971
991
|
}
|
|
972
|
-
|
|
992
|
+
const params = new URLSearchParams(window.location?.search ?? "");
|
|
993
|
+
const u = ["source", "medium", "campaign"].map((key) => params.get(`utm_${key}`)?.trim().toLowerCase() ?? "").join("|");
|
|
994
|
+
return { r: r === window.location?.hostname ? "" : r, u: u === "||" ? "" : u };
|
|
973
995
|
}
|
|
974
|
-
function
|
|
975
|
-
if (
|
|
976
|
-
|
|
996
|
+
function readAnalyticsConsent() {
|
|
997
|
+
if (typeof document === "undefined" || typeof navigator === "undefined") return "unknown";
|
|
998
|
+
const privacy = navigator;
|
|
999
|
+
if (privacy.globalPrivacyControl === true || privacy.doNotTrack === "1") return "declined";
|
|
1000
|
+
const prefix = `${COOKIE_CONSENT_COOKIE}=`;
|
|
1001
|
+
let raw;
|
|
1002
|
+
try {
|
|
1003
|
+
raw = document.cookie.split(/;\s*/).find((part) => part.startsWith(prefix))?.slice(prefix.length);
|
|
1004
|
+
} catch {
|
|
1005
|
+
return "unknown";
|
|
1006
|
+
}
|
|
1007
|
+
const choice = parseCookieConsentValue(raw ?? null);
|
|
1008
|
+
if (!choice) return "unknown";
|
|
1009
|
+
return choice.analytics ? "granted" : "declined";
|
|
977
1010
|
}
|
|
978
|
-
function
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
return
|
|
1011
|
+
function readVisits(storeSlug, now) {
|
|
1012
|
+
const stored = getItem(analyticsVisitsKey(storeSlug));
|
|
1013
|
+
if (!Array.isArray(stored)) return [];
|
|
1014
|
+
return stored.filter((visit2) => typeof visit2?.id === "string" && typeof visit2.at === "number" && now - visit2.at < ANALYTICS_VISITS_WINDOW_MS);
|
|
982
1015
|
}
|
|
983
|
-
function
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
variant_id: input2.variant_id,
|
|
987
|
-
price_variant_id: input2.price_variant_id ?? null,
|
|
988
|
-
addons: normalizeAddons(input2.addons),
|
|
989
|
-
custom_fields: normalizeCustomFields(input2.custom_fields),
|
|
990
|
-
unit_price: typeof input2.price_data?.unit_price === "number" && Number.isFinite(input2.price_data.unit_price) ? input2.price_data.unit_price : null,
|
|
991
|
-
pay_what_you_want_price: typeof input2.pay_what_you_want_price === "number" && Number.isFinite(input2.pay_what_you_want_price) ? input2.pay_what_you_want_price : null
|
|
992
|
-
};
|
|
993
|
-
return hashString(JSON.stringify(payload));
|
|
1016
|
+
function forgetAnalyticsData(storeSlug) {
|
|
1017
|
+
removeItem(analyticsSessionKey(storeSlug), "sessionStorage");
|
|
1018
|
+
removeItem(analyticsVisitsKey(storeSlug));
|
|
994
1019
|
}
|
|
995
|
-
function
|
|
996
|
-
|
|
997
|
-
|
|
1020
|
+
function analyticsSessionId(storeSlug, options, now = Date.now()) {
|
|
1021
|
+
removeItem(`presence_connection_${storeSlug}`);
|
|
1022
|
+
if (readAnalyticsConsent() !== "granted") {
|
|
1023
|
+
forgetAnalyticsData(storeSlug);
|
|
1024
|
+
return null;
|
|
998
1025
|
}
|
|
999
|
-
|
|
1026
|
+
const stored = getItem(analyticsSessionKey(storeSlug), "sessionStorage");
|
|
1027
|
+
const live = stored && typeof stored.id === "string" && typeof stored.at === "number" && now - stored.at < ANALYTICS_SESSION_IDLE_MS ? stored.id : null;
|
|
1028
|
+
if (!options.touch) return live;
|
|
1029
|
+
const landing = pageLanding();
|
|
1030
|
+
const newLanding = landing.r && landing.r !== stored?.r || landing.u && landing.u !== stored?.u;
|
|
1031
|
+
if (live && !newLanding) {
|
|
1032
|
+
setItem(analyticsSessionKey(storeSlug), { ...stored, id: live, at: now }, "sessionStorage");
|
|
1033
|
+
return live;
|
|
1034
|
+
}
|
|
1035
|
+
if (typeof crypto === "undefined" || typeof crypto.randomUUID !== "function") return null;
|
|
1036
|
+
if (landing.r) {
|
|
1037
|
+
try {
|
|
1038
|
+
globalThis.localStorage.removeItem(storefrontStorageKey(`${UTM_STORAGE_PREFIX}${storeSlug}`));
|
|
1039
|
+
} catch {
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
const id = crypto.randomUUID();
|
|
1043
|
+
setItem(analyticsSessionKey(storeSlug), { id, at: now, ...landing }, "sessionStorage");
|
|
1044
|
+
setItem(
|
|
1045
|
+
analyticsVisitsKey(storeSlug),
|
|
1046
|
+
[{ id, at: now }, ...readVisits(storeSlug, now)].slice(0, ANALYTICS_VISITS_MAX)
|
|
1047
|
+
);
|
|
1048
|
+
return id;
|
|
1000
1049
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
const sign = value < 0 ? -1 : 1;
|
|
1011
|
-
const shifted = shiftDecimal(Math.abs(value), PAYABLE_AMOUNT_DECIMAL_PLACES);
|
|
1012
|
-
const rounded = Math.round(shifted);
|
|
1013
|
-
if (rounded === 0) return 0;
|
|
1014
|
-
return sign * shiftDecimal(rounded, -PAYABLE_AMOUNT_DECIMAL_PLACES);
|
|
1050
|
+
function checkoutAttribution(storeSlug, now = Date.now()) {
|
|
1051
|
+
const consent = readAnalyticsConsent();
|
|
1052
|
+
if (consent === "declined") {
|
|
1053
|
+
forgetAnalyticsData(storeSlug);
|
|
1054
|
+
return { declined: true };
|
|
1055
|
+
}
|
|
1056
|
+
if (consent === "unknown") return void 0;
|
|
1057
|
+
const sessionIds = readVisits(storeSlug, now).map((visit2) => visit2.id);
|
|
1058
|
+
return sessionIds.length > 0 ? { session_ids: sessionIds } : void 0;
|
|
1015
1059
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1060
|
+
var engagedMs = 0;
|
|
1061
|
+
var visibleSince = null;
|
|
1062
|
+
var clockInstalled = false;
|
|
1063
|
+
var pageViewed = false;
|
|
1064
|
+
var pageSession = null;
|
|
1065
|
+
function markPageViewed(sessionId) {
|
|
1066
|
+
pageViewed = true;
|
|
1067
|
+
pageSession = sessionId;
|
|
1019
1068
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
var STORAGE_KEYS = {
|
|
1023
|
-
cart: "cart",
|
|
1024
|
-
cartBackup: "cart_backup",
|
|
1025
|
-
meta: "cart_meta",
|
|
1026
|
-
metaBackup: "cart_backup_meta",
|
|
1027
|
-
coupon: "cart_coupon",
|
|
1028
|
-
couponBackup: "cart_coupon_backup"
|
|
1029
|
-
};
|
|
1030
|
-
function getStorageKey(type) {
|
|
1031
|
-
return `${STORAGE_KEYS[type]}_${getConfig().storeSlug}`;
|
|
1069
|
+
function currentPageSession() {
|
|
1070
|
+
return pageSession;
|
|
1032
1071
|
}
|
|
1033
|
-
function
|
|
1034
|
-
return
|
|
1072
|
+
function isPageViewed() {
|
|
1073
|
+
return pageViewed;
|
|
1035
1074
|
}
|
|
1036
|
-
function
|
|
1037
|
-
|
|
1075
|
+
function settleClock(now) {
|
|
1076
|
+
if (visibleSince !== null) {
|
|
1077
|
+
engagedMs += now - visibleSince;
|
|
1078
|
+
visibleSince = document.visibilityState === "visible" ? now : null;
|
|
1079
|
+
}
|
|
1038
1080
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1081
|
+
var consentListenerInstalled = false;
|
|
1082
|
+
function onAnalyticsConsent(onYes) {
|
|
1083
|
+
if (consentListenerInstalled || typeof window === "undefined") return;
|
|
1084
|
+
consentListenerInstalled = true;
|
|
1085
|
+
window.addEventListener("shoppex:consent", () => {
|
|
1086
|
+
if (readAnalyticsConsent() === "granted") onYes();
|
|
1087
|
+
});
|
|
1041
1088
|
}
|
|
1042
|
-
function
|
|
1043
|
-
|
|
1089
|
+
function installEngagedClock(onHidden) {
|
|
1090
|
+
if (clockInstalled || typeof document === "undefined") return;
|
|
1091
|
+
clockInstalled = true;
|
|
1092
|
+
visibleSince = document.visibilityState === "visible" ? Date.now() : null;
|
|
1093
|
+
document.addEventListener("visibilitychange", () => {
|
|
1094
|
+
const now = Date.now();
|
|
1095
|
+
if (document.visibilityState === "visible") {
|
|
1096
|
+
visibleSince ?? (visibleSince = now);
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
settleClock(now);
|
|
1100
|
+
visibleSince = null;
|
|
1101
|
+
onHidden();
|
|
1102
|
+
});
|
|
1103
|
+
window.addEventListener("pagehide", () => {
|
|
1104
|
+
settleClock(Date.now());
|
|
1105
|
+
visibleSince = null;
|
|
1106
|
+
onHidden();
|
|
1107
|
+
});
|
|
1108
|
+
window.addEventListener("pageshow", (event) => {
|
|
1109
|
+
if (event.persisted && document.visibilityState === "visible") visibleSince = Date.now();
|
|
1110
|
+
});
|
|
1044
1111
|
}
|
|
1045
|
-
function
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1112
|
+
function takeEngagedMs(now = Date.now()) {
|
|
1113
|
+
settleClock(now);
|
|
1114
|
+
const taken = Math.min(Math.max(0, Math.round(engagedMs)), MAX_ENGAGED_MS_PER_PAGE);
|
|
1115
|
+
engagedMs = 0;
|
|
1116
|
+
return taken;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// ../sdk/src/core/attribution.ts
|
|
1120
|
+
var TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
1121
|
+
var UTM_KEYS = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
|
|
1122
|
+
var MAX_VALUE_LENGTH = 255;
|
|
1123
|
+
function readFromUrl(search) {
|
|
1124
|
+
let params;
|
|
1125
|
+
try {
|
|
1126
|
+
params = new URLSearchParams(search);
|
|
1127
|
+
} catch {
|
|
1128
|
+
return {};
|
|
1050
1129
|
}
|
|
1051
|
-
|
|
1130
|
+
const utm = {};
|
|
1131
|
+
for (const key of UTM_KEYS) {
|
|
1132
|
+
const value = params.get(key)?.trim();
|
|
1133
|
+
if (value) {
|
|
1134
|
+
utm[key] = value.slice(0, MAX_VALUE_LENGTH);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
return utm;
|
|
1052
1138
|
}
|
|
1053
|
-
function
|
|
1054
|
-
return
|
|
1139
|
+
function storageKey(storeSlug) {
|
|
1140
|
+
return `${UTM_STORAGE_PREFIX}${storeSlug}`;
|
|
1055
1141
|
}
|
|
1056
|
-
function
|
|
1057
|
-
|
|
1058
|
-
|
|
1142
|
+
function readStored(storeSlug) {
|
|
1143
|
+
try {
|
|
1144
|
+
const raw = window.localStorage.getItem(storefrontStorageKey(storageKey(storeSlug)));
|
|
1145
|
+
if (!raw) return {};
|
|
1146
|
+
const parsed = JSON.parse(raw);
|
|
1147
|
+
if (!parsed || typeof parsed.at !== "number" || typeof parsed.utm !== "object") return {};
|
|
1148
|
+
if (Date.now() - parsed.at > TTL_MS) {
|
|
1149
|
+
window.localStorage.removeItem(storefrontStorageKey(storageKey(storeSlug)));
|
|
1150
|
+
return {};
|
|
1151
|
+
}
|
|
1152
|
+
const utm = {};
|
|
1153
|
+
for (const key of UTM_KEYS) {
|
|
1154
|
+
const value = parsed.utm?.[key];
|
|
1155
|
+
if (typeof value === "string" && value.length > 0) {
|
|
1156
|
+
utm[key] = value.slice(0, MAX_VALUE_LENGTH);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
return utm;
|
|
1160
|
+
} catch {
|
|
1161
|
+
return {};
|
|
1059
1162
|
}
|
|
1060
|
-
return Math.floor(value);
|
|
1061
1163
|
}
|
|
1062
|
-
function
|
|
1063
|
-
|
|
1064
|
-
|
|
1164
|
+
function writeStored(storeSlug, utm) {
|
|
1165
|
+
try {
|
|
1166
|
+
const payload = { utm, at: Date.now() };
|
|
1167
|
+
window.localStorage.setItem(storefrontStorageKey(storageKey(storeSlug)), JSON.stringify(payload));
|
|
1168
|
+
} catch {
|
|
1169
|
+
}
|
|
1065
1170
|
}
|
|
1066
|
-
function
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
return null;
|
|
1171
|
+
function resolveUtmParameters(storeSlug) {
|
|
1172
|
+
if (typeof window === "undefined" || typeof window.location === "undefined") {
|
|
1173
|
+
return void 0;
|
|
1070
1174
|
}
|
|
1071
|
-
const
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
}
|
|
1076
|
-
function normalizeCartItems(value) {
|
|
1077
|
-
if (!Array.isArray(value)) return [];
|
|
1078
|
-
const normalized = [];
|
|
1079
|
-
for (const entry of value) {
|
|
1080
|
-
if (!entry || typeof entry !== "object") continue;
|
|
1081
|
-
const record2 = entry;
|
|
1082
|
-
const productId = typeof record2.product_id === "string" ? record2.product_id.trim() : "";
|
|
1083
|
-
const variantId = typeof record2.variant_id === "string" ? record2.variant_id.trim() : "";
|
|
1084
|
-
const quantity = Number(record2.quantity);
|
|
1085
|
-
if (!productId || !variantId || !Number.isFinite(quantity) || quantity < 1) {
|
|
1086
|
-
continue;
|
|
1087
|
-
}
|
|
1088
|
-
const item = {
|
|
1089
|
-
line_id: "",
|
|
1090
|
-
product_id: productId,
|
|
1091
|
-
variant_id: variantId,
|
|
1092
|
-
quantity: Math.floor(quantity)
|
|
1093
|
-
};
|
|
1094
|
-
if (typeof record2.price_variant_id === "string") {
|
|
1095
|
-
item.price_variant_id = record2.price_variant_id;
|
|
1096
|
-
}
|
|
1097
|
-
if (record2.price_data && typeof record2.price_data === "object") {
|
|
1098
|
-
const priceData = record2.price_data;
|
|
1099
|
-
if (typeof priceData.unit_price === "number" && Number.isFinite(priceData.unit_price)) {
|
|
1100
|
-
item.price_data = { unit_price: priceData.unit_price };
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
if (typeof record2.pay_what_you_want_price === "number" && Number.isFinite(record2.pay_what_you_want_price)) {
|
|
1104
|
-
item.pay_what_you_want_price = record2.pay_what_you_want_price;
|
|
1105
|
-
}
|
|
1106
|
-
if (Array.isArray(record2.addons)) {
|
|
1107
|
-
item.addons = record2.addons;
|
|
1108
|
-
}
|
|
1109
|
-
if (record2.custom_fields && typeof record2.custom_fields === "object" && !Array.isArray(record2.custom_fields)) {
|
|
1110
|
-
item.custom_fields = record2.custom_fields;
|
|
1111
|
-
}
|
|
1112
|
-
if (typeof record2.title === "string") {
|
|
1113
|
-
item.title = record2.title;
|
|
1114
|
-
}
|
|
1115
|
-
if (typeof record2.variant_title === "string") {
|
|
1116
|
-
item.variant_title = record2.variant_title;
|
|
1117
|
-
}
|
|
1118
|
-
if (typeof record2.image_url === "string") {
|
|
1119
|
-
item.image_url = record2.image_url;
|
|
1120
|
-
}
|
|
1121
|
-
if (Array.isArray(record2.addon_labels)) {
|
|
1122
|
-
item.addon_labels = record2.addon_labels.filter((label) => typeof label === "string");
|
|
1123
|
-
}
|
|
1124
|
-
if (typeof record2.max_quantity === "number" && Number.isFinite(record2.max_quantity)) {
|
|
1125
|
-
item.max_quantity = record2.max_quantity;
|
|
1126
|
-
}
|
|
1127
|
-
if (typeof record2.min_quantity === "number" && Number.isFinite(record2.min_quantity)) {
|
|
1128
|
-
item.min_quantity = record2.min_quantity;
|
|
1175
|
+
const fromUrl = readFromUrl(window.location.search);
|
|
1176
|
+
if (readAnalyticsConsent() !== "granted") {
|
|
1177
|
+
try {
|
|
1178
|
+
window.localStorage.removeItem(storefrontStorageKey(storageKey(storeSlug)));
|
|
1179
|
+
} catch {
|
|
1129
1180
|
}
|
|
1130
|
-
|
|
1131
|
-
const storedLineId = typeof record2.line_id === "string" ? record2.line_id.trim() : "";
|
|
1132
|
-
item.line_id = storedLineId || computeCartLineId(item);
|
|
1133
|
-
normalized.push(ensureCartLineId(item));
|
|
1181
|
+
return Object.keys(fromUrl).length > 0 ? fromUrl : void 0;
|
|
1134
1182
|
}
|
|
1135
|
-
|
|
1183
|
+
if (Object.keys(fromUrl).length > 0) {
|
|
1184
|
+
writeStored(storeSlug, fromUrl);
|
|
1185
|
+
return fromUrl;
|
|
1186
|
+
}
|
|
1187
|
+
const stored = readStored(storeSlug);
|
|
1188
|
+
return Object.keys(stored).length > 0 ? stored : void 0;
|
|
1136
1189
|
}
|
|
1137
|
-
|
|
1138
|
-
|
|
1190
|
+
|
|
1191
|
+
// ../sdk/src/core/page-path.ts
|
|
1192
|
+
var MAX_PATH_LENGTH = 256;
|
|
1193
|
+
function resolveStorefrontPagePath() {
|
|
1194
|
+
if (typeof window === "undefined") return void 0;
|
|
1195
|
+
let pathname;
|
|
1196
|
+
try {
|
|
1197
|
+
const location = window.location;
|
|
1198
|
+
pathname = typeof location?.pathname === "string" && location.pathname ? location.pathname : new URL(String(location?.href ?? "")).pathname;
|
|
1199
|
+
} catch {
|
|
1200
|
+
return void 0;
|
|
1201
|
+
}
|
|
1202
|
+
if (!pathname || !pathname.startsWith("/")) return void 0;
|
|
1203
|
+
return pathname.slice(0, MAX_PATH_LENGTH);
|
|
1139
1204
|
}
|
|
1140
|
-
|
|
1141
|
-
|
|
1205
|
+
|
|
1206
|
+
// ../sdk/src/core/page-tracker.ts
|
|
1207
|
+
var PLATFORM_PAGE_TRACKER_FLAG = "__shoppexPageTracker";
|
|
1208
|
+
function isPlatformPageTrackerActive() {
|
|
1209
|
+
if (typeof window === "undefined") return false;
|
|
1210
|
+
try {
|
|
1211
|
+
return Boolean(window[PLATFORM_PAGE_TRACKER_FLAG]);
|
|
1212
|
+
} catch {
|
|
1213
|
+
return false;
|
|
1214
|
+
}
|
|
1142
1215
|
}
|
|
1143
|
-
|
|
1144
|
-
|
|
1216
|
+
|
|
1217
|
+
// ../sdk/src/modules/analytics.ts
|
|
1218
|
+
var CONFIRMED_CART_STORAGE_PREFIX = "reported_cart_";
|
|
1219
|
+
var IN_FLIGHT_CART_STORAGE_PREFIX = "reporting_cart_";
|
|
1220
|
+
var CART_SEQUENCE_STORAGE_PREFIX = "presence_cart_seq_";
|
|
1221
|
+
var CART_CLAIM_TTL_MS = 1e4;
|
|
1222
|
+
function confirmedCartKey(storeSlug) {
|
|
1223
|
+
return `${CONFIRMED_CART_STORAGE_PREFIX}${storeSlug}`;
|
|
1145
1224
|
}
|
|
1146
|
-
function
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1225
|
+
function inFlightCartKey(storeSlug) {
|
|
1226
|
+
return `${IN_FLIGHT_CART_STORAGE_PREFIX}${storeSlug}`;
|
|
1227
|
+
}
|
|
1228
|
+
function cartSequenceKey(storeSlug) {
|
|
1229
|
+
return `${CART_SEQUENCE_STORAGE_PREFIX}${storeSlug}`;
|
|
1230
|
+
}
|
|
1231
|
+
function cartSnapshot(cartValue, itemCount) {
|
|
1232
|
+
return `${cartValue ?? ""}|${itemCount ?? ""}`;
|
|
1233
|
+
}
|
|
1234
|
+
function isCartSequence(value) {
|
|
1235
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
1236
|
+
}
|
|
1237
|
+
var CART_SEQUENCE_SCOPE_MAX_LENGTH = 64;
|
|
1238
|
+
function readCartCounter(storeSlug) {
|
|
1239
|
+
const counter = getItem(cartSequenceKey(storeSlug));
|
|
1240
|
+
if (!counter || typeof counter.scope !== "string" || counter.scope.length === 0 || counter.scope.length > CART_SEQUENCE_SCOPE_MAX_LENGTH || !isCartSequence(counter.seq)) {
|
|
1150
1241
|
return null;
|
|
1151
1242
|
}
|
|
1152
|
-
|
|
1153
|
-
return normalizedCoupon;
|
|
1243
|
+
return counter;
|
|
1154
1244
|
}
|
|
1155
|
-
|
|
1156
|
-
|
|
1245
|
+
var lastCartOrder = null;
|
|
1246
|
+
function nextCartOrder(storeSlug) {
|
|
1247
|
+
const stored = readCartCounter(storeSlug);
|
|
1248
|
+
const scope = stored?.scope ?? lastCartOrder?.scope ?? createClaimToken();
|
|
1249
|
+
const floor = Math.max(stored?.seq ?? 0, lastCartOrder?.scope === scope ? lastCartOrder.seq : 0);
|
|
1250
|
+
const order2 = { scope, seq: Math.max(Date.now(), floor + 1) };
|
|
1251
|
+
lastCartOrder = order2;
|
|
1252
|
+
setItem(cartSequenceKey(storeSlug), order2);
|
|
1253
|
+
return order2;
|
|
1157
1254
|
}
|
|
1158
|
-
function
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
const previous = getCartMetadata();
|
|
1163
|
-
const nextMeta = {
|
|
1164
|
-
created_at: previous?.created_at ?? now,
|
|
1165
|
-
last_modified: now,
|
|
1166
|
-
version: (previous?.version ?? 0) + 1,
|
|
1167
|
-
checksum: computeChecksum(normalizedCart)
|
|
1168
|
-
};
|
|
1169
|
-
writeCartStorage("meta", nextMeta);
|
|
1170
|
-
if (normalizedCart.length === 0) {
|
|
1171
|
-
clearCartCoupon();
|
|
1172
|
-
}
|
|
1255
|
+
function cartSequenceLocks() {
|
|
1256
|
+
if (typeof navigator === "undefined") return null;
|
|
1257
|
+
const locks = navigator.locks;
|
|
1258
|
+
return locks && typeof locks.request === "function" ? locks : null;
|
|
1173
1259
|
}
|
|
1174
|
-
function
|
|
1175
|
-
const
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
const nextMeta = {
|
|
1180
|
-
created_at: base?.created_at ?? now,
|
|
1181
|
-
last_modified: now,
|
|
1182
|
-
version: base?.version ?? 1,
|
|
1183
|
-
checksum: computeChecksum(normalizedCart)
|
|
1184
|
-
};
|
|
1185
|
-
writeCartStorage("meta", nextMeta);
|
|
1260
|
+
function reserveCartOrder(storeSlug) {
|
|
1261
|
+
const take = () => nextCartOrder(storeSlug);
|
|
1262
|
+
const locks = cartSequenceLocks();
|
|
1263
|
+
if (!locks) return Promise.resolve(take());
|
|
1264
|
+
return locks.request(cartSequenceKey(storeSlug), take).catch(take);
|
|
1186
1265
|
}
|
|
1187
|
-
function
|
|
1188
|
-
const
|
|
1189
|
-
|
|
1266
|
+
function readConfirmedCart(storeSlug) {
|
|
1267
|
+
const confirmed = getItem(confirmedCartKey(storeSlug));
|
|
1268
|
+
if (!confirmed || typeof confirmed.snapshot !== "string" || !isCartSequence(confirmed.seq)) return null;
|
|
1269
|
+
return confirmed;
|
|
1190
1270
|
}
|
|
1191
|
-
function
|
|
1192
|
-
const
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
if (matches.length === 0) {
|
|
1196
|
-
throw new CartError(`No cart line found for ${productId}/${variantId}`);
|
|
1271
|
+
function readInFlightCart(storeSlug) {
|
|
1272
|
+
const claim2 = getItem(inFlightCartKey(storeSlug));
|
|
1273
|
+
if (!claim2 || typeof claim2.snapshot !== "string" || !isCartSequence(claim2.seq) || typeof claim2.token !== "string" || typeof claim2.at !== "number") {
|
|
1274
|
+
return null;
|
|
1197
1275
|
}
|
|
1198
|
-
return
|
|
1276
|
+
return claim2;
|
|
1199
1277
|
}
|
|
1200
|
-
function
|
|
1201
|
-
const
|
|
1202
|
-
|
|
1278
|
+
function isCartReportedOrInFlight(storeSlug, snapshot) {
|
|
1279
|
+
const confirmed = readConfirmedCart(storeSlug);
|
|
1280
|
+
const claim2 = readInFlightCart(storeSlug);
|
|
1281
|
+
const liveClaim = claim2 && Date.now() - claim2.at < CART_CLAIM_TTL_MS ? claim2 : null;
|
|
1282
|
+
const expected = liveClaim && (!confirmed || liveClaim.seq > confirmed.seq) ? liveClaim : confirmed;
|
|
1283
|
+
return expected?.snapshot === snapshot;
|
|
1203
1284
|
}
|
|
1204
|
-
function
|
|
1205
|
-
if (
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
addons: options?.addons,
|
|
1217
|
-
custom_fields: options?.custom_fields,
|
|
1218
|
-
price_variant_id: options?.price_variant_id,
|
|
1219
|
-
price_data: options?.price_data,
|
|
1220
|
-
pay_what_you_want_price: options?.pay_what_you_want_price
|
|
1221
|
-
});
|
|
1222
|
-
const existingIndex = cart.findIndex((item) => item.line_id === lineId);
|
|
1223
|
-
const quantityBeforeAdd = existingIndex >= 0 ? cart[existingIndex].quantity : 0;
|
|
1224
|
-
if (existingIndex >= 0) {
|
|
1225
|
-
cart[existingIndex].quantity += normalizedQuantity;
|
|
1226
|
-
if (options?.addons) {
|
|
1227
|
-
cart[existingIndex].addons = options.addons;
|
|
1228
|
-
}
|
|
1229
|
-
if (options?.custom_fields) {
|
|
1230
|
-
cart[existingIndex].custom_fields = options.custom_fields;
|
|
1231
|
-
}
|
|
1232
|
-
if (options?.price_variant_id) {
|
|
1233
|
-
cart[existingIndex].price_variant_id = options.price_variant_id;
|
|
1234
|
-
}
|
|
1235
|
-
if (options?.price_data) {
|
|
1236
|
-
cart[existingIndex].price_data = options.price_data;
|
|
1285
|
+
function createClaimToken() {
|
|
1286
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
1287
|
+
return `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
|
|
1288
|
+
}
|
|
1289
|
+
function claimCartReport(storeSlug, seq, cartValue, itemCount) {
|
|
1290
|
+
const snapshot = cartSnapshot(cartValue, itemCount);
|
|
1291
|
+
const token = createClaimToken();
|
|
1292
|
+
setItem(inFlightCartKey(storeSlug), { snapshot, seq, token, at: Date.now() });
|
|
1293
|
+
return (delivered) => {
|
|
1294
|
+
if (delivered) {
|
|
1295
|
+
const confirmed = readConfirmedCart(storeSlug);
|
|
1296
|
+
if (!confirmed || seq > confirmed.seq) setItem(confirmedCartKey(storeSlug), { snapshot, seq });
|
|
1237
1297
|
}
|
|
1238
|
-
if (
|
|
1239
|
-
|
|
1240
|
-
}
|
|
1241
|
-
applyDisplaySnapshot(cart[existingIndex], options);
|
|
1242
|
-
clampQuantityToBounds(cart[existingIndex]);
|
|
1243
|
-
} else {
|
|
1244
|
-
const pushed = {
|
|
1245
|
-
line_id: lineId,
|
|
1246
|
-
product_id: productId,
|
|
1247
|
-
variant_id: variantId,
|
|
1248
|
-
quantity: normalizedQuantity,
|
|
1249
|
-
addons: options?.addons,
|
|
1250
|
-
custom_fields: options?.custom_fields,
|
|
1251
|
-
price_variant_id: options?.price_variant_id,
|
|
1252
|
-
price_data: options?.price_data,
|
|
1253
|
-
pay_what_you_want_price: options?.pay_what_you_want_price,
|
|
1254
|
-
title: options?.title,
|
|
1255
|
-
variant_title: options?.variant_title,
|
|
1256
|
-
image_url: options?.image_url,
|
|
1257
|
-
addon_labels: options?.addon_labels,
|
|
1258
|
-
max_quantity: options?.max_quantity,
|
|
1259
|
-
min_quantity: options?.min_quantity
|
|
1260
|
-
};
|
|
1261
|
-
clampQuantityToBounds(pushed);
|
|
1262
|
-
cart.push(pushed);
|
|
1263
|
-
}
|
|
1264
|
-
const intendedQuantity = (existingIndex >= 0 ? cart[existingIndex] : cart[cart.length - 1]).quantity;
|
|
1265
|
-
writeCart(cart);
|
|
1266
|
-
const persistedLine = getCart().find((item) => item.line_id === lineId);
|
|
1267
|
-
if (intendedQuantity > quantityBeforeAdd && persistedLine?.quantity === intendedQuantity) {
|
|
1268
|
-
const cartAffiliateCode = getCartCouponSource() === "AFFILIATE" ? getCartCoupon() : null;
|
|
1269
|
-
void trackAffiliateEvent("add_to_cart", cartAffiliateCode ? { code: cartAffiliateCode } : void 0);
|
|
1270
|
-
}
|
|
1271
|
-
}
|
|
1272
|
-
function clampQuantityToBounds(item) {
|
|
1273
|
-
const min = item.min_quantity;
|
|
1274
|
-
if (typeof min === "number" && Number.isFinite(min) && item.quantity < min) {
|
|
1275
|
-
item.quantity = Math.floor(min);
|
|
1276
|
-
}
|
|
1277
|
-
const max = item.max_quantity;
|
|
1278
|
-
if (typeof max === "number" && Number.isFinite(max) && item.quantity > max) {
|
|
1279
|
-
item.quantity = Math.floor(max);
|
|
1280
|
-
}
|
|
1281
|
-
if (item.quantity < 1) {
|
|
1282
|
-
item.quantity = 1;
|
|
1283
|
-
}
|
|
1298
|
+
if (readInFlightCart(storeSlug)?.token === token) removeItem(inFlightCartKey(storeSlug));
|
|
1299
|
+
};
|
|
1284
1300
|
}
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
item.min_quantity = options.min_quantity;
|
|
1293
|
-
return;
|
|
1294
|
-
}
|
|
1295
|
-
if (options?.title !== void 0) {
|
|
1296
|
-
item.title = options.title;
|
|
1297
|
-
}
|
|
1298
|
-
if (options?.variant_title !== void 0) {
|
|
1299
|
-
item.variant_title = options.variant_title;
|
|
1300
|
-
}
|
|
1301
|
-
if (options?.image_url !== void 0) {
|
|
1302
|
-
item.image_url = options.image_url;
|
|
1303
|
-
}
|
|
1304
|
-
if (options?.addon_labels !== void 0) {
|
|
1305
|
-
item.addon_labels = options.addon_labels;
|
|
1306
|
-
}
|
|
1307
|
-
if (options?.max_quantity !== void 0) {
|
|
1308
|
-
item.max_quantity = options.max_quantity;
|
|
1309
|
-
}
|
|
1310
|
-
if (options?.min_quantity !== void 0) {
|
|
1311
|
-
item.min_quantity = options.min_quantity;
|
|
1312
|
-
}
|
|
1301
|
+
var cartSendTail = Promise.resolve();
|
|
1302
|
+
var latestCartRequest = 0;
|
|
1303
|
+
function enqueueCartSend(send) {
|
|
1304
|
+
const request2 = ++latestCartRequest;
|
|
1305
|
+
const run = () => send(() => request2 === latestCartRequest);
|
|
1306
|
+
cartSendTail = cartSendTail.then(run, run);
|
|
1307
|
+
return cartSendTail;
|
|
1313
1308
|
}
|
|
1314
|
-
function
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
const
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
const lineId = computeCartLineId({
|
|
1324
|
-
product_id: productId,
|
|
1325
|
-
variant_id: variantId,
|
|
1326
|
-
addons: options?.addons,
|
|
1327
|
-
custom_fields: options?.custom_fields,
|
|
1328
|
-
price_variant_id: options?.price_variant_id,
|
|
1329
|
-
price_data: options?.price_data,
|
|
1330
|
-
pay_what_you_want_price: options?.pay_what_you_want_price
|
|
1309
|
+
async function postPing(body) {
|
|
1310
|
+
const config2 = getConfig();
|
|
1311
|
+
const controller = typeof AbortController === "undefined" ? void 0 : new AbortController();
|
|
1312
|
+
let timer;
|
|
1313
|
+
const timedOut = new Promise((resolve) => {
|
|
1314
|
+
timer = setTimeout(() => {
|
|
1315
|
+
controller?.abort();
|
|
1316
|
+
resolve(false);
|
|
1317
|
+
}, CART_CLAIM_TTL_MS);
|
|
1331
1318
|
});
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
}
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
title: options?.title,
|
|
1348
|
-
variant_title: options?.variant_title,
|
|
1349
|
-
image_url: options?.image_url,
|
|
1350
|
-
addon_labels: options?.addon_labels,
|
|
1351
|
-
max_quantity: options?.max_quantity,
|
|
1352
|
-
min_quantity: options?.min_quantity
|
|
1353
|
-
};
|
|
1354
|
-
clampQuantityToBounds(pushed);
|
|
1355
|
-
cart.push(pushed);
|
|
1356
|
-
writeCart(cart);
|
|
1357
|
-
}
|
|
1358
|
-
function updateCartItem(lineId, updates) {
|
|
1359
|
-
const cart = getCart();
|
|
1360
|
-
const normalizedLineId = lineId.trim();
|
|
1361
|
-
if (!normalizedLineId) {
|
|
1362
|
-
throw new CartError("line_id is required");
|
|
1363
|
-
}
|
|
1364
|
-
const index = cart.findIndex((item) => item.line_id === normalizedLineId);
|
|
1365
|
-
if (index < 0) {
|
|
1366
|
-
throw new CartError("Item not found in cart");
|
|
1367
|
-
}
|
|
1368
|
-
const before = JSON.stringify(cart);
|
|
1369
|
-
if (updates.quantity !== void 0) {
|
|
1370
|
-
const normalizedQuantity = normalizeQuantity(updates.quantity);
|
|
1371
|
-
if (normalizedQuantity < 1) {
|
|
1372
|
-
cart.splice(index, 1);
|
|
1373
|
-
writeCart(cart);
|
|
1374
|
-
return;
|
|
1375
|
-
}
|
|
1376
|
-
cart[index].quantity = normalizedQuantity;
|
|
1377
|
-
}
|
|
1378
|
-
if (updates.addons !== void 0) {
|
|
1379
|
-
cart[index].addons = updates.addons;
|
|
1380
|
-
}
|
|
1381
|
-
if (updates.custom_fields !== void 0) {
|
|
1382
|
-
cart[index].custom_fields = updates.custom_fields;
|
|
1383
|
-
}
|
|
1384
|
-
if (updates.price_variant_id !== void 0) {
|
|
1385
|
-
cart[index].price_variant_id = updates.price_variant_id;
|
|
1386
|
-
}
|
|
1387
|
-
if (updates.price_data !== void 0) {
|
|
1388
|
-
cart[index].price_data = updates.price_data;
|
|
1389
|
-
}
|
|
1390
|
-
if (updates.pay_what_you_want_price !== void 0) {
|
|
1391
|
-
cart[index].pay_what_you_want_price = updates.pay_what_you_want_price;
|
|
1392
|
-
}
|
|
1393
|
-
if (updates.variant_title !== void 0) {
|
|
1394
|
-
if (updates.variant_title === null) delete cart[index].variant_title;
|
|
1395
|
-
else cart[index].variant_title = updates.variant_title;
|
|
1396
|
-
}
|
|
1397
|
-
if (updates.max_quantity !== void 0) {
|
|
1398
|
-
if (updates.max_quantity === null) delete cart[index].max_quantity;
|
|
1399
|
-
else cart[index].max_quantity = updates.max_quantity;
|
|
1400
|
-
}
|
|
1401
|
-
if (updates.min_quantity !== void 0) {
|
|
1402
|
-
if (updates.min_quantity === null) delete cart[index].min_quantity;
|
|
1403
|
-
else cart[index].min_quantity = updates.min_quantity;
|
|
1404
|
-
}
|
|
1405
|
-
clampQuantityToBounds(cart[index]);
|
|
1406
|
-
const nextLineId = computeCartLineId(cart[index]);
|
|
1407
|
-
const duplicateIndex = cart.findIndex((item, itemIndex) => itemIndex !== index && item.line_id === nextLineId);
|
|
1408
|
-
if (duplicateIndex >= 0) {
|
|
1409
|
-
cart[duplicateIndex].quantity += cart[index].quantity;
|
|
1410
|
-
clampQuantityToBounds(cart[duplicateIndex]);
|
|
1411
|
-
cart.splice(index, 1);
|
|
1412
|
-
} else {
|
|
1413
|
-
cart[index].line_id = nextLineId;
|
|
1319
|
+
try {
|
|
1320
|
+
const endpoint = buildEndpoint("/v1/storefront/shops/:storeSlug/ping", {
|
|
1321
|
+
storeSlug: config2.storeSlug
|
|
1322
|
+
});
|
|
1323
|
+
const delivered = fetch(`${config2.apiBaseUrl}${endpoint}`, {
|
|
1324
|
+
method: "POST",
|
|
1325
|
+
headers: { "Content-Type": "application/json" },
|
|
1326
|
+
body: JSON.stringify(body),
|
|
1327
|
+
signal: controller?.signal
|
|
1328
|
+
}).then((response) => response.ok);
|
|
1329
|
+
return await Promise.race([delivered, timedOut]);
|
|
1330
|
+
} catch {
|
|
1331
|
+
return false;
|
|
1332
|
+
} finally {
|
|
1333
|
+
clearTimeout(timer);
|
|
1414
1334
|
}
|
|
1415
|
-
if (JSON.stringify(cart) === before) return;
|
|
1416
|
-
writeCart(cart);
|
|
1417
1335
|
}
|
|
1418
|
-
function
|
|
1419
|
-
|
|
1420
|
-
if (
|
|
1421
|
-
|
|
1336
|
+
async function trackPageView(cartValue, itemCount) {
|
|
1337
|
+
if (!isInitialized()) return;
|
|
1338
|
+
if (typeof document === "undefined") return;
|
|
1339
|
+
const config2 = getConfig();
|
|
1340
|
+
const carriesCart = cartValue !== void 0 || itemCount !== void 0;
|
|
1341
|
+
const reservedOrder = carriesCart ? reserveCartOrder(config2.storeSlug) : void 0;
|
|
1342
|
+
if (isPlatformPageTrackerActive()) {
|
|
1343
|
+
if (reservedOrder) await enqueueCartSend(async () => sendCartActivity(await reservedOrder, cartValue, itemCount));
|
|
1344
|
+
return;
|
|
1422
1345
|
}
|
|
1423
|
-
const
|
|
1424
|
-
|
|
1425
|
-
|
|
1346
|
+
const sendView = async () => {
|
|
1347
|
+
const order2 = reservedOrder ? await reservedOrder : void 0;
|
|
1348
|
+
const settle2 = order2 ? claimCartReport(config2.storeSlug, order2.seq, cartValue, itemCount) : void 0;
|
|
1349
|
+
const sessionId = analyticsSessionId(config2.storeSlug, { touch: true });
|
|
1350
|
+
const previousSession = currentPageSession();
|
|
1351
|
+
if (previousSession && previousSession !== sessionId) reportPageLeave();
|
|
1352
|
+
markPageViewed(sessionId);
|
|
1353
|
+
if (sessionId) installEngagedClock(reportPageLeave);
|
|
1354
|
+
onAnalyticsConsent(startSessionOnConsent);
|
|
1355
|
+
const delivered = await postPing({
|
|
1356
|
+
referer: document.referrer || void 0,
|
|
1357
|
+
cart_value: cartValue,
|
|
1358
|
+
item_count: itemCount,
|
|
1359
|
+
cart_seq: order2?.seq,
|
|
1360
|
+
cart_seq_scope: order2?.scope,
|
|
1361
|
+
session_id: sessionId ?? void 0,
|
|
1362
|
+
// Time on screen of the page before this one (client-side navigation).
|
|
1363
|
+
engaged_ms: sessionId ? takeEngagedMs() || void 0 : void 0,
|
|
1364
|
+
path: resolveStorefrontPagePath(),
|
|
1365
|
+
utm: resolveUtmParameters(config2.storeSlug)
|
|
1366
|
+
});
|
|
1367
|
+
settle2?.(delivered);
|
|
1368
|
+
};
|
|
1369
|
+
await (reservedOrder ? enqueueCartSend(sendView) : sendView());
|
|
1426
1370
|
}
|
|
1427
|
-
function
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1371
|
+
async function trackCartActivity(cartValue, itemCount) {
|
|
1372
|
+
if (!isInitialized()) return;
|
|
1373
|
+
if (typeof document === "undefined") return;
|
|
1374
|
+
const snapshot = cartSnapshot(cartValue, itemCount);
|
|
1375
|
+
const reservedOrder = reserveCartOrder(getConfig().storeSlug);
|
|
1376
|
+
await enqueueCartSend(async (isLatest) => {
|
|
1377
|
+
const order2 = await reservedOrder;
|
|
1378
|
+
if (!isLatest() || isCartReportedOrInFlight(getConfig().storeSlug, snapshot)) return;
|
|
1379
|
+
await sendCartActivity(order2, cartValue, itemCount);
|
|
1380
|
+
});
|
|
1432
1381
|
}
|
|
1433
|
-
function
|
|
1434
|
-
const
|
|
1435
|
-
|
|
1436
|
-
const
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
writeCartStorage("metaBackup", {
|
|
1448
|
-
created_at: now,
|
|
1449
|
-
last_modified: now,
|
|
1450
|
-
version: 1,
|
|
1451
|
-
checksum: computeChecksum(cart)
|
|
1452
|
-
});
|
|
1453
|
-
}
|
|
1382
|
+
async function sendCartActivity(order2, cartValue, itemCount) {
|
|
1383
|
+
const config2 = getConfig();
|
|
1384
|
+
const settle2 = claimCartReport(config2.storeSlug, order2.seq, cartValue, itemCount);
|
|
1385
|
+
const delivered = await postPing({
|
|
1386
|
+
event_type: "presence",
|
|
1387
|
+
cart_value: cartValue,
|
|
1388
|
+
item_count: itemCount,
|
|
1389
|
+
cart_seq: order2.seq,
|
|
1390
|
+
cart_seq_scope: order2.scope,
|
|
1391
|
+
// A cart marks the analytics session as one that did not bounce.
|
|
1392
|
+
session_id: analyticsSessionId(config2.storeSlug, { touch: false }) ?? void 0,
|
|
1393
|
+
path: resolveStorefrontPagePath()
|
|
1394
|
+
});
|
|
1395
|
+
settle2(delivered);
|
|
1454
1396
|
}
|
|
1455
|
-
function
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
const backupMeta = readCartStorage("metaBackup");
|
|
1459
|
-
const backupCoupon = readCartStorage("couponBackup");
|
|
1460
|
-
if (backup && backup.length > 0) {
|
|
1461
|
-
setCartWithMetadata(backup, backupMeta);
|
|
1462
|
-
if (backupCoupon && typeof backupCoupon === "object" && !Array.isArray(backupCoupon)) {
|
|
1463
|
-
const record2 = backupCoupon;
|
|
1464
|
-
const source = record2.source === "COUPON" || record2.source === "AFFILIATE" ? record2.source : null;
|
|
1465
|
-
if (typeof record2.code === "string" && source) {
|
|
1466
|
-
setCartCoupon(record2.code, source);
|
|
1467
|
-
} else {
|
|
1468
|
-
clearCartCoupon();
|
|
1469
|
-
}
|
|
1470
|
-
} else {
|
|
1471
|
-
clearCartCoupon();
|
|
1472
|
-
}
|
|
1473
|
-
return true;
|
|
1474
|
-
}
|
|
1475
|
-
return false;
|
|
1397
|
+
async function trackProductView(productId) {
|
|
1398
|
+
if (!isInitialized() || typeof document === "undefined" || !productId) return;
|
|
1399
|
+
await sendVisitEvent({ event_type: "product_view", product_id: productId });
|
|
1476
1400
|
}
|
|
1477
|
-
function
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
const productId = typeof incoming.product_id === "string" ? incoming.product_id.trim() : "";
|
|
1481
|
-
const variantId = typeof incoming.variant_id === "string" ? incoming.variant_id.trim() : "";
|
|
1482
|
-
if (!productId || !variantId) {
|
|
1483
|
-
continue;
|
|
1484
|
-
}
|
|
1485
|
-
let normalizedQuantity;
|
|
1486
|
-
try {
|
|
1487
|
-
normalizedQuantity = normalizeQuantity(incoming.quantity);
|
|
1488
|
-
} catch {
|
|
1489
|
-
continue;
|
|
1490
|
-
}
|
|
1491
|
-
if (normalizedQuantity < 1) {
|
|
1492
|
-
continue;
|
|
1493
|
-
}
|
|
1494
|
-
const mergedLine = ensureCartLineId({
|
|
1495
|
-
...incoming,
|
|
1496
|
-
line_id: incoming.line_id ?? computeCartLineId(incoming),
|
|
1497
|
-
product_id: productId,
|
|
1498
|
-
variant_id: variantId,
|
|
1499
|
-
quantity: normalizedQuantity
|
|
1500
|
-
});
|
|
1501
|
-
const index = cart.findIndex((item) => item.line_id === mergedLine.line_id);
|
|
1502
|
-
if (index >= 0) {
|
|
1503
|
-
cart[index].quantity = Math.max(cart[index].quantity, normalizedQuantity);
|
|
1504
|
-
clampQuantityToBounds(cart[index]);
|
|
1505
|
-
} else {
|
|
1506
|
-
clampQuantityToBounds(mergedLine);
|
|
1507
|
-
cart.push(mergedLine);
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
writeCart(cart);
|
|
1511
|
-
return cart;
|
|
1401
|
+
async function trackCartAdd(productId, variantId, quantity) {
|
|
1402
|
+
if (!isInitialized() || typeof document === "undefined" || quantity < 1) return;
|
|
1403
|
+
await sendVisitEvent({ event_type: "cart_add", product_id: productId, variant_id: variantId, quantity });
|
|
1512
1404
|
}
|
|
1513
|
-
function
|
|
1514
|
-
const
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
const toLineId = computeCartLineId({
|
|
1523
|
-
...fromItem,
|
|
1524
|
-
product_id: toProductId,
|
|
1525
|
-
variant_id: toVariantId
|
|
1405
|
+
async function sendVisitEvent(body) {
|
|
1406
|
+
const config2 = getConfig();
|
|
1407
|
+
if (config2.preview) return;
|
|
1408
|
+
await postPing({
|
|
1409
|
+
...body,
|
|
1410
|
+
referer: document.referrer || void 0,
|
|
1411
|
+
session_id: analyticsSessionId(config2.storeSlug, { touch: true }) ?? void 0,
|
|
1412
|
+
path: resolveStorefrontPagePath(),
|
|
1413
|
+
utm: resolveUtmParameters(config2.storeSlug)
|
|
1526
1414
|
});
|
|
1527
|
-
const toIndex = cart.findIndex((item) => item.line_id === toLineId);
|
|
1528
|
-
if (toIndex >= 0) {
|
|
1529
|
-
cart[toIndex].quantity += fromItem.quantity;
|
|
1530
|
-
clampQuantityToBounds(cart[toIndex]);
|
|
1531
|
-
} else {
|
|
1532
|
-
const moved = ensureCartLineId({
|
|
1533
|
-
...fromItem,
|
|
1534
|
-
product_id: toProductId,
|
|
1535
|
-
variant_id: toVariantId,
|
|
1536
|
-
line_id: toLineId
|
|
1537
|
-
});
|
|
1538
|
-
clampQuantityToBounds(moved);
|
|
1539
|
-
cart.push(moved);
|
|
1540
|
-
}
|
|
1541
|
-
writeCart(cart);
|
|
1542
|
-
}
|
|
1543
|
-
function validateCartIntegrity() {
|
|
1544
|
-
const cart = getCart();
|
|
1545
|
-
const metadata = getCartMetadata();
|
|
1546
|
-
const checksum = computeChecksum(cart);
|
|
1547
|
-
if (!metadata) {
|
|
1548
|
-
setCartWithMetadata(cart, null);
|
|
1549
|
-
return true;
|
|
1550
|
-
}
|
|
1551
|
-
return metadata.checksum === checksum;
|
|
1552
1415
|
}
|
|
1553
|
-
function
|
|
1554
|
-
const
|
|
1555
|
-
|
|
1556
|
-
const
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
version: metadata?.version ?? 0,
|
|
1568
|
-
has_backup: backup.length > 0,
|
|
1569
|
-
integrity_valid: integrityValid,
|
|
1570
|
-
total_price: roundPayableAmount(totalPrice),
|
|
1571
|
-
total_price_is_estimate: cart.length > 0 && !hasCompletePriceSnapshots
|
|
1572
|
-
};
|
|
1416
|
+
function startSessionOnConsent() {
|
|
1417
|
+
const config2 = getConfig();
|
|
1418
|
+
if (!isPageViewed() || analyticsSessionId(config2.storeSlug, { touch: false })) return;
|
|
1419
|
+
const sessionId = analyticsSessionId(config2.storeSlug, { touch: true });
|
|
1420
|
+
if (!sessionId) return;
|
|
1421
|
+
markPageViewed(sessionId);
|
|
1422
|
+
installEngagedClock(reportPageLeave);
|
|
1423
|
+
void postPing({
|
|
1424
|
+
event_type: "session_start",
|
|
1425
|
+
referer: document.referrer || void 0,
|
|
1426
|
+
session_id: sessionId,
|
|
1427
|
+
path: resolveStorefrontPagePath(),
|
|
1428
|
+
utm: resolveUtmParameters(config2.storeSlug)
|
|
1429
|
+
});
|
|
1573
1430
|
}
|
|
1574
|
-
function
|
|
1431
|
+
function reportPageLeave() {
|
|
1575
1432
|
const config2 = getConfig();
|
|
1576
|
-
const
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1433
|
+
const sessionId = currentPageSession();
|
|
1434
|
+
const engagedMs2 = takeEngagedMs();
|
|
1435
|
+
if (!sessionId || engagedMs2 === 0 || readAnalyticsConsent() !== "granted") return;
|
|
1436
|
+
try {
|
|
1437
|
+
const endpoint = buildEndpoint("/v1/storefront/shops/:storeSlug/ping", { storeSlug: config2.storeSlug });
|
|
1438
|
+
void fetch(`${config2.apiBaseUrl}${endpoint}`, {
|
|
1439
|
+
method: "POST",
|
|
1440
|
+
headers: { "Content-Type": "application/json" },
|
|
1441
|
+
body: JSON.stringify({ event_type: "page_leave", session_id: sessionId, engaged_ms: engagedMs2 }),
|
|
1442
|
+
keepalive: true
|
|
1443
|
+
}).catch(() => {
|
|
1444
|
+
});
|
|
1445
|
+
} catch {
|
|
1446
|
+
}
|
|
1582
1447
|
}
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1448
|
+
|
|
1449
|
+
// ../sdk/src/utils/cart-line-id.ts
|
|
1450
|
+
function hashString(value) {
|
|
1451
|
+
let hash2 = 2166136261;
|
|
1452
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
1453
|
+
hash2 ^= value.charCodeAt(i);
|
|
1454
|
+
hash2 += (hash2 << 1) + (hash2 << 4) + (hash2 << 7) + (hash2 << 8) + (hash2 << 24);
|
|
1588
1455
|
}
|
|
1589
|
-
return
|
|
1456
|
+
return (hash2 >>> 0).toString(16);
|
|
1590
1457
|
}
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
return latestQuoteToken;
|
|
1458
|
+
function normalizeAddons(addons) {
|
|
1459
|
+
if (!addons?.length) return [];
|
|
1460
|
+
return [...addons].map((addon) => ({ id: addon.id, quantity: addon.quantity ?? 1 })).sort((a, b) => a.id.localeCompare(b.id));
|
|
1595
1461
|
}
|
|
1596
|
-
function
|
|
1597
|
-
|
|
1598
|
-
|
|
1462
|
+
function normalizeCustomFields(fields) {
|
|
1463
|
+
if (!fields) return {};
|
|
1464
|
+
const entries = Object.entries(fields).filter(([, value]) => typeof value === "string").sort(([a], [b]) => a.localeCompare(b));
|
|
1465
|
+
return Object.fromEntries(entries);
|
|
1599
1466
|
}
|
|
1600
|
-
|
|
1601
|
-
const
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1467
|
+
function computeCartLineId(input2) {
|
|
1468
|
+
const payload = {
|
|
1469
|
+
product_id: input2.product_id,
|
|
1470
|
+
variant_id: input2.variant_id,
|
|
1471
|
+
price_variant_id: input2.price_variant_id ?? null,
|
|
1472
|
+
addons: normalizeAddons(input2.addons),
|
|
1473
|
+
custom_fields: normalizeCustomFields(input2.custom_fields),
|
|
1474
|
+
unit_price: typeof input2.price_data?.unit_price === "number" && Number.isFinite(input2.price_data.unit_price) ? input2.price_data.unit_price : null,
|
|
1475
|
+
pay_what_you_want_price: typeof input2.pay_what_you_want_price === "number" && Number.isFinite(input2.pay_what_you_want_price) ? input2.pay_what_you_want_price : null
|
|
1476
|
+
};
|
|
1477
|
+
return hashString(JSON.stringify(payload));
|
|
1478
|
+
}
|
|
1479
|
+
function ensureCartLineId(item) {
|
|
1480
|
+
if (typeof item.line_id === "string" && item.line_id.trim()) {
|
|
1481
|
+
return item;
|
|
1614
1482
|
}
|
|
1615
|
-
return
|
|
1483
|
+
return { ...item, line_id: computeCartLineId(item) };
|
|
1616
1484
|
}
|
|
1617
1485
|
|
|
1618
|
-
// ../contracts/src/
|
|
1619
|
-
var
|
|
1620
|
-
var
|
|
1621
|
-
var
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1486
|
+
// ../contracts/src/catalog-unit-price.ts
|
|
1487
|
+
var CATALOG_UNIT_PRICE_DECIMAL_PLACES = 3;
|
|
1488
|
+
var PAYABLE_AMOUNT_DECIMAL_PLACES = 2;
|
|
1489
|
+
var CATALOG_UNIT_PRICE_FORMAT_OPTIONS = {
|
|
1490
|
+
maximumFractionDigits: CATALOG_UNIT_PRICE_DECIMAL_PLACES
|
|
1491
|
+
};
|
|
1492
|
+
function roundPayableAmount(value) {
|
|
1493
|
+
if (!Number.isFinite(value)) return value;
|
|
1494
|
+
const sign = value < 0 ? -1 : 1;
|
|
1495
|
+
const shifted = shiftDecimal(Math.abs(value), PAYABLE_AMOUNT_DECIMAL_PLACES);
|
|
1496
|
+
const rounded = Math.round(shifted);
|
|
1497
|
+
if (rounded === 0) return 0;
|
|
1498
|
+
return sign * shiftDecimal(rounded, -PAYABLE_AMOUNT_DECIMAL_PLACES);
|
|
1499
|
+
}
|
|
1500
|
+
function shiftDecimal(value, places) {
|
|
1501
|
+
const [coefficient, currentExponent = "0"] = String(value).split("e");
|
|
1502
|
+
return Number(`${coefficient}e${Number(currentExponent) + places}`);
|
|
1626
1503
|
}
|
|
1627
1504
|
|
|
1628
|
-
// ../sdk/src/
|
|
1629
|
-
var
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1505
|
+
// ../sdk/src/modules/cart.ts
|
|
1506
|
+
var STORAGE_KEYS = {
|
|
1507
|
+
cart: "cart",
|
|
1508
|
+
cartBackup: "cart_backup",
|
|
1509
|
+
meta: "cart_meta",
|
|
1510
|
+
metaBackup: "cart_backup_meta",
|
|
1511
|
+
coupon: "cart_coupon",
|
|
1512
|
+
couponBackup: "cart_coupon_backup"
|
|
1513
|
+
};
|
|
1514
|
+
function getStorageKey(type) {
|
|
1515
|
+
return `${STORAGE_KEYS[type]}_${getConfig().storeSlug}`;
|
|
1516
|
+
}
|
|
1517
|
+
function cartStorageArea() {
|
|
1518
|
+
return getConfig().preview ? "sessionStorage" : "localStorage";
|
|
1519
|
+
}
|
|
1520
|
+
function readCartStorage(type) {
|
|
1521
|
+
return getItem(getStorageKey(type), cartStorageArea());
|
|
1522
|
+
}
|
|
1523
|
+
function writeCartStorage(type, value) {
|
|
1524
|
+
setItem(getStorageKey(type), value, cartStorageArea());
|
|
1525
|
+
}
|
|
1526
|
+
function removeCartStorage(type) {
|
|
1527
|
+
removeItem(getStorageKey(type), cartStorageArea());
|
|
1528
|
+
}
|
|
1529
|
+
function hashString2(value) {
|
|
1530
|
+
let hash2 = 2166136261;
|
|
1531
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
1532
|
+
hash2 ^= value.charCodeAt(i);
|
|
1533
|
+
hash2 += (hash2 << 1) + (hash2 << 4) + (hash2 << 7) + (hash2 << 8) + (hash2 << 24);
|
|
1645
1534
|
}
|
|
1646
|
-
|
|
1647
|
-
if (!choice) return "unknown";
|
|
1648
|
-
return choice.analytics ? "granted" : "declined";
|
|
1535
|
+
return (hash2 >>> 0).toString(16);
|
|
1649
1536
|
}
|
|
1650
|
-
function
|
|
1651
|
-
|
|
1652
|
-
if (!Array.isArray(stored)) return [];
|
|
1653
|
-
return stored.filter((visit2) => typeof visit2?.id === "string" && typeof visit2.at === "number" && now - visit2.at < ANALYTICS_VISITS_WINDOW_MS);
|
|
1537
|
+
function computeChecksum(cart) {
|
|
1538
|
+
return hashString2(JSON.stringify(cart));
|
|
1654
1539
|
}
|
|
1655
|
-
function
|
|
1656
|
-
|
|
1657
|
-
|
|
1540
|
+
function normalizeQuantity(value) {
|
|
1541
|
+
if (!Number.isFinite(value)) {
|
|
1542
|
+
throw new CartError("quantity must be a finite number");
|
|
1543
|
+
}
|
|
1544
|
+
return Math.floor(value);
|
|
1658
1545
|
}
|
|
1659
|
-
function
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1546
|
+
function normalizeCouponCode(value) {
|
|
1547
|
+
const normalized = value?.trim().toUpperCase();
|
|
1548
|
+
return normalized ? normalized : null;
|
|
1549
|
+
}
|
|
1550
|
+
function getStoredCartCode() {
|
|
1551
|
+
const raw = readCartStorage("coupon");
|
|
1552
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
1663
1553
|
return null;
|
|
1664
1554
|
}
|
|
1665
|
-
const
|
|
1666
|
-
const
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1555
|
+
const record2 = raw;
|
|
1556
|
+
const code = typeof record2.code === "string" ? normalizeCouponCode(record2.code) : null;
|
|
1557
|
+
const source = record2.source === "COUPON" || record2.source === "AFFILIATE" ? record2.source : null;
|
|
1558
|
+
return code && source ? { code, source } : null;
|
|
1559
|
+
}
|
|
1560
|
+
function normalizeCartItems(value) {
|
|
1561
|
+
if (!Array.isArray(value)) return [];
|
|
1562
|
+
const normalized = [];
|
|
1563
|
+
for (const entry of value) {
|
|
1564
|
+
if (!entry || typeof entry !== "object") continue;
|
|
1565
|
+
const record2 = entry;
|
|
1566
|
+
const productId = typeof record2.product_id === "string" ? record2.product_id.trim() : "";
|
|
1567
|
+
const variantId = typeof record2.variant_id === "string" ? record2.variant_id.trim() : "";
|
|
1568
|
+
const quantity = Number(record2.quantity);
|
|
1569
|
+
if (!productId || !variantId || !Number.isFinite(quantity) || quantity < 1) {
|
|
1570
|
+
continue;
|
|
1571
|
+
}
|
|
1572
|
+
const item = {
|
|
1573
|
+
line_id: "",
|
|
1574
|
+
product_id: productId,
|
|
1575
|
+
variant_id: variantId,
|
|
1576
|
+
quantity: Math.floor(quantity)
|
|
1577
|
+
};
|
|
1578
|
+
if (typeof record2.price_variant_id === "string") {
|
|
1579
|
+
item.price_variant_id = record2.price_variant_id;
|
|
1580
|
+
}
|
|
1581
|
+
if (record2.price_data && typeof record2.price_data === "object") {
|
|
1582
|
+
const priceData = record2.price_data;
|
|
1583
|
+
if (typeof priceData.unit_price === "number" && Number.isFinite(priceData.unit_price)) {
|
|
1584
|
+
item.price_data = { unit_price: priceData.unit_price };
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
if (typeof record2.pay_what_you_want_price === "number" && Number.isFinite(record2.pay_what_you_want_price)) {
|
|
1588
|
+
item.pay_what_you_want_price = record2.pay_what_you_want_price;
|
|
1589
|
+
}
|
|
1590
|
+
if (Array.isArray(record2.addons)) {
|
|
1591
|
+
item.addons = record2.addons;
|
|
1592
|
+
}
|
|
1593
|
+
if (record2.custom_fields && typeof record2.custom_fields === "object" && !Array.isArray(record2.custom_fields)) {
|
|
1594
|
+
item.custom_fields = record2.custom_fields;
|
|
1595
|
+
}
|
|
1596
|
+
if (typeof record2.title === "string") {
|
|
1597
|
+
item.title = record2.title;
|
|
1598
|
+
}
|
|
1599
|
+
if (typeof record2.variant_title === "string") {
|
|
1600
|
+
item.variant_title = record2.variant_title;
|
|
1601
|
+
}
|
|
1602
|
+
if (typeof record2.image_url === "string") {
|
|
1603
|
+
item.image_url = record2.image_url;
|
|
1604
|
+
}
|
|
1605
|
+
if (Array.isArray(record2.addon_labels)) {
|
|
1606
|
+
item.addon_labels = record2.addon_labels.filter((label) => typeof label === "string");
|
|
1607
|
+
}
|
|
1608
|
+
if (typeof record2.max_quantity === "number" && Number.isFinite(record2.max_quantity)) {
|
|
1609
|
+
item.max_quantity = record2.max_quantity;
|
|
1610
|
+
}
|
|
1611
|
+
if (typeof record2.min_quantity === "number" && Number.isFinite(record2.min_quantity)) {
|
|
1612
|
+
item.min_quantity = record2.min_quantity;
|
|
1613
|
+
}
|
|
1614
|
+
clampQuantityToBounds(item);
|
|
1615
|
+
const storedLineId = typeof record2.line_id === "string" ? record2.line_id.trim() : "";
|
|
1616
|
+
item.line_id = storedLineId || computeCartLineId(item);
|
|
1617
|
+
normalized.push(ensureCartLineId(item));
|
|
1671
1618
|
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
);
|
|
1679
|
-
|
|
1619
|
+
return normalized;
|
|
1620
|
+
}
|
|
1621
|
+
function getCartMetadata() {
|
|
1622
|
+
return readCartStorage("meta");
|
|
1623
|
+
}
|
|
1624
|
+
function getCartCoupon() {
|
|
1625
|
+
return getStoredCartCode()?.code ?? null;
|
|
1626
|
+
}
|
|
1627
|
+
function getCartCouponSource() {
|
|
1628
|
+
return getStoredCartCode()?.source ?? null;
|
|
1680
1629
|
}
|
|
1681
|
-
function
|
|
1682
|
-
const
|
|
1683
|
-
if (
|
|
1684
|
-
|
|
1685
|
-
return
|
|
1630
|
+
function setCartCoupon(coupon, source = "COUPON") {
|
|
1631
|
+
const normalizedCoupon = normalizeCouponCode(coupon);
|
|
1632
|
+
if (!normalizedCoupon) {
|
|
1633
|
+
removeCartStorage("coupon");
|
|
1634
|
+
return null;
|
|
1686
1635
|
}
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
return sessionIds.length > 0 ? { session_ids: sessionIds } : void 0;
|
|
1636
|
+
writeCartStorage("coupon", { code: normalizedCoupon, source });
|
|
1637
|
+
return normalizedCoupon;
|
|
1690
1638
|
}
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
var clockInstalled = false;
|
|
1694
|
-
var pageViewed = false;
|
|
1695
|
-
var pageSession = null;
|
|
1696
|
-
function markPageViewed(sessionId) {
|
|
1697
|
-
pageViewed = true;
|
|
1698
|
-
pageSession = sessionId;
|
|
1639
|
+
function clearCartCoupon() {
|
|
1640
|
+
removeCartStorage("coupon");
|
|
1699
1641
|
}
|
|
1700
|
-
function
|
|
1701
|
-
|
|
1642
|
+
function writeCart(cart) {
|
|
1643
|
+
const normalizedCart = normalizeCartItems(cart);
|
|
1644
|
+
writeCartStorage("cart", normalizedCart);
|
|
1645
|
+
const now = Date.now();
|
|
1646
|
+
const previous = getCartMetadata();
|
|
1647
|
+
const nextMeta = {
|
|
1648
|
+
created_at: previous?.created_at ?? now,
|
|
1649
|
+
last_modified: now,
|
|
1650
|
+
version: (previous?.version ?? 0) + 1,
|
|
1651
|
+
checksum: computeChecksum(normalizedCart)
|
|
1652
|
+
};
|
|
1653
|
+
writeCartStorage("meta", nextMeta);
|
|
1654
|
+
if (normalizedCart.length === 0) {
|
|
1655
|
+
clearCartCoupon();
|
|
1656
|
+
}
|
|
1702
1657
|
}
|
|
1703
|
-
function
|
|
1704
|
-
|
|
1658
|
+
function setCartWithMetadata(cart, metadata) {
|
|
1659
|
+
const normalizedCart = normalizeCartItems(cart);
|
|
1660
|
+
writeCartStorage("cart", normalizedCart);
|
|
1661
|
+
const now = Date.now();
|
|
1662
|
+
const base = metadata ?? getCartMetadata();
|
|
1663
|
+
const nextMeta = {
|
|
1664
|
+
created_at: base?.created_at ?? now,
|
|
1665
|
+
last_modified: now,
|
|
1666
|
+
version: base?.version ?? 1,
|
|
1667
|
+
checksum: computeChecksum(normalizedCart)
|
|
1668
|
+
};
|
|
1669
|
+
writeCartStorage("meta", nextMeta);
|
|
1705
1670
|
}
|
|
1706
|
-
function
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1671
|
+
function getCart() {
|
|
1672
|
+
const raw = readCartStorage("cart");
|
|
1673
|
+
return normalizeCartItems(raw);
|
|
1674
|
+
}
|
|
1675
|
+
function resolveCartLineId(productId, variantId, cart = getCart()) {
|
|
1676
|
+
const matches = cart.filter(
|
|
1677
|
+
(item) => item.product_id === productId && item.variant_id === variantId
|
|
1678
|
+
);
|
|
1679
|
+
if (matches.length === 0) {
|
|
1680
|
+
throw new CartError(`No cart line found for ${productId}/${variantId}`);
|
|
1710
1681
|
}
|
|
1682
|
+
return matches[0].line_id;
|
|
1711
1683
|
}
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
consentListenerInstalled = true;
|
|
1716
|
-
window.addEventListener("shoppex:consent", () => {
|
|
1717
|
-
if (readAnalyticsConsent() === "granted") onYes();
|
|
1718
|
-
});
|
|
1684
|
+
function getCartItemCount() {
|
|
1685
|
+
const cart = getCart();
|
|
1686
|
+
return cart.reduce((sum, item) => sum + item.quantity, 0);
|
|
1719
1687
|
}
|
|
1720
|
-
function
|
|
1721
|
-
if (
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
onHidden();
|
|
1738
|
-
});
|
|
1739
|
-
window.addEventListener("pageshow", (event) => {
|
|
1740
|
-
if (event.persisted && document.visibilityState === "visible") visibleSince = Date.now();
|
|
1688
|
+
function addToCart(productId, variantId, quantity = 1, options) {
|
|
1689
|
+
if (!productId || !variantId) {
|
|
1690
|
+
throw new CartError("product_id and variant_id are required");
|
|
1691
|
+
}
|
|
1692
|
+
const normalizedQuantity = normalizeQuantity(quantity);
|
|
1693
|
+
if (normalizedQuantity < 1) {
|
|
1694
|
+
throw new CartError("quantity must be at least 1");
|
|
1695
|
+
}
|
|
1696
|
+
const cart = getCart();
|
|
1697
|
+
const lineId = computeCartLineId({
|
|
1698
|
+
product_id: productId,
|
|
1699
|
+
variant_id: variantId,
|
|
1700
|
+
addons: options?.addons,
|
|
1701
|
+
custom_fields: options?.custom_fields,
|
|
1702
|
+
price_variant_id: options?.price_variant_id,
|
|
1703
|
+
price_data: options?.price_data,
|
|
1704
|
+
pay_what_you_want_price: options?.pay_what_you_want_price
|
|
1741
1705
|
});
|
|
1706
|
+
const existingIndex = cart.findIndex((item) => item.line_id === lineId);
|
|
1707
|
+
const quantityBeforeAdd = existingIndex >= 0 ? cart[existingIndex].quantity : 0;
|
|
1708
|
+
if (existingIndex >= 0) {
|
|
1709
|
+
cart[existingIndex].quantity += normalizedQuantity;
|
|
1710
|
+
if (options?.addons) {
|
|
1711
|
+
cart[existingIndex].addons = options.addons;
|
|
1712
|
+
}
|
|
1713
|
+
if (options?.custom_fields) {
|
|
1714
|
+
cart[existingIndex].custom_fields = options.custom_fields;
|
|
1715
|
+
}
|
|
1716
|
+
if (options?.price_variant_id) {
|
|
1717
|
+
cart[existingIndex].price_variant_id = options.price_variant_id;
|
|
1718
|
+
}
|
|
1719
|
+
if (options?.price_data) {
|
|
1720
|
+
cart[existingIndex].price_data = options.price_data;
|
|
1721
|
+
}
|
|
1722
|
+
if (options?.pay_what_you_want_price !== void 0) {
|
|
1723
|
+
cart[existingIndex].pay_what_you_want_price = options.pay_what_you_want_price;
|
|
1724
|
+
}
|
|
1725
|
+
applyDisplaySnapshot(cart[existingIndex], options);
|
|
1726
|
+
clampQuantityToBounds(cart[existingIndex]);
|
|
1727
|
+
} else {
|
|
1728
|
+
const pushed = {
|
|
1729
|
+
line_id: lineId,
|
|
1730
|
+
product_id: productId,
|
|
1731
|
+
variant_id: variantId,
|
|
1732
|
+
quantity: normalizedQuantity,
|
|
1733
|
+
addons: options?.addons,
|
|
1734
|
+
custom_fields: options?.custom_fields,
|
|
1735
|
+
price_variant_id: options?.price_variant_id,
|
|
1736
|
+
price_data: options?.price_data,
|
|
1737
|
+
pay_what_you_want_price: options?.pay_what_you_want_price,
|
|
1738
|
+
title: options?.title,
|
|
1739
|
+
variant_title: options?.variant_title,
|
|
1740
|
+
image_url: options?.image_url,
|
|
1741
|
+
addon_labels: options?.addon_labels,
|
|
1742
|
+
max_quantity: options?.max_quantity,
|
|
1743
|
+
min_quantity: options?.min_quantity
|
|
1744
|
+
};
|
|
1745
|
+
clampQuantityToBounds(pushed);
|
|
1746
|
+
cart.push(pushed);
|
|
1747
|
+
}
|
|
1748
|
+
const intendedQuantity = (existingIndex >= 0 ? cart[existingIndex] : cart[cart.length - 1]).quantity;
|
|
1749
|
+
writeCart(cart);
|
|
1750
|
+
const persistedLine = getCart().find((item) => item.line_id === lineId);
|
|
1751
|
+
if (intendedQuantity > quantityBeforeAdd && persistedLine?.quantity === intendedQuantity) {
|
|
1752
|
+
const cartAffiliateCode = getCartCouponSource() === "AFFILIATE" ? getCartCoupon() : null;
|
|
1753
|
+
void trackAffiliateEvent("add_to_cart", cartAffiliateCode ? { code: cartAffiliateCode } : void 0);
|
|
1754
|
+
void trackCartAdd(productId, variantId, intendedQuantity - quantityBeforeAdd);
|
|
1755
|
+
}
|
|
1742
1756
|
}
|
|
1743
|
-
function
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
return taken;
|
|
1748
|
-
}
|
|
1749
|
-
|
|
1750
|
-
// ../sdk/src/core/attribution.ts
|
|
1751
|
-
var STORAGE_PREFIX2 = "shoppex:utm:";
|
|
1752
|
-
var TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
1753
|
-
var UTM_KEYS = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
|
|
1754
|
-
var MAX_VALUE_LENGTH = 255;
|
|
1755
|
-
function readFromUrl(search) {
|
|
1756
|
-
let params;
|
|
1757
|
-
try {
|
|
1758
|
-
params = new URLSearchParams(search);
|
|
1759
|
-
} catch {
|
|
1760
|
-
return {};
|
|
1757
|
+
function clampQuantityToBounds(item) {
|
|
1758
|
+
const min = item.min_quantity;
|
|
1759
|
+
if (typeof min === "number" && Number.isFinite(min) && item.quantity < min) {
|
|
1760
|
+
item.quantity = Math.floor(min);
|
|
1761
1761
|
}
|
|
1762
|
-
const
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1762
|
+
const max = item.max_quantity;
|
|
1763
|
+
if (typeof max === "number" && Number.isFinite(max) && item.quantity > max) {
|
|
1764
|
+
item.quantity = Math.floor(max);
|
|
1765
|
+
}
|
|
1766
|
+
if (item.quantity < 1) {
|
|
1767
|
+
item.quantity = 1;
|
|
1768
1768
|
}
|
|
1769
|
-
return utm;
|
|
1770
1769
|
}
|
|
1771
|
-
function
|
|
1772
|
-
|
|
1770
|
+
function applyDisplaySnapshot(item, options) {
|
|
1771
|
+
if (options?.replace_display_snapshot) {
|
|
1772
|
+
item.title = options.title;
|
|
1773
|
+
item.variant_title = options.variant_title;
|
|
1774
|
+
item.image_url = options.image_url;
|
|
1775
|
+
item.addon_labels = options.addon_labels;
|
|
1776
|
+
item.max_quantity = options.max_quantity;
|
|
1777
|
+
item.min_quantity = options.min_quantity;
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
if (options?.title !== void 0) {
|
|
1781
|
+
item.title = options.title;
|
|
1782
|
+
}
|
|
1783
|
+
if (options?.variant_title !== void 0) {
|
|
1784
|
+
item.variant_title = options.variant_title;
|
|
1785
|
+
}
|
|
1786
|
+
if (options?.image_url !== void 0) {
|
|
1787
|
+
item.image_url = options.image_url;
|
|
1788
|
+
}
|
|
1789
|
+
if (options?.addon_labels !== void 0) {
|
|
1790
|
+
item.addon_labels = options.addon_labels;
|
|
1791
|
+
}
|
|
1792
|
+
if (options?.max_quantity !== void 0) {
|
|
1793
|
+
item.max_quantity = options.max_quantity;
|
|
1794
|
+
}
|
|
1795
|
+
if (options?.min_quantity !== void 0) {
|
|
1796
|
+
item.min_quantity = options.min_quantity;
|
|
1797
|
+
}
|
|
1773
1798
|
}
|
|
1774
|
-
function
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1799
|
+
function setCartItem(productId, variantId, quantity = 1, options) {
|
|
1800
|
+
if (!productId || !variantId) {
|
|
1801
|
+
throw new CartError("product_id and variant_id are required");
|
|
1802
|
+
}
|
|
1803
|
+
const normalizedQuantity = normalizeQuantity(quantity);
|
|
1804
|
+
if (normalizedQuantity < 1) {
|
|
1805
|
+
throw new CartError("quantity must be at least 1");
|
|
1806
|
+
}
|
|
1807
|
+
const cart = getCart();
|
|
1808
|
+
const lineId = computeCartLineId({
|
|
1809
|
+
product_id: productId,
|
|
1810
|
+
variant_id: variantId,
|
|
1811
|
+
addons: options?.addons,
|
|
1812
|
+
custom_fields: options?.custom_fields,
|
|
1813
|
+
price_variant_id: options?.price_variant_id,
|
|
1814
|
+
price_data: options?.price_data,
|
|
1815
|
+
pay_what_you_want_price: options?.pay_what_you_want_price
|
|
1816
|
+
});
|
|
1817
|
+
for (let index = cart.length - 1; index >= 0; index -= 1) {
|
|
1818
|
+
if (cart[index].product_id === productId && cart[index].variant_id === variantId) {
|
|
1819
|
+
cart.splice(index, 1);
|
|
1790
1820
|
}
|
|
1791
|
-
return utm;
|
|
1792
|
-
} catch {
|
|
1793
|
-
return {};
|
|
1794
1821
|
}
|
|
1822
|
+
const pushed = {
|
|
1823
|
+
line_id: lineId,
|
|
1824
|
+
product_id: productId,
|
|
1825
|
+
variant_id: variantId,
|
|
1826
|
+
quantity: normalizedQuantity,
|
|
1827
|
+
addons: options?.addons,
|
|
1828
|
+
custom_fields: options?.custom_fields,
|
|
1829
|
+
price_variant_id: options?.price_variant_id,
|
|
1830
|
+
price_data: options?.price_data,
|
|
1831
|
+
pay_what_you_want_price: options?.pay_what_you_want_price,
|
|
1832
|
+
title: options?.title,
|
|
1833
|
+
variant_title: options?.variant_title,
|
|
1834
|
+
image_url: options?.image_url,
|
|
1835
|
+
addon_labels: options?.addon_labels,
|
|
1836
|
+
max_quantity: options?.max_quantity,
|
|
1837
|
+
min_quantity: options?.min_quantity
|
|
1838
|
+
};
|
|
1839
|
+
clampQuantityToBounds(pushed);
|
|
1840
|
+
cart.push(pushed);
|
|
1841
|
+
writeCart(cart);
|
|
1842
|
+
const persistedLine = getCart().find((item) => item.line_id === lineId);
|
|
1843
|
+
if (persistedLine) void trackCartAdd(productId, variantId, persistedLine.quantity);
|
|
1795
1844
|
}
|
|
1796
|
-
function
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1845
|
+
function updateCartItem(lineId, updates) {
|
|
1846
|
+
const cart = getCart();
|
|
1847
|
+
const normalizedLineId = lineId.trim();
|
|
1848
|
+
if (!normalizedLineId) {
|
|
1849
|
+
throw new CartError("line_id is required");
|
|
1801
1850
|
}
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
return void 0;
|
|
1851
|
+
const index = cart.findIndex((item) => item.line_id === normalizedLineId);
|
|
1852
|
+
if (index < 0) {
|
|
1853
|
+
throw new CartError("Item not found in cart");
|
|
1806
1854
|
}
|
|
1807
|
-
const
|
|
1808
|
-
if (
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1855
|
+
const before = JSON.stringify(cart);
|
|
1856
|
+
if (updates.quantity !== void 0) {
|
|
1857
|
+
const normalizedQuantity = normalizeQuantity(updates.quantity);
|
|
1858
|
+
if (normalizedQuantity < 1) {
|
|
1859
|
+
cart.splice(index, 1);
|
|
1860
|
+
writeCart(cart);
|
|
1861
|
+
return;
|
|
1812
1862
|
}
|
|
1813
|
-
|
|
1863
|
+
cart[index].quantity = normalizedQuantity;
|
|
1814
1864
|
}
|
|
1815
|
-
if (
|
|
1816
|
-
|
|
1817
|
-
return fromUrl;
|
|
1865
|
+
if (updates.addons !== void 0) {
|
|
1866
|
+
cart[index].addons = updates.addons;
|
|
1818
1867
|
}
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
}
|
|
1822
|
-
|
|
1823
|
-
// ../sdk/src/core/page-path.ts
|
|
1824
|
-
var MAX_PATH_LENGTH = 256;
|
|
1825
|
-
function resolveStorefrontPagePath() {
|
|
1826
|
-
if (typeof window === "undefined") return void 0;
|
|
1827
|
-
let pathname;
|
|
1828
|
-
try {
|
|
1829
|
-
const location = window.location;
|
|
1830
|
-
pathname = typeof location?.pathname === "string" && location.pathname ? location.pathname : new URL(String(location?.href ?? "")).pathname;
|
|
1831
|
-
} catch {
|
|
1832
|
-
return void 0;
|
|
1868
|
+
if (updates.custom_fields !== void 0) {
|
|
1869
|
+
cart[index].custom_fields = updates.custom_fields;
|
|
1833
1870
|
}
|
|
1834
|
-
if (
|
|
1835
|
-
|
|
1836
|
-
}
|
|
1837
|
-
|
|
1838
|
-
// ../sdk/src/core/page-tracker.ts
|
|
1839
|
-
var PLATFORM_PAGE_TRACKER_FLAG = "__shoppexPageTracker";
|
|
1840
|
-
function isPlatformPageTrackerActive() {
|
|
1841
|
-
if (typeof window === "undefined") return false;
|
|
1842
|
-
try {
|
|
1843
|
-
return Boolean(window[PLATFORM_PAGE_TRACKER_FLAG]);
|
|
1844
|
-
} catch {
|
|
1845
|
-
return false;
|
|
1871
|
+
if (updates.price_variant_id !== void 0) {
|
|
1872
|
+
cart[index].price_variant_id = updates.price_variant_id;
|
|
1846
1873
|
}
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
// ../sdk/src/modules/analytics.ts
|
|
1850
|
-
var CONFIRMED_CART_STORAGE_PREFIX = "reported_cart_";
|
|
1851
|
-
var IN_FLIGHT_CART_STORAGE_PREFIX = "reporting_cart_";
|
|
1852
|
-
var CART_SEQUENCE_STORAGE_PREFIX = "presence_cart_seq_";
|
|
1853
|
-
var CART_CLAIM_TTL_MS = 1e4;
|
|
1854
|
-
function confirmedCartKey(storeSlug) {
|
|
1855
|
-
return `${CONFIRMED_CART_STORAGE_PREFIX}${storeSlug}`;
|
|
1856
|
-
}
|
|
1857
|
-
function inFlightCartKey(storeSlug) {
|
|
1858
|
-
return `${IN_FLIGHT_CART_STORAGE_PREFIX}${storeSlug}`;
|
|
1859
|
-
}
|
|
1860
|
-
function cartSequenceKey(storeSlug) {
|
|
1861
|
-
return `${CART_SEQUENCE_STORAGE_PREFIX}${storeSlug}`;
|
|
1862
|
-
}
|
|
1863
|
-
function cartSnapshot(cartValue, itemCount) {
|
|
1864
|
-
return `${cartValue ?? ""}|${itemCount ?? ""}`;
|
|
1865
|
-
}
|
|
1866
|
-
function isCartSequence(value) {
|
|
1867
|
-
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
1868
|
-
}
|
|
1869
|
-
var CART_SEQUENCE_SCOPE_MAX_LENGTH = 64;
|
|
1870
|
-
function readCartCounter(storeSlug) {
|
|
1871
|
-
const counter = getItem(cartSequenceKey(storeSlug));
|
|
1872
|
-
if (!counter || typeof counter.scope !== "string" || counter.scope.length === 0 || counter.scope.length > CART_SEQUENCE_SCOPE_MAX_LENGTH || !isCartSequence(counter.seq)) {
|
|
1873
|
-
return null;
|
|
1874
|
+
if (updates.price_data !== void 0) {
|
|
1875
|
+
cart[index].price_data = updates.price_data;
|
|
1874
1876
|
}
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
}
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
if (
|
|
1901
|
-
|
|
1877
|
+
if (updates.pay_what_you_want_price !== void 0) {
|
|
1878
|
+
cart[index].pay_what_you_want_price = updates.pay_what_you_want_price;
|
|
1879
|
+
}
|
|
1880
|
+
if (updates.variant_title !== void 0) {
|
|
1881
|
+
if (updates.variant_title === null) delete cart[index].variant_title;
|
|
1882
|
+
else cart[index].variant_title = updates.variant_title;
|
|
1883
|
+
}
|
|
1884
|
+
if (updates.max_quantity !== void 0) {
|
|
1885
|
+
if (updates.max_quantity === null) delete cart[index].max_quantity;
|
|
1886
|
+
else cart[index].max_quantity = updates.max_quantity;
|
|
1887
|
+
}
|
|
1888
|
+
if (updates.min_quantity !== void 0) {
|
|
1889
|
+
if (updates.min_quantity === null) delete cart[index].min_quantity;
|
|
1890
|
+
else cart[index].min_quantity = updates.min_quantity;
|
|
1891
|
+
}
|
|
1892
|
+
clampQuantityToBounds(cart[index]);
|
|
1893
|
+
const nextLineId = computeCartLineId(cart[index]);
|
|
1894
|
+
const duplicateIndex = cart.findIndex((item, itemIndex) => itemIndex !== index && item.line_id === nextLineId);
|
|
1895
|
+
if (duplicateIndex >= 0) {
|
|
1896
|
+
cart[duplicateIndex].quantity += cart[index].quantity;
|
|
1897
|
+
clampQuantityToBounds(cart[duplicateIndex]);
|
|
1898
|
+
cart.splice(index, 1);
|
|
1899
|
+
} else {
|
|
1900
|
+
cart[index].line_id = nextLineId;
|
|
1901
|
+
}
|
|
1902
|
+
if (JSON.stringify(cart) === before) return;
|
|
1903
|
+
writeCart(cart);
|
|
1902
1904
|
}
|
|
1903
|
-
function
|
|
1904
|
-
const
|
|
1905
|
-
if (!
|
|
1906
|
-
|
|
1905
|
+
function removeFromCart(lineId) {
|
|
1906
|
+
const normalizedLineId = lineId.trim();
|
|
1907
|
+
if (!normalizedLineId) {
|
|
1908
|
+
throw new CartError("line_id is required");
|
|
1907
1909
|
}
|
|
1908
|
-
|
|
1910
|
+
const cart = getCart();
|
|
1911
|
+
const filtered = cart.filter((item) => item.line_id !== normalizedLineId);
|
|
1912
|
+
writeCart(filtered);
|
|
1909
1913
|
}
|
|
1910
|
-
function
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
return expected?.snapshot === snapshot;
|
|
1914
|
+
function clearCart() {
|
|
1915
|
+
removeCartStorage("cart");
|
|
1916
|
+
removeCartStorage("meta");
|
|
1917
|
+
clearCartCoupon();
|
|
1918
|
+
clearLatestQuoteToken();
|
|
1916
1919
|
}
|
|
1917
|
-
function
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
+
function createCartBackup() {
|
|
1921
|
+
const cart = getCart();
|
|
1922
|
+
writeCartStorage("cartBackup", cart);
|
|
1923
|
+
const cartCode = getStoredCartCode();
|
|
1924
|
+
if (cartCode) {
|
|
1925
|
+
writeCartStorage("couponBackup", cartCode);
|
|
1926
|
+
} else {
|
|
1927
|
+
removeCartStorage("couponBackup");
|
|
1928
|
+
}
|
|
1929
|
+
const metadata = getCartMetadata();
|
|
1930
|
+
if (metadata) {
|
|
1931
|
+
writeCartStorage("metaBackup", metadata);
|
|
1932
|
+
} else {
|
|
1933
|
+
const now = Date.now();
|
|
1934
|
+
writeCartStorage("metaBackup", {
|
|
1935
|
+
created_at: now,
|
|
1936
|
+
last_modified: now,
|
|
1937
|
+
version: 1,
|
|
1938
|
+
checksum: computeChecksum(cart)
|
|
1939
|
+
});
|
|
1940
|
+
}
|
|
1920
1941
|
}
|
|
1921
|
-
function
|
|
1922
|
-
const
|
|
1923
|
-
const
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1942
|
+
function restoreCartFromBackup() {
|
|
1943
|
+
const backupRaw = readCartStorage("cartBackup");
|
|
1944
|
+
const backup = normalizeCartItems(backupRaw);
|
|
1945
|
+
const backupMeta = readCartStorage("metaBackup");
|
|
1946
|
+
const backupCoupon = readCartStorage("couponBackup");
|
|
1947
|
+
if (backup && backup.length > 0) {
|
|
1948
|
+
setCartWithMetadata(backup, backupMeta);
|
|
1949
|
+
if (backupCoupon && typeof backupCoupon === "object" && !Array.isArray(backupCoupon)) {
|
|
1950
|
+
const record2 = backupCoupon;
|
|
1951
|
+
const source = record2.source === "COUPON" || record2.source === "AFFILIATE" ? record2.source : null;
|
|
1952
|
+
if (typeof record2.code === "string" && source) {
|
|
1953
|
+
setCartCoupon(record2.code, source);
|
|
1954
|
+
} else {
|
|
1955
|
+
clearCartCoupon();
|
|
1956
|
+
}
|
|
1957
|
+
} else {
|
|
1958
|
+
clearCartCoupon();
|
|
1929
1959
|
}
|
|
1930
|
-
|
|
1931
|
-
}
|
|
1960
|
+
return true;
|
|
1961
|
+
}
|
|
1962
|
+
return false;
|
|
1932
1963
|
}
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1964
|
+
function mergeBaskets(items) {
|
|
1965
|
+
const cart = getCart();
|
|
1966
|
+
for (const incoming of items) {
|
|
1967
|
+
const productId = typeof incoming.product_id === "string" ? incoming.product_id.trim() : "";
|
|
1968
|
+
const variantId = typeof incoming.variant_id === "string" ? incoming.variant_id.trim() : "";
|
|
1969
|
+
if (!productId || !variantId) {
|
|
1970
|
+
continue;
|
|
1971
|
+
}
|
|
1972
|
+
let normalizedQuantity;
|
|
1973
|
+
try {
|
|
1974
|
+
normalizedQuantity = normalizeQuantity(incoming.quantity);
|
|
1975
|
+
} catch {
|
|
1976
|
+
continue;
|
|
1977
|
+
}
|
|
1978
|
+
if (normalizedQuantity < 1) {
|
|
1979
|
+
continue;
|
|
1980
|
+
}
|
|
1981
|
+
const mergedLine = ensureCartLineId({
|
|
1982
|
+
...incoming,
|
|
1983
|
+
line_id: incoming.line_id ?? computeCartLineId(incoming),
|
|
1984
|
+
product_id: productId,
|
|
1985
|
+
variant_id: variantId,
|
|
1986
|
+
quantity: normalizedQuantity
|
|
1987
|
+
});
|
|
1988
|
+
const index = cart.findIndex((item) => item.line_id === mergedLine.line_id);
|
|
1989
|
+
if (index >= 0) {
|
|
1990
|
+
cart[index].quantity = Math.max(cart[index].quantity, normalizedQuantity);
|
|
1991
|
+
clampQuantityToBounds(cart[index]);
|
|
1992
|
+
} else {
|
|
1993
|
+
clampQuantityToBounds(mergedLine);
|
|
1994
|
+
cart.push(mergedLine);
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
writeCart(cart);
|
|
1998
|
+
return cart;
|
|
1940
1999
|
}
|
|
1941
|
-
|
|
1942
|
-
const
|
|
1943
|
-
const
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
2000
|
+
function moveBasketItem(fromProductId, fromVariantId, toProductId, toVariantId) {
|
|
2001
|
+
const cart = getCart();
|
|
2002
|
+
const fromIndex = cart.findIndex(
|
|
2003
|
+
(item) => item.product_id === fromProductId && item.variant_id === fromVariantId
|
|
2004
|
+
);
|
|
2005
|
+
if (fromIndex < 0) {
|
|
2006
|
+
throw new CartError("Item not found in cart");
|
|
2007
|
+
}
|
|
2008
|
+
const [fromItem] = cart.splice(fromIndex, 1);
|
|
2009
|
+
const toLineId = computeCartLineId({
|
|
2010
|
+
...fromItem,
|
|
2011
|
+
product_id: toProductId,
|
|
2012
|
+
variant_id: toVariantId
|
|
1950
2013
|
});
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
2014
|
+
const toIndex = cart.findIndex((item) => item.line_id === toLineId);
|
|
2015
|
+
if (toIndex >= 0) {
|
|
2016
|
+
cart[toIndex].quantity += fromItem.quantity;
|
|
2017
|
+
clampQuantityToBounds(cart[toIndex]);
|
|
2018
|
+
} else {
|
|
2019
|
+
const moved = ensureCartLineId({
|
|
2020
|
+
...fromItem,
|
|
2021
|
+
product_id: toProductId,
|
|
2022
|
+
variant_id: toVariantId,
|
|
2023
|
+
line_id: toLineId
|
|
1954
2024
|
});
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
headers: { "Content-Type": "application/json" },
|
|
1958
|
-
body: JSON.stringify(body),
|
|
1959
|
-
signal: controller?.signal
|
|
1960
|
-
}).then((response) => response.ok);
|
|
1961
|
-
return await Promise.race([delivered, timedOut]);
|
|
1962
|
-
} catch {
|
|
1963
|
-
return false;
|
|
1964
|
-
} finally {
|
|
1965
|
-
clearTimeout(timer);
|
|
2025
|
+
clampQuantityToBounds(moved);
|
|
2026
|
+
cart.push(moved);
|
|
1966
2027
|
}
|
|
2028
|
+
writeCart(cart);
|
|
1967
2029
|
}
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
const
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
if (reservedOrder) await enqueueCartSend(async () => sendCartActivity(await reservedOrder, cartValue, itemCount));
|
|
1976
|
-
return;
|
|
2030
|
+
function validateCartIntegrity() {
|
|
2031
|
+
const cart = getCart();
|
|
2032
|
+
const metadata = getCartMetadata();
|
|
2033
|
+
const checksum = computeChecksum(cart);
|
|
2034
|
+
if (!metadata) {
|
|
2035
|
+
setCartWithMetadata(cart, null);
|
|
2036
|
+
return true;
|
|
1977
2037
|
}
|
|
1978
|
-
|
|
1979
|
-
const order2 = reservedOrder ? await reservedOrder : void 0;
|
|
1980
|
-
const settle2 = order2 ? claimCartReport(config2.storeSlug, order2.seq, cartValue, itemCount) : void 0;
|
|
1981
|
-
const sessionId = analyticsSessionId(config2.storeSlug, { touch: true });
|
|
1982
|
-
const previousSession = currentPageSession();
|
|
1983
|
-
if (previousSession && previousSession !== sessionId) reportPageLeave();
|
|
1984
|
-
markPageViewed(sessionId);
|
|
1985
|
-
if (sessionId) installEngagedClock(reportPageLeave);
|
|
1986
|
-
onAnalyticsConsent(startSessionOnConsent);
|
|
1987
|
-
const delivered = await postPing({
|
|
1988
|
-
referer: document.referrer || void 0,
|
|
1989
|
-
cart_value: cartValue,
|
|
1990
|
-
item_count: itemCount,
|
|
1991
|
-
cart_seq: order2?.seq,
|
|
1992
|
-
cart_seq_scope: order2?.scope,
|
|
1993
|
-
session_id: sessionId ?? void 0,
|
|
1994
|
-
// Time on screen of the page before this one (client-side navigation).
|
|
1995
|
-
engaged_ms: sessionId ? takeEngagedMs() || void 0 : void 0,
|
|
1996
|
-
path: resolveStorefrontPagePath(),
|
|
1997
|
-
utm: resolveUtmParameters(config2.storeSlug)
|
|
1998
|
-
});
|
|
1999
|
-
settle2?.(delivered);
|
|
2000
|
-
};
|
|
2001
|
-
await (reservedOrder ? enqueueCartSend(sendView) : sendView());
|
|
2038
|
+
return metadata.checksum === checksum;
|
|
2002
2039
|
}
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
const
|
|
2007
|
-
const
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
});
|
|
2040
|
+
function getCartStats() {
|
|
2041
|
+
const cart = getCart();
|
|
2042
|
+
const integrityValid = validateCartIntegrity();
|
|
2043
|
+
const metadata = getCartMetadata();
|
|
2044
|
+
const backup = readCartStorage("cartBackup") ?? [];
|
|
2045
|
+
const hasCompletePriceSnapshots = cart.length > 0 && cart.every((item) => typeof item.price_data?.unit_price === "number");
|
|
2046
|
+
const totalPrice = cart.reduce((sum, item) => {
|
|
2047
|
+
const unitPrice = item.price_data?.unit_price ?? 0;
|
|
2048
|
+
return sum + roundPayableAmount(unitPrice * item.quantity);
|
|
2049
|
+
}, 0);
|
|
2050
|
+
return {
|
|
2051
|
+
item_count: cart.length,
|
|
2052
|
+
total_quantity: cart.reduce((sum, item) => sum + item.quantity, 0),
|
|
2053
|
+
last_modified: metadata?.last_modified ?? 0,
|
|
2054
|
+
version: metadata?.version ?? 0,
|
|
2055
|
+
has_backup: backup.length > 0,
|
|
2056
|
+
integrity_valid: integrityValid,
|
|
2057
|
+
total_price: roundPayableAmount(totalPrice),
|
|
2058
|
+
total_price_is_estimate: cart.length > 0 && !hasCompletePriceSnapshots
|
|
2059
|
+
};
|
|
2013
2060
|
}
|
|
2014
|
-
|
|
2061
|
+
function getCartPayload(coupon) {
|
|
2015
2062
|
const config2 = getConfig();
|
|
2016
|
-
const
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
cart_seq_scope: order2.scope,
|
|
2023
|
-
// A cart marks the analytics session as one that did not bounce.
|
|
2024
|
-
session_id: analyticsSessionId(config2.storeSlug, { touch: false }) ?? void 0,
|
|
2025
|
-
path: resolveStorefrontPagePath()
|
|
2026
|
-
});
|
|
2027
|
-
settle2(delivered);
|
|
2063
|
+
const normalizedCoupon = normalizeCouponCode(coupon) ?? getCartCoupon() ?? void 0;
|
|
2064
|
+
return {
|
|
2065
|
+
store_slug: config2.storeSlug,
|
|
2066
|
+
items: getCart(),
|
|
2067
|
+
coupon: normalizedCoupon
|
|
2068
|
+
};
|
|
2028
2069
|
}
|
|
2029
|
-
function
|
|
2030
|
-
const
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
void postPing({
|
|
2037
|
-
event_type: "session_start",
|
|
2038
|
-
referer: document.referrer || void 0,
|
|
2039
|
-
session_id: sessionId,
|
|
2040
|
-
path: resolveStorefrontPagePath(),
|
|
2041
|
-
utm: resolveUtmParameters(config2.storeSlug)
|
|
2042
|
-
});
|
|
2070
|
+
function getAmbientAffiliateCodeForQuote() {
|
|
2071
|
+
const storedCode = getCartCoupon();
|
|
2072
|
+
const storedSource = getCartCouponSource();
|
|
2073
|
+
if (storedSource === "AFFILIATE" && storedCode) {
|
|
2074
|
+
return storedCode.trim().toLowerCase();
|
|
2075
|
+
}
|
|
2076
|
+
return getAffiliateCode();
|
|
2043
2077
|
}
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2078
|
+
var latestQuoteToken = null;
|
|
2079
|
+
var quoteSequence = 0;
|
|
2080
|
+
function getLatestQuoteToken() {
|
|
2081
|
+
return latestQuoteToken;
|
|
2082
|
+
}
|
|
2083
|
+
function clearLatestQuoteToken() {
|
|
2084
|
+
latestQuoteToken = null;
|
|
2085
|
+
quoteSequence += 1;
|
|
2086
|
+
}
|
|
2087
|
+
async function quoteCart(coupon, currency) {
|
|
2088
|
+
const sequence = quoteSequence += 1;
|
|
2089
|
+
const payload = getCartPayload(coupon);
|
|
2090
|
+
const normalizedCurrency = normalizeRequestedCurrency(currency) ?? resolveBuyerCurrency(getConfig().currency);
|
|
2091
|
+
const response = await post("/v1/storefront/cart/quote", {
|
|
2092
|
+
shop_slug: payload.store_slug,
|
|
2093
|
+
cart: payload.items,
|
|
2094
|
+
coupon: payload.coupon,
|
|
2095
|
+
affiliate_code: getAmbientAffiliateCodeForQuote() ?? void 0,
|
|
2096
|
+
currency: normalizedCurrency ?? void 0
|
|
2097
|
+
});
|
|
2098
|
+
if (sequence !== quoteSequence) return response;
|
|
2099
|
+
if (response.success) {
|
|
2100
|
+
latestQuoteToken = typeof response.data?.quote_token === "string" ? response.data.quote_token : null;
|
|
2059
2101
|
}
|
|
2102
|
+
return response;
|
|
2060
2103
|
}
|
|
2061
2104
|
|
|
2062
2105
|
// ../sdk/src/storefront-storage-sdk.ts
|
|
@@ -2102,7 +2145,8 @@ var storefrontStorageSdk = {
|
|
|
2102
2145
|
trackAffiliateEvent,
|
|
2103
2146
|
// Analytics
|
|
2104
2147
|
trackPageView,
|
|
2105
|
-
trackCartActivity
|
|
2148
|
+
trackCartActivity,
|
|
2149
|
+
trackProductView
|
|
2106
2150
|
};
|
|
2107
2151
|
|
|
2108
2152
|
// ../../node_modules/.bun/openapi-fetch@0.17.0/node_modules/openapi-fetch/dist/index.mjs
|
|
@@ -24349,6 +24393,27 @@ var customerPortalAffiliateLedgerStatusSchema = external_exports.enum([
|
|
|
24349
24393
|
"split",
|
|
24350
24394
|
"voided"
|
|
24351
24395
|
]);
|
|
24396
|
+
var customerPortalAffiliateCommissionBreakdownSchema = external_exports.object({
|
|
24397
|
+
lines: external_exports.array(external_exports.object({
|
|
24398
|
+
product_id: external_exports.string().nullable(),
|
|
24399
|
+
title: external_exports.string(),
|
|
24400
|
+
base_usd: external_exports.string(),
|
|
24401
|
+
percent: external_exports.number(),
|
|
24402
|
+
source: external_exports.enum(["PRODUCT_DISABLED", "LINK", "AFFILIATE", "TIER", "PRODUCT", "SHOP_DEFAULT"]),
|
|
24403
|
+
amount_usd: external_exports.string()
|
|
24404
|
+
})),
|
|
24405
|
+
base_usd: external_exports.string(),
|
|
24406
|
+
gross_usd: external_exports.string(),
|
|
24407
|
+
cap_usd: nullableStringSchema,
|
|
24408
|
+
cap_applied: external_exports.boolean(),
|
|
24409
|
+
minimum_order_usd: nullableStringSchema,
|
|
24410
|
+
minimum_met: external_exports.boolean(),
|
|
24411
|
+
shareback_usd: external_exports.string(),
|
|
24412
|
+
amount_usd: external_exports.string(),
|
|
24413
|
+
tier_name: nullableStringSchema,
|
|
24414
|
+
attribution_source: external_exports.enum(["CODE", "BINDING"]),
|
|
24415
|
+
bound_at: nullableStringSchema
|
|
24416
|
+
});
|
|
24352
24417
|
var customerPortalAffiliateSummarySchema = external_exports.object({
|
|
24353
24418
|
customer: external_exports.object({
|
|
24354
24419
|
id: external_exports.string(),
|
|
@@ -24391,6 +24456,7 @@ var customerPortalAffiliateSummarySchema = external_exports.object({
|
|
|
24391
24456
|
store_credit_amount: external_exports.string(),
|
|
24392
24457
|
base_amount: external_exports.string(),
|
|
24393
24458
|
discount_amount: external_exports.string(),
|
|
24459
|
+
breakdown: customerPortalAffiliateCommissionBreakdownSchema.nullable(),
|
|
24394
24460
|
status: external_exports.string(),
|
|
24395
24461
|
created_at: nullableStringSchema,
|
|
24396
24462
|
paid_at: nullableStringSchema,
|
|
@@ -24854,19 +24920,29 @@ function createTicket(payload) {
|
|
|
24854
24920
|
body: {
|
|
24855
24921
|
...payload.title !== void 0 ? { title: payload.title } : {},
|
|
24856
24922
|
message: payload.message,
|
|
24857
|
-
...payload.invoice_id !== void 0 ? { invoice_id: payload.invoice_id } : {}
|
|
24923
|
+
...payload.invoice_id !== void 0 ? { invoice_id: payload.invoice_id } : {},
|
|
24924
|
+
...payload.attachment_ids?.length ? { attachment_ids: payload.attachment_ids } : {}
|
|
24858
24925
|
}
|
|
24859
24926
|
});
|
|
24860
24927
|
}
|
|
24861
24928
|
function ticket(uniqid) {
|
|
24862
24929
|
return requestCustomer(`/tickets/${encodeURIComponent(uniqid)}`);
|
|
24863
24930
|
}
|
|
24864
|
-
function replyToTicket(uniqid, message) {
|
|
24931
|
+
function replyToTicket(uniqid, message, attachmentIds = []) {
|
|
24865
24932
|
return requestCustomer(`/tickets/${encodeURIComponent(uniqid)}/reply`, {
|
|
24866
24933
|
method: "POST",
|
|
24867
|
-
body: { message }
|
|
24934
|
+
body: attachmentIds.length > 0 ? { message, attachment_ids: attachmentIds } : { message }
|
|
24868
24935
|
});
|
|
24869
24936
|
}
|
|
24937
|
+
function uploadTicketImage(file2, ticket2) {
|
|
24938
|
+
const form = new FormData();
|
|
24939
|
+
form.append("file", file2);
|
|
24940
|
+
if (ticket2) form.append("ticket", ticket2);
|
|
24941
|
+
return requestCustomer("/ticket-attachments", { method: "POST", formData: form });
|
|
24942
|
+
}
|
|
24943
|
+
function discardTicketImage(id) {
|
|
24944
|
+
return requestCustomer(`/ticket-attachments/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
24945
|
+
}
|
|
24870
24946
|
function updateProfile(patch) {
|
|
24871
24947
|
return requestCustomer("/profile", {
|
|
24872
24948
|
method: "POST",
|
|
@@ -24992,6 +25068,8 @@ var shoppex = {
|
|
|
24992
25068
|
createTicket,
|
|
24993
25069
|
ticket,
|
|
24994
25070
|
replyToTicket,
|
|
25071
|
+
uploadTicketImage,
|
|
25072
|
+
discardTicketImage,
|
|
24995
25073
|
updateProfile,
|
|
24996
25074
|
updateAvatar,
|
|
24997
25075
|
removeAvatar,
|
|
@@ -25049,6 +25127,7 @@ if (typeof window !== "undefined") {
|
|
|
25049
25127
|
createAffiliateLink,
|
|
25050
25128
|
createTicket,
|
|
25051
25129
|
dashboard,
|
|
25130
|
+
discardTicketImage,
|
|
25052
25131
|
emailPreferences,
|
|
25053
25132
|
enrollAsReseller,
|
|
25054
25133
|
ensureCartLineId,
|
|
@@ -25116,11 +25195,13 @@ if (typeof window !== "undefined") {
|
|
|
25116
25195
|
touchStorefrontPresence,
|
|
25117
25196
|
trackCartActivity,
|
|
25118
25197
|
trackPageView,
|
|
25198
|
+
trackProductView,
|
|
25119
25199
|
undoSubscriptionCancel,
|
|
25120
25200
|
updateAvatar,
|
|
25121
25201
|
updateEmailPreferences,
|
|
25122
25202
|
updateNotificationPreferences,
|
|
25123
25203
|
updateProfile,
|
|
25204
|
+
uploadTicketImage,
|
|
25124
25205
|
validateStorefrontCustomFieldValue,
|
|
25125
25206
|
verifyOtp,
|
|
25126
25207
|
warranties
|