@aranova/tracking-react 0.12.2 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/dist/index.d.mts +64 -16
- package/dist/index.d.ts +64 -16
- package/dist/index.js +738 -183
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +726 -173
- package/dist/index.mjs.map +1 -1
- package/dist/{phone-utils-Du-alwyM.d.mts → phone-utils-Dyk0F14_.d.mts} +26 -1
- package/dist/{phone-utils-Du-alwyM.d.ts → phone-utils-Dyk0F14_.d.ts} +26 -1
- package/dist/phone.d.mts +1 -1
- package/dist/phone.d.ts +1 -1
- package/dist/phone.js +73 -0
- package/dist/phone.js.map +1 -1
- package/dist/phone.mjs +73 -0
- package/dist/phone.mjs.map +1 -1
- package/dist/sales-BsJodmh0.d.mts +887 -0
- package/dist/sales-BsJodmh0.d.ts +887 -0
- package/dist/sales.d.mts +2 -784
- package/dist/sales.d.ts +2 -784
- package/dist/sales.js +172 -45
- package/dist/sales.js.map +1 -1
- package/dist/sales.mjs +172 -45
- package/dist/sales.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
|
+
AdPlatformTracking: () => AdPlatformTracking,
|
|
23
24
|
AranovaApiError: () => AranovaApiError,
|
|
24
25
|
ConsentBanner: () => ConsentBanner,
|
|
25
26
|
DEFAULT_PHONE_COUNTRY: () => DEFAULT_PHONE_COUNTRY,
|
|
@@ -45,6 +46,7 @@ __export(src_exports, {
|
|
|
45
46
|
parsePhone: () => parsePhone,
|
|
46
47
|
phoneField: () => phoneField,
|
|
47
48
|
resetConsent: () => resetConsent,
|
|
49
|
+
resolveConversionConfig: () => resolveConversionConfig,
|
|
48
50
|
saleCreateSchema: () => saleCreateSchema,
|
|
49
51
|
saleItemSchema: () => saleItemSchema,
|
|
50
52
|
saleServiceSchema: () => saleServiceSchema,
|
|
@@ -71,6 +73,13 @@ var import_react = require("react");
|
|
|
71
73
|
// ../tracking-core/src/consent.ts
|
|
72
74
|
var CONSENT_STATE_KEY = "consent_state";
|
|
73
75
|
var CONSENT_TIMESTAMP_KEY = "consent_timestamp";
|
|
76
|
+
var grantedListeners = /* @__PURE__ */ new Set();
|
|
77
|
+
function onConsentGranted(listener) {
|
|
78
|
+
grantedListeners.add(listener);
|
|
79
|
+
return () => {
|
|
80
|
+
grantedListeners.delete(listener);
|
|
81
|
+
};
|
|
82
|
+
}
|
|
74
83
|
function buildConsentPayload(state) {
|
|
75
84
|
return {
|
|
76
85
|
ad_storage: state,
|
|
@@ -81,21 +90,40 @@ function buildConsentPayload(state) {
|
|
|
81
90
|
}
|
|
82
91
|
function getConsentState() {
|
|
83
92
|
if (typeof window === "undefined") return "pending";
|
|
84
|
-
|
|
85
|
-
|
|
93
|
+
try {
|
|
94
|
+
const storedState = window.localStorage.getItem(CONSENT_STATE_KEY);
|
|
95
|
+
if (storedState === "granted" || storedState === "denied") return storedState;
|
|
96
|
+
} catch {
|
|
97
|
+
}
|
|
86
98
|
return "pending";
|
|
87
99
|
}
|
|
88
100
|
function setConsentState(state) {
|
|
89
101
|
if (typeof window === "undefined") return;
|
|
90
|
-
|
|
91
|
-
|
|
102
|
+
try {
|
|
103
|
+
window.localStorage.setItem(CONSENT_STATE_KEY, state);
|
|
104
|
+
window.localStorage.setItem(CONSENT_TIMESTAMP_KEY, (/* @__PURE__ */ new Date()).toISOString());
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
92
107
|
if (typeof window.gtag === "function")
|
|
93
108
|
window.gtag("consent", "update", buildConsentPayload(state));
|
|
109
|
+
if (typeof window.fbq === "function")
|
|
110
|
+
window.fbq("consent", state === "granted" ? "grant" : "revoke");
|
|
111
|
+
if (state === "granted") {
|
|
112
|
+
for (const listener of grantedListeners) {
|
|
113
|
+
try {
|
|
114
|
+
listener();
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
94
119
|
}
|
|
95
120
|
function resetConsent() {
|
|
96
121
|
if (typeof window === "undefined") return;
|
|
97
|
-
|
|
98
|
-
|
|
122
|
+
try {
|
|
123
|
+
window.localStorage.removeItem(CONSENT_STATE_KEY);
|
|
124
|
+
window.localStorage.removeItem(CONSENT_TIMESTAMP_KEY);
|
|
125
|
+
} catch {
|
|
126
|
+
}
|
|
99
127
|
}
|
|
100
128
|
function restoreStoredConsent() {
|
|
101
129
|
const consentState = getConsentState();
|
|
@@ -103,45 +131,106 @@ function restoreStoredConsent() {
|
|
|
103
131
|
return consentState;
|
|
104
132
|
}
|
|
105
133
|
|
|
106
|
-
// ../tracking-core/src/
|
|
107
|
-
|
|
134
|
+
// ../tracking-core/src/tracking.ts
|
|
135
|
+
var TRACKING_COOKIE_MAX_AGE_SECONDS = 7776e3;
|
|
136
|
+
var TRACKING_PARAM_KEYS = [
|
|
137
|
+
"gclid",
|
|
138
|
+
"fbclid",
|
|
139
|
+
"utm_source",
|
|
140
|
+
"utm_medium",
|
|
141
|
+
"utm_campaign",
|
|
142
|
+
"utm_term",
|
|
143
|
+
"utm_content"
|
|
144
|
+
];
|
|
145
|
+
function createEmptyTrackingParams() {
|
|
108
146
|
return {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
active_gtag_ids: input.activeGtagIds ?? null
|
|
147
|
+
gclid: null,
|
|
148
|
+
fbclid: null,
|
|
149
|
+
utm_source: null,
|
|
150
|
+
utm_medium: null,
|
|
151
|
+
utm_campaign: null,
|
|
152
|
+
utm_term: null,
|
|
153
|
+
utm_content: null
|
|
117
154
|
};
|
|
118
155
|
}
|
|
119
|
-
function
|
|
120
|
-
return
|
|
121
|
-
session_id: input.sessionId,
|
|
122
|
-
visitor_id: input.visitorId ?? null,
|
|
123
|
-
gclid: trackingParams.gclid,
|
|
124
|
-
fbclid: trackingParams.fbclid,
|
|
125
|
-
utm_source: trackingParams.utm_source,
|
|
126
|
-
utm_medium: trackingParams.utm_medium,
|
|
127
|
-
utm_campaign: trackingParams.utm_campaign,
|
|
128
|
-
utm_term: trackingParams.utm_term,
|
|
129
|
-
utm_content: trackingParams.utm_content,
|
|
130
|
-
first_page: input.firstPage ?? null,
|
|
131
|
-
consent_state: input.consentState ?? null,
|
|
132
|
-
context
|
|
133
|
-
};
|
|
156
|
+
function normalizeTrackingCookieValue(value) {
|
|
157
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
134
158
|
}
|
|
135
|
-
function
|
|
136
|
-
return {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
159
|
+
function getTrackingParamsFromCookieReader(readCookie) {
|
|
160
|
+
return TRACKING_PARAM_KEYS.reduce((params, key) => {
|
|
161
|
+
params[key] = normalizeTrackingCookieValue(readCookie(key));
|
|
162
|
+
return params;
|
|
163
|
+
}, createEmptyTrackingParams());
|
|
164
|
+
}
|
|
165
|
+
function getTrackingQueryValues(searchParams) {
|
|
166
|
+
return TRACKING_PARAM_KEYS.reduce((params, key) => {
|
|
167
|
+
const value = searchParams.get(key);
|
|
168
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
169
|
+
params[key] = value;
|
|
170
|
+
}
|
|
171
|
+
return params;
|
|
172
|
+
}, {});
|
|
173
|
+
}
|
|
174
|
+
var FALLBACK_STORAGE_PREFIX = "_aranova_track_";
|
|
175
|
+
function fallbackKey(name) {
|
|
176
|
+
return `${FALLBACK_STORAGE_PREFIX}${name}`;
|
|
177
|
+
}
|
|
178
|
+
function persistCookieValue(name, value, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
|
|
179
|
+
const encoded = encodeURIComponent(value);
|
|
180
|
+
if (typeof document !== "undefined") {
|
|
181
|
+
try {
|
|
182
|
+
document.cookie = `${name}=${encoded}; Max-Age=${maxAgeSeconds}; Path=/; SameSite=Lax`;
|
|
183
|
+
} catch {
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (typeof window !== "undefined") {
|
|
187
|
+
try {
|
|
188
|
+
window.localStorage.setItem(fallbackKey(name), encoded);
|
|
189
|
+
} catch {
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function readCookieValue(name) {
|
|
194
|
+
if (typeof document !== "undefined") {
|
|
195
|
+
const cookies = document.cookie ? document.cookie.split("; ") : [];
|
|
196
|
+
const match = cookies.find((cookie) => cookie.startsWith(`${name}=`));
|
|
197
|
+
if (match) {
|
|
198
|
+
const [, rawValue = ""] = match.split("=");
|
|
199
|
+
return normalizeTrackingCookieValue(decodeURIComponent(rawValue));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (typeof window !== "undefined") {
|
|
203
|
+
try {
|
|
204
|
+
const stored = window.localStorage.getItem(fallbackKey(name));
|
|
205
|
+
if (stored) return normalizeTrackingCookieValue(decodeURIComponent(stored));
|
|
206
|
+
} catch {
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
function getCookieValueFromDocument(key) {
|
|
212
|
+
return readCookieValue(key);
|
|
213
|
+
}
|
|
214
|
+
function setTrackingCookie(key, value, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
|
|
215
|
+
persistCookieValue(key, value, maxAgeSeconds);
|
|
216
|
+
}
|
|
217
|
+
function mergeTrackingParams(primary, fallback) {
|
|
218
|
+
return TRACKING_PARAM_KEYS.reduce((merged, key) => {
|
|
219
|
+
merged[key] = primary[key] ?? fallback[key];
|
|
220
|
+
return merged;
|
|
221
|
+
}, createEmptyTrackingParams());
|
|
222
|
+
}
|
|
223
|
+
function persistTrackingParamsFromSearchParams(searchParams, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
|
|
224
|
+
const trackingValues = getTrackingQueryValues(searchParams);
|
|
225
|
+
Object.entries(trackingValues).forEach(([key, value]) => {
|
|
226
|
+
setTrackingCookie(key, value, maxAgeSeconds);
|
|
227
|
+
});
|
|
228
|
+
return trackingValues;
|
|
229
|
+
}
|
|
230
|
+
function captureTrackingParamsFromLocation(url = typeof window === "undefined" ? "" : window.location.href, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
|
|
231
|
+
const resolvedUrl = typeof window === "undefined" ? new URL(url || "https://example.invalid") : new URL(url, window.location.origin);
|
|
232
|
+
persistTrackingParamsFromSearchParams(resolvedUrl.searchParams, maxAgeSeconds);
|
|
233
|
+
return getTrackingParamsFromCookieReader(getCookieValueFromDocument);
|
|
145
234
|
}
|
|
146
235
|
|
|
147
236
|
// ../tracking-core/src/gtag.ts
|
|
@@ -162,6 +251,24 @@ function ensureGtagFunction() {
|
|
|
162
251
|
};
|
|
163
252
|
return window.gtag;
|
|
164
253
|
}
|
|
254
|
+
var SEND_TO_RE = /^AW-[A-Za-z0-9]+\/[A-Za-z0-9_-]+$/;
|
|
255
|
+
function isValidSendTo(sendTo) {
|
|
256
|
+
return SEND_TO_RE.test(sendTo);
|
|
257
|
+
}
|
|
258
|
+
function fireGtagConversion(input) {
|
|
259
|
+
if (typeof window === "undefined" || typeof window.gtag !== "function") return false;
|
|
260
|
+
if (!isValidSendTo(input.sendTo)) return false;
|
|
261
|
+
const params = { send_to: input.sendTo };
|
|
262
|
+
if (input.value != null) params.value = input.value;
|
|
263
|
+
if (input.currency) params.currency = input.currency;
|
|
264
|
+
if (input.transactionId) params.transaction_id = input.transactionId;
|
|
265
|
+
try {
|
|
266
|
+
window.gtag("event", "conversion", params);
|
|
267
|
+
return true;
|
|
268
|
+
} catch {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
165
272
|
function applyDefaultConsentState() {
|
|
166
273
|
const gtag = ensureGtagFunction();
|
|
167
274
|
gtag("consent", "default", {
|
|
@@ -214,70 +321,441 @@ function bootstrapMultipleGtags(gtagIds) {
|
|
|
214
321
|
restoreStoredConsent();
|
|
215
322
|
}
|
|
216
323
|
|
|
217
|
-
// ../tracking-core/src/
|
|
218
|
-
var
|
|
219
|
-
var
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
"
|
|
227
|
-
|
|
228
|
-
|
|
324
|
+
// ../tracking-core/src/fbq.ts
|
|
325
|
+
var FB_EVENTS_SCRIPT_HOST = "https://connect.facebook.net/en_US/fbevents.js";
|
|
326
|
+
var FBC_COOKIE = "_fbc";
|
|
327
|
+
var FBP_COOKIE = "_fbp";
|
|
328
|
+
var META_PIXEL_ID_PATTERN = /^\d{15,16}$/;
|
|
329
|
+
function isValidMetaPixelId(id) {
|
|
330
|
+
return META_PIXEL_ID_PATTERN.test(id);
|
|
331
|
+
}
|
|
332
|
+
function computeFbSubdomainIndex(hostname) {
|
|
333
|
+
const labels = hostname.split(".").filter(Boolean);
|
|
334
|
+
return Math.max(0, labels.length - 1);
|
|
335
|
+
}
|
|
336
|
+
function buildFbc(fbclid, now, hostname) {
|
|
337
|
+
const host = hostname ?? (typeof window === "undefined" ? "" : window.location.hostname);
|
|
338
|
+
return `fb.${computeFbSubdomainIndex(host)}.${now}.${fbclid}`;
|
|
339
|
+
}
|
|
340
|
+
function getFbcCookie() {
|
|
341
|
+
return readCookieValue(FBC_COOKIE);
|
|
342
|
+
}
|
|
343
|
+
function getFbpCookie() {
|
|
344
|
+
return readCookieValue(FBP_COOKIE);
|
|
345
|
+
}
|
|
346
|
+
function readFbclidFromUrl() {
|
|
347
|
+
if (typeof window === "undefined") return null;
|
|
348
|
+
try {
|
|
349
|
+
const value = new URL(window.location.href).searchParams.get("fbclid");
|
|
350
|
+
return value && value.trim().length > 0 ? value : null;
|
|
351
|
+
} catch {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
function captureFbc(now = typeof Date === "undefined" ? 0 : Date.now()) {
|
|
356
|
+
if (typeof window === "undefined") return;
|
|
357
|
+
if (getFbcCookie()) return;
|
|
358
|
+
const fbclid = readFbclidFromUrl() ?? readCookieValue("fbclid");
|
|
359
|
+
if (!fbclid) return;
|
|
360
|
+
persistCookieValue(FBC_COOKIE, buildFbc(fbclid, now), TRACKING_COOKIE_MAX_AGE_SECONDS);
|
|
361
|
+
}
|
|
362
|
+
function getScriptMarker2(id) {
|
|
363
|
+
return `aranova-${id}`;
|
|
364
|
+
}
|
|
365
|
+
function ensureFbqFunction() {
|
|
366
|
+
const w = window;
|
|
367
|
+
if (typeof w.fbq === "function") return w.fbq;
|
|
368
|
+
const fbq = function(...args) {
|
|
369
|
+
if (fbq.callMethod) fbq.callMethod.apply(fbq, args);
|
|
370
|
+
else fbq.queue.push(args);
|
|
371
|
+
};
|
|
372
|
+
fbq.push = fbq;
|
|
373
|
+
fbq.loaded = true;
|
|
374
|
+
fbq.version = "2.0";
|
|
375
|
+
fbq.queue = [];
|
|
376
|
+
w.fbq = fbq;
|
|
377
|
+
if (!w._fbq) w._fbq = fbq;
|
|
378
|
+
return fbq;
|
|
379
|
+
}
|
|
380
|
+
function applyDefaultMetaConsentState() {
|
|
381
|
+
ensureFbqFunction()("consent", "revoke");
|
|
382
|
+
}
|
|
383
|
+
function loadFbeventsScript() {
|
|
384
|
+
if (typeof document === "undefined") return;
|
|
385
|
+
const marker = getScriptMarker2("fbq-loader");
|
|
386
|
+
const existing = document.querySelector(
|
|
387
|
+
`script[${TRACKING_SCRIPT_ATTRIBUTE}="${marker}"]`
|
|
388
|
+
);
|
|
389
|
+
if (existing) return;
|
|
390
|
+
const script = document.createElement("script");
|
|
391
|
+
script.async = true;
|
|
392
|
+
script.src = FB_EVENTS_SCRIPT_HOST;
|
|
393
|
+
script.setAttribute(TRACKING_SCRIPT_ATTRIBUTE, marker);
|
|
394
|
+
document.head.append(script);
|
|
395
|
+
}
|
|
396
|
+
function initializeMetaPixel(pixelId) {
|
|
397
|
+
const fbq = ensureFbqFunction();
|
|
398
|
+
fbq("init", pixelId);
|
|
399
|
+
fbq("track", "PageView");
|
|
400
|
+
}
|
|
401
|
+
function restoreMetaConsentState() {
|
|
402
|
+
if (typeof window === "undefined") return;
|
|
403
|
+
const state = getConsentState();
|
|
404
|
+
if (state === "granted") window.fbq?.("consent", "grant");
|
|
405
|
+
else if (state === "denied") window.fbq?.("consent", "revoke");
|
|
406
|
+
}
|
|
407
|
+
function bootstrapMetaPixel(pixelId) {
|
|
408
|
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
409
|
+
if (!isValidMetaPixelId(pixelId)) return;
|
|
410
|
+
applyDefaultMetaConsentState();
|
|
411
|
+
loadFbeventsScript();
|
|
412
|
+
initializeMetaPixel(pixelId);
|
|
413
|
+
restoreMetaConsentState();
|
|
414
|
+
captureFbc();
|
|
415
|
+
}
|
|
416
|
+
function bootstrapMultiplePixels(pixelIds) {
|
|
417
|
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
418
|
+
const ids = Object.values(pixelIds).filter(
|
|
419
|
+
(id) => typeof id === "string" && isValidMetaPixelId(id)
|
|
420
|
+
);
|
|
421
|
+
if (ids.length === 0) return;
|
|
422
|
+
applyDefaultMetaConsentState();
|
|
423
|
+
loadFbeventsScript();
|
|
424
|
+
const fbq = ensureFbqFunction();
|
|
425
|
+
for (const id of ids) {
|
|
426
|
+
fbq("init", id);
|
|
427
|
+
}
|
|
428
|
+
fbq("track", "PageView");
|
|
429
|
+
restoreMetaConsentState();
|
|
430
|
+
captureFbc();
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// ../tracking-core/src/payloads.ts
|
|
434
|
+
function createTrackingClientContext(surface, input = {}) {
|
|
229
435
|
return {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
436
|
+
surface,
|
|
437
|
+
sdk_version: input.sdkVersion ?? null,
|
|
438
|
+
package_name: input.packageName ?? null,
|
|
439
|
+
site_origin: input.siteOrigin ?? (typeof window === "undefined" ? null : window.location.origin),
|
|
440
|
+
page_title: input.pageTitle ?? (typeof document === "undefined" ? null : document.title || null),
|
|
441
|
+
referrer: input.referrer ?? (typeof document === "undefined" ? null : document.referrer || null),
|
|
442
|
+
environment: input.environment ?? "production",
|
|
443
|
+
active_gtag_ids: input.activeGtagIds ?? null
|
|
237
444
|
};
|
|
238
445
|
}
|
|
239
|
-
function
|
|
240
|
-
return
|
|
446
|
+
function createTrackingSessionUpsertPayload(trackingParams, input, context) {
|
|
447
|
+
return {
|
|
448
|
+
session_id: input.sessionId,
|
|
449
|
+
visitor_id: input.visitorId ?? null,
|
|
450
|
+
gclid: trackingParams.gclid,
|
|
451
|
+
fbclid: trackingParams.fbclid,
|
|
452
|
+
fbc: getFbcCookie(),
|
|
453
|
+
fbp: getFbpCookie(),
|
|
454
|
+
utm_source: trackingParams.utm_source,
|
|
455
|
+
utm_medium: trackingParams.utm_medium,
|
|
456
|
+
utm_campaign: trackingParams.utm_campaign,
|
|
457
|
+
utm_term: trackingParams.utm_term,
|
|
458
|
+
utm_content: trackingParams.utm_content,
|
|
459
|
+
first_page: input.firstPage ?? null,
|
|
460
|
+
consent_state: input.consentState ?? null,
|
|
461
|
+
context
|
|
462
|
+
};
|
|
241
463
|
}
|
|
242
|
-
function
|
|
243
|
-
return
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
464
|
+
function createTrackingEventCreatePayload(trackingParams, input, context) {
|
|
465
|
+
return {
|
|
466
|
+
session_id: input.sessionId,
|
|
467
|
+
event_type: input.eventType,
|
|
468
|
+
gclid: trackingParams.gclid,
|
|
469
|
+
fbclid: trackingParams.fbclid,
|
|
470
|
+
fbc: getFbcCookie(),
|
|
471
|
+
fbp: getFbpCookie(),
|
|
472
|
+
page_url: input.pageUrl ?? (typeof window === "undefined" ? null : window.location.href),
|
|
473
|
+
metadata: input.metadata ?? null,
|
|
474
|
+
context
|
|
475
|
+
};
|
|
247
476
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
477
|
+
|
|
478
|
+
// ../tracking-core/src/resources/conversion-firing.ts
|
|
479
|
+
var DEDUP_PREFIX = "_aranova_conv_";
|
|
480
|
+
var MAX_PENDING = 100;
|
|
481
|
+
var pendingQueue = [];
|
|
482
|
+
function dedupKey(input) {
|
|
483
|
+
return `${DEDUP_PREFIX}${input.transactionId ?? ""}:${input.sendTo}`;
|
|
484
|
+
}
|
|
485
|
+
function alreadyFired(input) {
|
|
486
|
+
if (!input.transactionId || typeof window === "undefined") return false;
|
|
487
|
+
try {
|
|
488
|
+
return window.sessionStorage.getItem(dedupKey(input)) !== null;
|
|
489
|
+
} catch {
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
256
492
|
}
|
|
257
|
-
function
|
|
258
|
-
if (typeof
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
return normalizeTrackingCookieValue(decodeURIComponent(rawValue));
|
|
493
|
+
function markFired(input) {
|
|
494
|
+
if (!input.transactionId || typeof window === "undefined") return;
|
|
495
|
+
try {
|
|
496
|
+
window.sessionStorage.setItem(dedupKey(input), "1");
|
|
497
|
+
} catch {
|
|
498
|
+
}
|
|
264
499
|
}
|
|
265
|
-
function
|
|
266
|
-
if (
|
|
267
|
-
|
|
268
|
-
document.cookie = `${key}=${encodedValue}; Max-Age=${maxAgeSeconds}; Path=/; SameSite=Lax`;
|
|
500
|
+
function fireOnce(input) {
|
|
501
|
+
if (alreadyFired(input)) return;
|
|
502
|
+
if (fireGtagConversion(input)) markFired(input);
|
|
269
503
|
}
|
|
270
|
-
function
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
504
|
+
function fireConversionWithConsent(input) {
|
|
505
|
+
const state = getConsentState();
|
|
506
|
+
if (state === "denied") return;
|
|
507
|
+
if (state === "pending") {
|
|
508
|
+
if (pendingQueue.length >= MAX_PENDING) pendingQueue.shift();
|
|
509
|
+
pendingQueue.push(input);
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
fireOnce(input);
|
|
513
|
+
}
|
|
514
|
+
function flushPendingConversions() {
|
|
515
|
+
if (getConsentState() !== "granted") return;
|
|
516
|
+
while (pendingQueue.length > 0) {
|
|
517
|
+
const input = pendingQueue.shift();
|
|
518
|
+
if (input) fireOnce(input);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (typeof window !== "undefined") onConsentGranted(flushPendingConversions);
|
|
522
|
+
|
|
523
|
+
// ../tracking-core/src/resources/conversion-config.ts
|
|
524
|
+
function isStringMap(value) {
|
|
525
|
+
return typeof value === "object" && value !== null && Object.values(value).every((v) => typeof v === "string");
|
|
526
|
+
}
|
|
527
|
+
function parseFiring(value) {
|
|
528
|
+
if (!value || typeof value !== "object") return null;
|
|
529
|
+
const f = value;
|
|
530
|
+
if (typeof f.send_to !== "string") return null;
|
|
531
|
+
return {
|
|
532
|
+
send_to: f.send_to,
|
|
533
|
+
value_cents: typeof f.value_cents === "number" ? f.value_cents : null,
|
|
534
|
+
currency: typeof f.currency === "string" ? f.currency : null
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
function parseTrigger(value) {
|
|
538
|
+
if (!value || typeof value !== "object") return null;
|
|
539
|
+
const t = value;
|
|
540
|
+
if (typeof t.event_type !== "string") return null;
|
|
541
|
+
const spec = { event_type: t.event_type };
|
|
542
|
+
if (typeof t.threshold_percent === "number") spec.threshold_percent = t.threshold_percent;
|
|
543
|
+
if (typeof t.threshold_seconds === "number") spec.threshold_seconds = t.threshold_seconds;
|
|
544
|
+
if (typeof t.page_threshold === "number") spec.page_threshold = t.page_threshold;
|
|
545
|
+
if (typeof t.page_name === "string") spec.page_name = t.page_name;
|
|
546
|
+
return spec;
|
|
547
|
+
}
|
|
548
|
+
function parseConversionConfig(raw) {
|
|
549
|
+
if (!raw || typeof raw !== "object") return null;
|
|
550
|
+
const obj = raw;
|
|
551
|
+
const servicesRaw = Array.isArray(obj.services) ? obj.services : [];
|
|
552
|
+
const services = servicesRaw.flatMap((entry) => {
|
|
553
|
+
if (!entry || typeof entry !== "object") return [];
|
|
554
|
+
const s = entry;
|
|
555
|
+
if (typeof s.key !== "string") return [];
|
|
556
|
+
return [
|
|
557
|
+
{
|
|
558
|
+
key: s.key,
|
|
559
|
+
label: typeof s.label === "string" ? s.label : void 0,
|
|
560
|
+
firing: parseFiring(s.firing)
|
|
561
|
+
}
|
|
562
|
+
];
|
|
274
563
|
});
|
|
275
|
-
|
|
564
|
+
const goalsRaw = Array.isArray(obj.goals) ? obj.goals : null;
|
|
565
|
+
const goals = goalsRaw ? goalsRaw.flatMap((entry) => {
|
|
566
|
+
if (!entry || typeof entry !== "object") return [];
|
|
567
|
+
const g = entry;
|
|
568
|
+
if (typeof g.key !== "string") return [];
|
|
569
|
+
return [
|
|
570
|
+
{
|
|
571
|
+
key: g.key,
|
|
572
|
+
label: typeof g.label === "string" ? g.label : void 0,
|
|
573
|
+
kind: g.kind === "event" ? "event" : "sale",
|
|
574
|
+
trigger: parseTrigger(g.trigger),
|
|
575
|
+
firing: parseFiring(g.firing)
|
|
576
|
+
}
|
|
577
|
+
];
|
|
578
|
+
}) : services.map((s) => ({
|
|
579
|
+
key: s.key,
|
|
580
|
+
label: s.label,
|
|
581
|
+
kind: "sale",
|
|
582
|
+
trigger: null,
|
|
583
|
+
firing: s.firing
|
|
584
|
+
}));
|
|
585
|
+
return {
|
|
586
|
+
schema_version: typeof obj.schema_version === "number" ? obj.schema_version : 1,
|
|
587
|
+
config_version: typeof obj.config_version === "number" ? obj.config_version : 0,
|
|
588
|
+
business_id: typeof obj.business_id === "string" ? obj.business_id : void 0,
|
|
589
|
+
customer_id: typeof obj.customer_id === "string" ? obj.customer_id : null,
|
|
590
|
+
environment: typeof obj.environment === "string" ? obj.environment : void 0,
|
|
591
|
+
gtag_ids: isStringMap(obj.gtag_ids) ? obj.gtag_ids : {},
|
|
592
|
+
meta_pixel_ids: isStringMap(obj.meta_pixel_ids) ? obj.meta_pixel_ids : {},
|
|
593
|
+
services,
|
|
594
|
+
goals
|
|
595
|
+
};
|
|
276
596
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
597
|
+
var CACHE_PREFIX = "_aranova_cfg_";
|
|
598
|
+
function cacheKey(url) {
|
|
599
|
+
return `${CACHE_PREFIX}${url}`;
|
|
600
|
+
}
|
|
601
|
+
function readCache(url) {
|
|
602
|
+
if (typeof window === "undefined") return null;
|
|
603
|
+
try {
|
|
604
|
+
const raw = window.sessionStorage.getItem(cacheKey(url));
|
|
605
|
+
if (!raw) return null;
|
|
606
|
+
const parsed = JSON.parse(raw);
|
|
607
|
+
const config = parseConversionConfig(parsed.config);
|
|
608
|
+
if (!config) return null;
|
|
609
|
+
return {
|
|
610
|
+
etag: typeof parsed.etag === "string" ? parsed.etag : null,
|
|
611
|
+
config
|
|
612
|
+
};
|
|
613
|
+
} catch {
|
|
614
|
+
return null;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
function writeCache(url, entry) {
|
|
618
|
+
if (typeof window === "undefined") return;
|
|
619
|
+
try {
|
|
620
|
+
window.sessionStorage.setItem(cacheKey(url), JSON.stringify(entry));
|
|
621
|
+
} catch {
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
function resolveConversionConfig(options) {
|
|
625
|
+
const cached = readCache(options.cdnUrl);
|
|
626
|
+
let current = cached?.config ?? options.baked ?? null;
|
|
627
|
+
let etag = cached?.etag ?? null;
|
|
628
|
+
const goalsByKey = /* @__PURE__ */ new Map();
|
|
629
|
+
function rebuildIndex() {
|
|
630
|
+
goalsByKey.clear();
|
|
631
|
+
for (const goal of current?.goals ?? []) {
|
|
632
|
+
goalsByKey.set(goal.key, goal);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
function adopt(next, nextEtag) {
|
|
636
|
+
if (!next) return;
|
|
637
|
+
if (current && next.config_version <= current.config_version) return;
|
|
638
|
+
current = next;
|
|
639
|
+
etag = nextEtag;
|
|
640
|
+
rebuildIndex();
|
|
641
|
+
writeCache(options.cdnUrl, { etag, config: next });
|
|
642
|
+
}
|
|
643
|
+
async function revalidate() {
|
|
644
|
+
if (typeof window === "undefined") return;
|
|
645
|
+
try {
|
|
646
|
+
const doFetch = options.fetchImpl ?? globalThis.fetch;
|
|
647
|
+
if (!doFetch) return;
|
|
648
|
+
const headers = {};
|
|
649
|
+
if (etag) headers["If-None-Match"] = etag;
|
|
650
|
+
const response = await doFetch(options.cdnUrl, {
|
|
651
|
+
method: "GET",
|
|
652
|
+
headers
|
|
653
|
+
});
|
|
654
|
+
if (response.status === 304 || !response.ok) return;
|
|
655
|
+
adopt(parseConversionConfig(await response.json()), response.headers.get("ETag"));
|
|
656
|
+
} catch {
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
rebuildIndex();
|
|
660
|
+
void revalidate();
|
|
661
|
+
return {
|
|
662
|
+
getFiring: (key) => goalsByKey.get(key)?.firing ?? null,
|
|
663
|
+
getGoal: (key) => goalsByKey.get(key) ?? null,
|
|
664
|
+
listGoals: () => [...goalsByKey.values()],
|
|
665
|
+
current: () => current,
|
|
666
|
+
revalidate
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// ../tracking-core/src/resources/sales/money.ts
|
|
671
|
+
var MINOR_UNIT_EXPONENT = {
|
|
672
|
+
USD: 2,
|
|
673
|
+
CAD: 2
|
|
674
|
+
};
|
|
675
|
+
function exponentFor(currency) {
|
|
676
|
+
return MINOR_UNIT_EXPONENT[currency] ?? 2;
|
|
677
|
+
}
|
|
678
|
+
function toMinor(amount, currency) {
|
|
679
|
+
return Math.round(amount * 10 ** exponentFor(currency));
|
|
680
|
+
}
|
|
681
|
+
function fromMinor(cents, currency) {
|
|
682
|
+
return cents / 10 ** exponentFor(currency);
|
|
683
|
+
}
|
|
684
|
+
function formatMoney(cents, currency, locale) {
|
|
685
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
|
|
686
|
+
fromMinor(cents, currency)
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
function formatDateInTz(iso, timeZone, opts, locale) {
|
|
690
|
+
const date = new Date(iso);
|
|
691
|
+
if (Number.isNaN(date.getTime())) return iso;
|
|
692
|
+
return new Intl.DateTimeFormat(locale, {
|
|
693
|
+
year: "numeric",
|
|
694
|
+
month: "short",
|
|
695
|
+
day: "2-digit",
|
|
696
|
+
hour: "2-digit",
|
|
697
|
+
minute: "2-digit",
|
|
698
|
+
...opts,
|
|
699
|
+
timeZone
|
|
700
|
+
}).format(date);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// ../tracking-core/src/resources/conversion-autofire.ts
|
|
704
|
+
function thresholdMet(goal, eventType, metadata) {
|
|
705
|
+
const t = goal.trigger;
|
|
706
|
+
if (!t || t.event_type !== eventType) return false;
|
|
707
|
+
switch (eventType) {
|
|
708
|
+
case "scroll_depth":
|
|
709
|
+
return typeof metadata.depth_percent === "number" && t.threshold_percent != null && metadata.depth_percent >= t.threshold_percent;
|
|
710
|
+
case "time_on_site":
|
|
711
|
+
return typeof metadata.duration_ms === "number" && t.threshold_seconds != null && metadata.duration_ms >= t.threshold_seconds * 1e3;
|
|
712
|
+
case "multi_page_session":
|
|
713
|
+
return typeof metadata.page_count === "number" && t.page_threshold != null && metadata.page_count >= t.page_threshold;
|
|
714
|
+
case "specific_page_visit":
|
|
715
|
+
return typeof metadata.page_name === "string" && metadata.page_name === t.page_name;
|
|
716
|
+
case "page_view":
|
|
717
|
+
case "form_start":
|
|
718
|
+
return true;
|
|
719
|
+
// no threshold — fire whenever the detector emits
|
|
720
|
+
default:
|
|
721
|
+
return false;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
function currentPath() {
|
|
725
|
+
return typeof window === "undefined" ? "" : window.location.pathname;
|
|
726
|
+
}
|
|
727
|
+
function createConversionAutoFire(store) {
|
|
728
|
+
return {
|
|
729
|
+
onAutomaticEvent(eventType, metadata) {
|
|
730
|
+
for (const goal of store.listGoals()) {
|
|
731
|
+
if (goal.kind !== "event" || !goal.firing) continue;
|
|
732
|
+
if (!thresholdMet(goal, eventType, metadata)) continue;
|
|
733
|
+
const firing = goal.firing;
|
|
734
|
+
const cents = firing.value_cents ?? null;
|
|
735
|
+
const currency = firing.currency ?? null;
|
|
736
|
+
fireConversionWithConsent({
|
|
737
|
+
sendTo: firing.send_to,
|
|
738
|
+
value: cents != null && currency ? fromMinor(cents, currency) : null,
|
|
739
|
+
currency,
|
|
740
|
+
// Page-scoped txn id → fire once per (goal, path) per session; engagement conversions
|
|
741
|
+
// shouldn't re-fire as the visitor scrolls back and forth or re-enters a page.
|
|
742
|
+
transactionId: `auto:${goal.key}:${currentPath()}`
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
function withConversionAutoFire(client, autoFire) {
|
|
749
|
+
return {
|
|
750
|
+
...client,
|
|
751
|
+
trackEvent: (input) => {
|
|
752
|
+
client.trackEvent(input);
|
|
753
|
+
try {
|
|
754
|
+
autoFire.onAutomaticEvent(input.eventType, input.metadata ?? {});
|
|
755
|
+
} catch {
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
};
|
|
281
759
|
}
|
|
282
760
|
|
|
283
761
|
// ../tracking-core/src/session.ts
|
|
@@ -608,11 +1086,22 @@ function createTrackingClient(config) {
|
|
|
608
1086
|
let queue = [];
|
|
609
1087
|
let flushTimer = null;
|
|
610
1088
|
let firstPage = null;
|
|
1089
|
+
let initialParams = createEmptyTrackingParams();
|
|
611
1090
|
let destroyed = false;
|
|
612
1091
|
const visitorId = getVisitorId();
|
|
613
1092
|
const initialSession = getOrRotateSessionId();
|
|
614
1093
|
let sessionId = initialSession.id;
|
|
615
|
-
if (typeof window !== "undefined")
|
|
1094
|
+
if (typeof window !== "undefined") {
|
|
1095
|
+
firstPage = window.location.href;
|
|
1096
|
+
try {
|
|
1097
|
+
initialParams = captureTrackingParamsFromLocation();
|
|
1098
|
+
} catch {
|
|
1099
|
+
}
|
|
1100
|
+
try {
|
|
1101
|
+
captureFbc();
|
|
1102
|
+
} catch {
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
616
1105
|
function enqueueHeartbeat() {
|
|
617
1106
|
const metadata = buildHeartbeatMetadata(
|
|
618
1107
|
config.surface,
|
|
@@ -637,7 +1126,7 @@ function createTrackingClient(config) {
|
|
|
637
1126
|
enqueueHeartbeat();
|
|
638
1127
|
}
|
|
639
1128
|
sessionId = rotated.id;
|
|
640
|
-
const params = readTrackingParams();
|
|
1129
|
+
const params = mergeTrackingParams(readTrackingParams(), initialParams);
|
|
641
1130
|
const context = buildContext(
|
|
642
1131
|
config.surface,
|
|
643
1132
|
sdkVersion,
|
|
@@ -650,6 +1139,8 @@ function createTrackingClient(config) {
|
|
|
650
1139
|
visitor_id: visitorId,
|
|
651
1140
|
gclid: params.gclid,
|
|
652
1141
|
fbclid: params.fbclid,
|
|
1142
|
+
fbc: getFbcCookie(),
|
|
1143
|
+
fbp: getFbpCookie(),
|
|
653
1144
|
utm_source: params.utm_source,
|
|
654
1145
|
utm_medium: params.utm_medium,
|
|
655
1146
|
utm_campaign: params.utm_campaign,
|
|
@@ -1086,7 +1577,7 @@ function attachScrollDepth(client, config) {
|
|
|
1086
1577
|
}
|
|
1087
1578
|
const thresholds = new Set(config.thresholds);
|
|
1088
1579
|
let firedForPath = /* @__PURE__ */ new Set();
|
|
1089
|
-
let
|
|
1580
|
+
let currentPath2 = window.location.pathname;
|
|
1090
1581
|
let rafId = null;
|
|
1091
1582
|
function getScrollPercent() {
|
|
1092
1583
|
const doc = document.documentElement;
|
|
@@ -1105,7 +1596,7 @@ function attachScrollDepth(client, config) {
|
|
|
1105
1596
|
eventType: "scroll_depth",
|
|
1106
1597
|
metadata: {
|
|
1107
1598
|
depth_percent: threshold,
|
|
1108
|
-
page: { path:
|
|
1599
|
+
page: { path: currentPath2 }
|
|
1109
1600
|
},
|
|
1110
1601
|
pageUrl: window.location.href,
|
|
1111
1602
|
occurredAt: null
|
|
@@ -1122,8 +1613,8 @@ function attachScrollDepth(client, config) {
|
|
|
1122
1613
|
}
|
|
1123
1614
|
function resetIfPathChanged() {
|
|
1124
1615
|
const newPath = window.location.pathname;
|
|
1125
|
-
if (newPath ===
|
|
1126
|
-
|
|
1616
|
+
if (newPath === currentPath2) return;
|
|
1617
|
+
currentPath2 = newPath;
|
|
1127
1618
|
firedForPath = /* @__PURE__ */ new Set();
|
|
1128
1619
|
setTimeout(checkThresholds, 0);
|
|
1129
1620
|
}
|
|
@@ -1199,13 +1690,13 @@ function attachMultiPageSession(client, config) {
|
|
|
1199
1690
|
return storage.getItem(FIRED_KEY) === "1";
|
|
1200
1691
|
}
|
|
1201
1692
|
function check() {
|
|
1202
|
-
const
|
|
1203
|
-
if (
|
|
1204
|
-
lastCheckedPath =
|
|
1693
|
+
const currentPath2 = window.location.pathname;
|
|
1694
|
+
if (currentPath2 === lastCheckedPath) return;
|
|
1695
|
+
lastCheckedPath = currentPath2;
|
|
1205
1696
|
resetIfSessionChanged();
|
|
1206
1697
|
if (hasFired()) return;
|
|
1207
1698
|
const paths = getDistinctPaths();
|
|
1208
|
-
paths.add(
|
|
1699
|
+
paths.add(currentPath2);
|
|
1209
1700
|
saveDistinctPaths(paths);
|
|
1210
1701
|
if (paths.size >= pageThreshold) {
|
|
1211
1702
|
storage.setItem(FIRED_KEY, "1");
|
|
@@ -1249,7 +1740,7 @@ function attachFormStart(client, config) {
|
|
|
1249
1740
|
}
|
|
1250
1741
|
const selector = config.selector ?? "form";
|
|
1251
1742
|
let firedForms = /* @__PURE__ */ new Set();
|
|
1252
|
-
let
|
|
1743
|
+
let currentPath2 = window.location.pathname;
|
|
1253
1744
|
function getFormKey(form) {
|
|
1254
1745
|
if (form.id) return `id:${form.id}`;
|
|
1255
1746
|
const explicitAction = form.getAttribute("action");
|
|
@@ -1280,8 +1771,8 @@ function attachFormStart(client, config) {
|
|
|
1280
1771
|
}
|
|
1281
1772
|
function resetIfPathChanged() {
|
|
1282
1773
|
const newPath = window.location.pathname;
|
|
1283
|
-
if (newPath ===
|
|
1284
|
-
|
|
1774
|
+
if (newPath === currentPath2) return;
|
|
1775
|
+
currentPath2 = newPath;
|
|
1285
1776
|
firedForms = /* @__PURE__ */ new Set();
|
|
1286
1777
|
}
|
|
1287
1778
|
const originalPushState = history.pushState.bind(history);
|
|
@@ -1360,21 +1851,64 @@ async function salesRequest(config, method, path, body) {
|
|
|
1360
1851
|
}
|
|
1361
1852
|
|
|
1362
1853
|
// ../tracking-core/src/resources/sales/client.ts
|
|
1854
|
+
function fireRecordedConversions(firing, input, recorded, sale, currency) {
|
|
1855
|
+
if (!firing) return;
|
|
1856
|
+
const txnBase = input.external_id ?? sale.id;
|
|
1857
|
+
for (const item of recorded) {
|
|
1858
|
+
if (!item.service) continue;
|
|
1859
|
+
const config = firing.getFiring(item.service);
|
|
1860
|
+
if (!config) continue;
|
|
1861
|
+
const cents = item.amount_cents ?? config.value_cents ?? null;
|
|
1862
|
+
fireConversionWithConsent({
|
|
1863
|
+
sendTo: config.send_to,
|
|
1864
|
+
value: cents != null ? fromMinor(cents, currency) : null,
|
|
1865
|
+
currency: config.currency ?? currency,
|
|
1866
|
+
transactionId: `${txnBase}:${item.service}`
|
|
1867
|
+
});
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1363
1870
|
function createSalesClient(config) {
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1871
|
+
async function record(input) {
|
|
1872
|
+
const currency = input.currency ?? config.defaultCurrency;
|
|
1873
|
+
if (!currency) {
|
|
1874
|
+
throw new Error(
|
|
1875
|
+
"record: `currency` is required (pass it on the sale or set config.defaultCurrency)"
|
|
1876
|
+
);
|
|
1877
|
+
}
|
|
1878
|
+
const body = {
|
|
1879
|
+
...input,
|
|
1880
|
+
currency,
|
|
1881
|
+
occurred_at: input.occurred_at ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
1882
|
+
};
|
|
1883
|
+
const sale = await salesRequest(config, "POST", "/sales", body);
|
|
1884
|
+
const recorded = input.services?.length ? input.services.map((s) => ({
|
|
1885
|
+
service: s.service,
|
|
1886
|
+
amount_cents: s.amount_cents
|
|
1887
|
+
})) : [
|
|
1888
|
+
{
|
|
1889
|
+
service: input.service,
|
|
1890
|
+
amount_cents: input.amount_total_cents ?? null
|
|
1371
1891
|
}
|
|
1372
|
-
|
|
1373
|
-
|
|
1892
|
+
];
|
|
1893
|
+
fireRecordedConversions(config.firing, input, recorded, sale, currency);
|
|
1894
|
+
return sale;
|
|
1895
|
+
}
|
|
1896
|
+
return {
|
|
1897
|
+
record,
|
|
1898
|
+
// recordSale is the intent-revealing alias — same behavior, clearer call site.
|
|
1899
|
+
recordSale: record,
|
|
1900
|
+
trackConversion(key, options) {
|
|
1901
|
+
const firing = config.firing?.getFiring(key);
|
|
1902
|
+
if (!firing) return;
|
|
1903
|
+
const currency = firing.currency ?? options?.currency ?? config.defaultCurrency ?? null;
|
|
1904
|
+
const cents = firing.value_cents ?? null;
|
|
1905
|
+
const value = options?.value ?? (cents != null && currency ? fromMinor(cents, currency) : null);
|
|
1906
|
+
fireConversionWithConsent({
|
|
1907
|
+
sendTo: firing.send_to,
|
|
1908
|
+
value,
|
|
1374
1909
|
currency,
|
|
1375
|
-
|
|
1376
|
-
};
|
|
1377
|
-
return salesRequest(config, "POST", "/sales", body);
|
|
1910
|
+
transactionId: options?.transactionId ?? null
|
|
1911
|
+
});
|
|
1378
1912
|
},
|
|
1379
1913
|
async list(query) {
|
|
1380
1914
|
const { cursor, limit, sort, order, want_total, ...filters } = query ?? {};
|
|
@@ -1468,39 +2002,6 @@ function createSalesClient(config) {
|
|
|
1468
2002
|
};
|
|
1469
2003
|
}
|
|
1470
2004
|
|
|
1471
|
-
// ../tracking-core/src/resources/sales/money.ts
|
|
1472
|
-
var MINOR_UNIT_EXPONENT = {
|
|
1473
|
-
USD: 2,
|
|
1474
|
-
CAD: 2
|
|
1475
|
-
};
|
|
1476
|
-
function exponentFor(currency) {
|
|
1477
|
-
return MINOR_UNIT_EXPONENT[currency] ?? 2;
|
|
1478
|
-
}
|
|
1479
|
-
function toMinor(amount, currency) {
|
|
1480
|
-
return Math.round(amount * 10 ** exponentFor(currency));
|
|
1481
|
-
}
|
|
1482
|
-
function fromMinor(cents, currency) {
|
|
1483
|
-
return cents / 10 ** exponentFor(currency);
|
|
1484
|
-
}
|
|
1485
|
-
function formatMoney(cents, currency, locale) {
|
|
1486
|
-
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
|
|
1487
|
-
fromMinor(cents, currency)
|
|
1488
|
-
);
|
|
1489
|
-
}
|
|
1490
|
-
function formatDateInTz(iso, timeZone, opts, locale) {
|
|
1491
|
-
const date = new Date(iso);
|
|
1492
|
-
if (Number.isNaN(date.getTime())) return iso;
|
|
1493
|
-
return new Intl.DateTimeFormat(locale, {
|
|
1494
|
-
year: "numeric",
|
|
1495
|
-
month: "short",
|
|
1496
|
-
day: "2-digit",
|
|
1497
|
-
hour: "2-digit",
|
|
1498
|
-
minute: "2-digit",
|
|
1499
|
-
...opts,
|
|
1500
|
-
timeZone
|
|
1501
|
-
}).format(date);
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
2005
|
// ../tracking-core/src/resources/sales/schema.ts
|
|
1505
2006
|
var import_zod11 = require("zod");
|
|
1506
2007
|
var SUPPORTED_CURRENCIES = ["USD", "CAD"];
|
|
@@ -1899,11 +2400,19 @@ var ANIMATION_KEYFRAMES = `
|
|
|
1899
2400
|
}
|
|
1900
2401
|
`;
|
|
1901
2402
|
|
|
1902
|
-
// src/
|
|
2403
|
+
// src/AdPlatformTracking.tsx
|
|
1903
2404
|
var import_react3 = require("react");
|
|
1904
|
-
function
|
|
1905
|
-
|
|
2405
|
+
function AdPlatformTracking({
|
|
2406
|
+
gtagId,
|
|
2407
|
+
gtagIds,
|
|
2408
|
+
metaPixelId,
|
|
2409
|
+
metaPixelIds
|
|
2410
|
+
}) {
|
|
1906
2411
|
const gtagIdsKey = (0, import_react3.useMemo)(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
|
|
2412
|
+
const metaPixelIdsKey = (0, import_react3.useMemo)(
|
|
2413
|
+
() => metaPixelIds ? JSON.stringify(metaPixelIds) : "",
|
|
2414
|
+
[metaPixelIds]
|
|
2415
|
+
);
|
|
1907
2416
|
(0, import_react3.useEffect)(() => {
|
|
1908
2417
|
if (gtagIds && Object.keys(gtagIds).length > 0) {
|
|
1909
2418
|
bootstrapMultipleGtags(gtagIds);
|
|
@@ -1911,21 +2420,43 @@ function GoogleAdsTracking(props) {
|
|
|
1911
2420
|
bootstrapGoogleAdsTracking(gtagId);
|
|
1912
2421
|
}
|
|
1913
2422
|
}, [gtagId, gtagIdsKey]);
|
|
2423
|
+
(0, import_react3.useEffect)(() => {
|
|
2424
|
+
if (metaPixelIds && Object.keys(metaPixelIds).length > 0) {
|
|
2425
|
+
bootstrapMultiplePixels(metaPixelIds);
|
|
2426
|
+
} else if (metaPixelId) {
|
|
2427
|
+
bootstrapMetaPixel(metaPixelId);
|
|
2428
|
+
}
|
|
2429
|
+
}, [metaPixelId, metaPixelIdsKey]);
|
|
2430
|
+
return null;
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
// src/GoogleAdsTracking.tsx
|
|
2434
|
+
var import_react4 = require("react");
|
|
2435
|
+
function GoogleAdsTracking(props) {
|
|
2436
|
+
const { gtagId, gtagIds } = props;
|
|
2437
|
+
const gtagIdsKey = (0, import_react4.useMemo)(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
|
|
2438
|
+
(0, import_react4.useEffect)(() => {
|
|
2439
|
+
if (gtagIds && Object.keys(gtagIds).length > 0) {
|
|
2440
|
+
bootstrapMultipleGtags(gtagIds);
|
|
2441
|
+
} else if (gtagId) {
|
|
2442
|
+
bootstrapGoogleAdsTracking(gtagId);
|
|
2443
|
+
}
|
|
2444
|
+
}, [gtagId, gtagIdsKey]);
|
|
1914
2445
|
return null;
|
|
1915
2446
|
}
|
|
1916
2447
|
|
|
1917
2448
|
// src/factory.tsx
|
|
1918
|
-
var
|
|
2449
|
+
var import_react6 = require("react");
|
|
1919
2450
|
|
|
1920
2451
|
// package.json
|
|
1921
|
-
var version = "0.
|
|
2452
|
+
var version = "0.14.0";
|
|
1922
2453
|
|
|
1923
2454
|
// ../tracking-core/src/phone-react.tsx
|
|
1924
|
-
var
|
|
2455
|
+
var import_react5 = require("react");
|
|
1925
2456
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1926
2457
|
var _phoneConfigContext;
|
|
1927
2458
|
function phoneConfigContext() {
|
|
1928
|
-
return _phoneConfigContext ?? (_phoneConfigContext = (0,
|
|
2459
|
+
return _phoneConfigContext ?? (_phoneConfigContext = (0, import_react5.createContext)(null));
|
|
1929
2460
|
}
|
|
1930
2461
|
function PhoneConfigProvider({
|
|
1931
2462
|
value,
|
|
@@ -1935,7 +2466,7 @@ function PhoneConfigProvider({
|
|
|
1935
2466
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Ctx.Provider, { value, children });
|
|
1936
2467
|
}
|
|
1937
2468
|
function usePhoneConfig() {
|
|
1938
|
-
const ctx = (0,
|
|
2469
|
+
const ctx = (0, import_react5.useContext)(phoneConfigContext());
|
|
1939
2470
|
return {
|
|
1940
2471
|
defaultCountry: ctx?.defaultCountry ?? DEFAULT_PHONE_COUNTRY,
|
|
1941
2472
|
display: ctx?.display ?? "national"
|
|
@@ -1946,10 +2477,10 @@ function usePhoneField(opts = {}) {
|
|
|
1946
2477
|
const country = opts.country ?? cfg.defaultCountry;
|
|
1947
2478
|
const display = opts.display ?? cfg.display;
|
|
1948
2479
|
const { onValueChange } = opts;
|
|
1949
|
-
const [value, setValue] = (0,
|
|
1950
|
-
const [touched, setTouched] = (0,
|
|
1951
|
-
const parsed = (0,
|
|
1952
|
-
const onChange = (0,
|
|
2480
|
+
const [value, setValue] = (0, import_react5.useState)(() => formatPhoneAsTyped(opts.defaultValue ?? "", country));
|
|
2481
|
+
const [touched, setTouched] = (0, import_react5.useState)(false);
|
|
2482
|
+
const parsed = (0, import_react5.useMemo)(() => parsePhone(value, country), [value, country]);
|
|
2483
|
+
const onChange = (0, import_react5.useCallback)(
|
|
1953
2484
|
(event) => {
|
|
1954
2485
|
const next = formatPhoneAsTyped(event.target.value, country);
|
|
1955
2486
|
setValue(next);
|
|
@@ -1957,7 +2488,7 @@ function usePhoneField(opts = {}) {
|
|
|
1957
2488
|
},
|
|
1958
2489
|
[country, onValueChange]
|
|
1959
2490
|
);
|
|
1960
|
-
const onBlur = (0,
|
|
2491
|
+
const onBlur = (0, import_react5.useCallback)(
|
|
1961
2492
|
(_event) => {
|
|
1962
2493
|
setTouched(true);
|
|
1963
2494
|
setValue((current) => {
|
|
@@ -1977,11 +2508,11 @@ function usePhoneField(opts = {}) {
|
|
|
1977
2508
|
inputProps: { value, onChange, onBlur, type: "tel", inputMode: "tel", autoComplete: "tel" }
|
|
1978
2509
|
};
|
|
1979
2510
|
}
|
|
1980
|
-
var PhoneField = (0,
|
|
2511
|
+
var PhoneField = (0, import_react5.forwardRef)(function PhoneField2({ country, value, defaultValue, onChange, onE164Change, ...rest }, ref) {
|
|
1981
2512
|
const cfg = usePhoneConfig();
|
|
1982
2513
|
const resolvedCountry = country ?? cfg.defaultCountry;
|
|
1983
2514
|
const isControlled = value !== void 0;
|
|
1984
|
-
const [internal, setInternal] = (0,
|
|
2515
|
+
const [internal, setInternal] = (0, import_react5.useState)(
|
|
1985
2516
|
() => formatPhoneAsTyped(defaultValue ?? "", resolvedCountry)
|
|
1986
2517
|
);
|
|
1987
2518
|
const handleChange = (event) => {
|
|
@@ -2017,7 +2548,7 @@ var NOOP_CLIENT = {
|
|
|
2017
2548
|
getVisitorId: () => ""
|
|
2018
2549
|
};
|
|
2019
2550
|
function createTracking(options) {
|
|
2020
|
-
const { apiKey, endpoint, triggers, environment, debug, phone } = options;
|
|
2551
|
+
const { apiKey, endpoint, triggers, environment, debug, phone, conversionConfig } = options;
|
|
2021
2552
|
if (!apiKey || !endpoint) {
|
|
2022
2553
|
if (apiKey || endpoint) {
|
|
2023
2554
|
console.warn(
|
|
@@ -2032,12 +2563,18 @@ function createTracking(options) {
|
|
|
2032
2563
|
useTracking: () => noopTyped
|
|
2033
2564
|
};
|
|
2034
2565
|
}
|
|
2035
|
-
const TrackingContext = (0,
|
|
2036
|
-
function TrackingProvider({
|
|
2566
|
+
const TrackingContext = (0, import_react6.createContext)(null);
|
|
2567
|
+
function TrackingProvider({
|
|
2568
|
+
gtagId,
|
|
2569
|
+
gtagIds,
|
|
2570
|
+
metaPixelId,
|
|
2571
|
+
metaPixelIds,
|
|
2572
|
+
children
|
|
2573
|
+
}) {
|
|
2037
2574
|
const resolvedGtagIds = gtagIds ? Object.fromEntries(
|
|
2038
2575
|
Object.entries(gtagIds).filter((e) => e[1] != null)
|
|
2039
2576
|
) : gtagId ? { default: gtagId } : void 0;
|
|
2040
|
-
const client = (0,
|
|
2577
|
+
const client = (0, import_react6.useMemo)(
|
|
2041
2578
|
() => createTypedClient(
|
|
2042
2579
|
getOrCreateTrackingClient({
|
|
2043
2580
|
apiKey,
|
|
@@ -2055,15 +2592,26 @@ function createTracking(options) {
|
|
|
2055
2592
|
),
|
|
2056
2593
|
[]
|
|
2057
2594
|
);
|
|
2058
|
-
const gtagIdsKey = (0,
|
|
2059
|
-
(0,
|
|
2595
|
+
const gtagIdsKey = (0, import_react6.useMemo)(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
|
|
2596
|
+
(0, import_react6.useEffect)(() => {
|
|
2060
2597
|
if (gtagIds && Object.keys(gtagIds).length > 0) {
|
|
2061
2598
|
bootstrapMultipleGtags(gtagIds);
|
|
2062
2599
|
} else if (gtagId) {
|
|
2063
2600
|
bootstrapGoogleAdsTracking(gtagId);
|
|
2064
2601
|
}
|
|
2065
2602
|
}, [gtagId, gtagIdsKey]);
|
|
2066
|
-
(0,
|
|
2603
|
+
const metaPixelIdsKey = (0, import_react6.useMemo)(
|
|
2604
|
+
() => metaPixelIds ? JSON.stringify(metaPixelIds) : "",
|
|
2605
|
+
[metaPixelIds]
|
|
2606
|
+
);
|
|
2607
|
+
(0, import_react6.useEffect)(() => {
|
|
2608
|
+
if (metaPixelIds && Object.keys(metaPixelIds).length > 0) {
|
|
2609
|
+
bootstrapMultiplePixels(metaPixelIds);
|
|
2610
|
+
} else if (metaPixelId) {
|
|
2611
|
+
bootstrapMetaPixel(metaPixelId);
|
|
2612
|
+
}
|
|
2613
|
+
}, [metaPixelId, metaPixelIdsKey]);
|
|
2614
|
+
(0, import_react6.useEffect)(() => {
|
|
2067
2615
|
const detachers = [];
|
|
2068
2616
|
const rawClient = getOrCreateTrackingClient({
|
|
2069
2617
|
apiKey,
|
|
@@ -2075,27 +2623,32 @@ function createTracking(options) {
|
|
|
2075
2623
|
activeGtagIds: resolvedGtagIds,
|
|
2076
2624
|
debug
|
|
2077
2625
|
});
|
|
2078
|
-
|
|
2079
|
-
|
|
2626
|
+
const conversionStore = conversionConfig ? resolveConversionConfig({
|
|
2627
|
+
cdnUrl: conversionConfig.cdnUrl,
|
|
2628
|
+
baked: conversionConfig.baked
|
|
2629
|
+
}) : null;
|
|
2630
|
+
const detectorClient = conversionStore ? withConversionAutoFire(rawClient, createConversionAutoFire(conversionStore)) : rawClient;
|
|
2631
|
+
detachers.push(attachAutoPageView(detectorClient));
|
|
2632
|
+
detachers.push(attachBfcacheRestore(detectorClient));
|
|
2080
2633
|
const timeOnSite = triggers.automatic.time_on_site;
|
|
2081
2634
|
if (timeOnSite) {
|
|
2082
|
-
detachers.push(attachTimeOnSite(
|
|
2635
|
+
detachers.push(attachTimeOnSite(detectorClient, timeOnSite));
|
|
2083
2636
|
}
|
|
2084
2637
|
const specificPageVisit = triggers.automatic.specific_page_visit;
|
|
2085
2638
|
if (specificPageVisit) {
|
|
2086
|
-
detachers.push(attachSpecificPageVisit(
|
|
2639
|
+
detachers.push(attachSpecificPageVisit(detectorClient, specificPageVisit));
|
|
2087
2640
|
}
|
|
2088
2641
|
const scrollDepth = triggers.automatic.scroll_depth;
|
|
2089
2642
|
if (scrollDepth) {
|
|
2090
|
-
detachers.push(attachScrollDepth(
|
|
2643
|
+
detachers.push(attachScrollDepth(detectorClient, scrollDepth));
|
|
2091
2644
|
}
|
|
2092
2645
|
const multiPageSession = triggers.automatic.multi_page_session;
|
|
2093
2646
|
if (multiPageSession) {
|
|
2094
|
-
detachers.push(attachMultiPageSession(
|
|
2647
|
+
detachers.push(attachMultiPageSession(detectorClient, multiPageSession));
|
|
2095
2648
|
}
|
|
2096
2649
|
const formStart = triggers.automatic.form_start;
|
|
2097
2650
|
if (formStart) {
|
|
2098
|
-
detachers.push(attachFormStart(
|
|
2651
|
+
detachers.push(attachFormStart(detectorClient, formStart));
|
|
2099
2652
|
}
|
|
2100
2653
|
return () => {
|
|
2101
2654
|
for (let i = detachers.length - 1; i >= 0; i--) {
|
|
@@ -2106,7 +2659,7 @@ function createTracking(options) {
|
|
|
2106
2659
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TrackingContext.Provider, { value: client, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PhoneConfigProvider, { value: phone ?? null, children }) });
|
|
2107
2660
|
}
|
|
2108
2661
|
function useTracking() {
|
|
2109
|
-
const client = (0,
|
|
2662
|
+
const client = (0, import_react6.useContext)(TrackingContext);
|
|
2110
2663
|
if (client === null) {
|
|
2111
2664
|
throw new Error(
|
|
2112
2665
|
"useTracking must be called inside a <TrackingProvider> returned by createTracking()"
|
|
@@ -2118,6 +2671,7 @@ function createTracking(options) {
|
|
|
2118
2671
|
}
|
|
2119
2672
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2120
2673
|
0 && (module.exports = {
|
|
2674
|
+
AdPlatformTracking,
|
|
2121
2675
|
AranovaApiError,
|
|
2122
2676
|
ConsentBanner,
|
|
2123
2677
|
DEFAULT_PHONE_COUNTRY,
|
|
@@ -2143,6 +2697,7 @@ function createTracking(options) {
|
|
|
2143
2697
|
parsePhone,
|
|
2144
2698
|
phoneField,
|
|
2145
2699
|
resetConsent,
|
|
2700
|
+
resolveConversionConfig,
|
|
2146
2701
|
saleCreateSchema,
|
|
2147
2702
|
saleItemSchema,
|
|
2148
2703
|
saleServiceSchema,
|