@aranova/tracking-next 0.13.0 → 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 +25 -14
- package/dist/index.d.ts +25 -14
- package/dist/index.js +406 -62
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +405 -62
- package/dist/index.mjs.map +1 -1
- package/dist/middleware.js +73 -0
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +73 -0
- package/dist/middleware.mjs.map +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/dist/server.js +73 -0
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +73 -0
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
// ../tracking-core/src/consent.ts
|
|
2
2
|
var CONSENT_STATE_KEY = "consent_state";
|
|
3
3
|
var CONSENT_TIMESTAMP_KEY = "consent_timestamp";
|
|
4
|
+
var grantedListeners = /* @__PURE__ */ new Set();
|
|
5
|
+
function onConsentGranted(listener) {
|
|
6
|
+
grantedListeners.add(listener);
|
|
7
|
+
return () => {
|
|
8
|
+
grantedListeners.delete(listener);
|
|
9
|
+
};
|
|
10
|
+
}
|
|
4
11
|
function buildConsentPayload(state) {
|
|
5
12
|
return {
|
|
6
13
|
ad_storage: state,
|
|
@@ -29,6 +36,14 @@ function setConsentState(state) {
|
|
|
29
36
|
window.gtag("consent", "update", buildConsentPayload(state));
|
|
30
37
|
if (typeof window.fbq === "function")
|
|
31
38
|
window.fbq("consent", state === "granted" ? "grant" : "revoke");
|
|
39
|
+
if (state === "granted") {
|
|
40
|
+
for (const listener of grantedListeners) {
|
|
41
|
+
try {
|
|
42
|
+
listener();
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
32
47
|
}
|
|
33
48
|
function resetConsent() {
|
|
34
49
|
if (typeof window === "undefined") return;
|
|
@@ -185,6 +200,24 @@ try {
|
|
|
185
200
|
} catch (e) {}
|
|
186
201
|
`.trim();
|
|
187
202
|
}
|
|
203
|
+
var SEND_TO_RE = /^AW-[A-Za-z0-9]+\/[A-Za-z0-9_-]+$/;
|
|
204
|
+
function isValidSendTo(sendTo) {
|
|
205
|
+
return SEND_TO_RE.test(sendTo);
|
|
206
|
+
}
|
|
207
|
+
function fireGtagConversion(input) {
|
|
208
|
+
if (typeof window === "undefined" || typeof window.gtag !== "function") return false;
|
|
209
|
+
if (!isValidSendTo(input.sendTo)) return false;
|
|
210
|
+
const params = { send_to: input.sendTo };
|
|
211
|
+
if (input.value != null) params.value = input.value;
|
|
212
|
+
if (input.currency) params.currency = input.currency;
|
|
213
|
+
if (input.transactionId) params.transaction_id = input.transactionId;
|
|
214
|
+
try {
|
|
215
|
+
window.gtag("event", "conversion", params);
|
|
216
|
+
return true;
|
|
217
|
+
} catch {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
188
221
|
function createGtagInitScriptMulti(gtagIds) {
|
|
189
222
|
const safeIds = gtagIds.filter(isValidGtagId);
|
|
190
223
|
const configs = safeIds.map((id) => `gtag('config', '${id}');`).join("\n");
|
|
@@ -313,6 +346,289 @@ function createTrackingEventCreatePayload(trackingParams, input, context) {
|
|
|
313
346
|
};
|
|
314
347
|
}
|
|
315
348
|
|
|
349
|
+
// ../tracking-core/src/resources/conversion-firing.ts
|
|
350
|
+
var DEDUP_PREFIX = "_aranova_conv_";
|
|
351
|
+
var MAX_PENDING = 100;
|
|
352
|
+
var pendingQueue = [];
|
|
353
|
+
function dedupKey(input) {
|
|
354
|
+
return `${DEDUP_PREFIX}${input.transactionId ?? ""}:${input.sendTo}`;
|
|
355
|
+
}
|
|
356
|
+
function alreadyFired(input) {
|
|
357
|
+
if (!input.transactionId || typeof window === "undefined") return false;
|
|
358
|
+
try {
|
|
359
|
+
return window.sessionStorage.getItem(dedupKey(input)) !== null;
|
|
360
|
+
} catch {
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
function markFired(input) {
|
|
365
|
+
if (!input.transactionId || typeof window === "undefined") return;
|
|
366
|
+
try {
|
|
367
|
+
window.sessionStorage.setItem(dedupKey(input), "1");
|
|
368
|
+
} catch {
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function fireOnce(input) {
|
|
372
|
+
if (alreadyFired(input)) return;
|
|
373
|
+
if (fireGtagConversion(input)) markFired(input);
|
|
374
|
+
}
|
|
375
|
+
function fireConversionWithConsent(input) {
|
|
376
|
+
const state = getConsentState();
|
|
377
|
+
if (state === "denied") return;
|
|
378
|
+
if (state === "pending") {
|
|
379
|
+
if (pendingQueue.length >= MAX_PENDING) pendingQueue.shift();
|
|
380
|
+
pendingQueue.push(input);
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
fireOnce(input);
|
|
384
|
+
}
|
|
385
|
+
function flushPendingConversions() {
|
|
386
|
+
if (getConsentState() !== "granted") return;
|
|
387
|
+
while (pendingQueue.length > 0) {
|
|
388
|
+
const input = pendingQueue.shift();
|
|
389
|
+
if (input) fireOnce(input);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
if (typeof window !== "undefined") onConsentGranted(flushPendingConversions);
|
|
393
|
+
|
|
394
|
+
// ../tracking-core/src/resources/conversion-config.ts
|
|
395
|
+
function isStringMap(value) {
|
|
396
|
+
return typeof value === "object" && value !== null && Object.values(value).every((v) => typeof v === "string");
|
|
397
|
+
}
|
|
398
|
+
function parseFiring(value) {
|
|
399
|
+
if (!value || typeof value !== "object") return null;
|
|
400
|
+
const f = value;
|
|
401
|
+
if (typeof f.send_to !== "string") return null;
|
|
402
|
+
return {
|
|
403
|
+
send_to: f.send_to,
|
|
404
|
+
value_cents: typeof f.value_cents === "number" ? f.value_cents : null,
|
|
405
|
+
currency: typeof f.currency === "string" ? f.currency : null
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
function parseTrigger(value) {
|
|
409
|
+
if (!value || typeof value !== "object") return null;
|
|
410
|
+
const t = value;
|
|
411
|
+
if (typeof t.event_type !== "string") return null;
|
|
412
|
+
const spec = { event_type: t.event_type };
|
|
413
|
+
if (typeof t.threshold_percent === "number") spec.threshold_percent = t.threshold_percent;
|
|
414
|
+
if (typeof t.threshold_seconds === "number") spec.threshold_seconds = t.threshold_seconds;
|
|
415
|
+
if (typeof t.page_threshold === "number") spec.page_threshold = t.page_threshold;
|
|
416
|
+
if (typeof t.page_name === "string") spec.page_name = t.page_name;
|
|
417
|
+
return spec;
|
|
418
|
+
}
|
|
419
|
+
function parseConversionConfig(raw) {
|
|
420
|
+
if (!raw || typeof raw !== "object") return null;
|
|
421
|
+
const obj = raw;
|
|
422
|
+
const servicesRaw = Array.isArray(obj.services) ? obj.services : [];
|
|
423
|
+
const services = servicesRaw.flatMap((entry) => {
|
|
424
|
+
if (!entry || typeof entry !== "object") return [];
|
|
425
|
+
const s = entry;
|
|
426
|
+
if (typeof s.key !== "string") return [];
|
|
427
|
+
return [
|
|
428
|
+
{
|
|
429
|
+
key: s.key,
|
|
430
|
+
label: typeof s.label === "string" ? s.label : void 0,
|
|
431
|
+
firing: parseFiring(s.firing)
|
|
432
|
+
}
|
|
433
|
+
];
|
|
434
|
+
});
|
|
435
|
+
const goalsRaw = Array.isArray(obj.goals) ? obj.goals : null;
|
|
436
|
+
const goals = goalsRaw ? goalsRaw.flatMap((entry) => {
|
|
437
|
+
if (!entry || typeof entry !== "object") return [];
|
|
438
|
+
const g = entry;
|
|
439
|
+
if (typeof g.key !== "string") return [];
|
|
440
|
+
return [
|
|
441
|
+
{
|
|
442
|
+
key: g.key,
|
|
443
|
+
label: typeof g.label === "string" ? g.label : void 0,
|
|
444
|
+
kind: g.kind === "event" ? "event" : "sale",
|
|
445
|
+
trigger: parseTrigger(g.trigger),
|
|
446
|
+
firing: parseFiring(g.firing)
|
|
447
|
+
}
|
|
448
|
+
];
|
|
449
|
+
}) : services.map((s) => ({
|
|
450
|
+
key: s.key,
|
|
451
|
+
label: s.label,
|
|
452
|
+
kind: "sale",
|
|
453
|
+
trigger: null,
|
|
454
|
+
firing: s.firing
|
|
455
|
+
}));
|
|
456
|
+
return {
|
|
457
|
+
schema_version: typeof obj.schema_version === "number" ? obj.schema_version : 1,
|
|
458
|
+
config_version: typeof obj.config_version === "number" ? obj.config_version : 0,
|
|
459
|
+
business_id: typeof obj.business_id === "string" ? obj.business_id : void 0,
|
|
460
|
+
customer_id: typeof obj.customer_id === "string" ? obj.customer_id : null,
|
|
461
|
+
environment: typeof obj.environment === "string" ? obj.environment : void 0,
|
|
462
|
+
gtag_ids: isStringMap(obj.gtag_ids) ? obj.gtag_ids : {},
|
|
463
|
+
meta_pixel_ids: isStringMap(obj.meta_pixel_ids) ? obj.meta_pixel_ids : {},
|
|
464
|
+
services,
|
|
465
|
+
goals
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
var CACHE_PREFIX = "_aranova_cfg_";
|
|
469
|
+
function cacheKey(url) {
|
|
470
|
+
return `${CACHE_PREFIX}${url}`;
|
|
471
|
+
}
|
|
472
|
+
function readCache(url) {
|
|
473
|
+
if (typeof window === "undefined") return null;
|
|
474
|
+
try {
|
|
475
|
+
const raw = window.sessionStorage.getItem(cacheKey(url));
|
|
476
|
+
if (!raw) return null;
|
|
477
|
+
const parsed = JSON.parse(raw);
|
|
478
|
+
const config = parseConversionConfig(parsed.config);
|
|
479
|
+
if (!config) return null;
|
|
480
|
+
return {
|
|
481
|
+
etag: typeof parsed.etag === "string" ? parsed.etag : null,
|
|
482
|
+
config
|
|
483
|
+
};
|
|
484
|
+
} catch {
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
function writeCache(url, entry) {
|
|
489
|
+
if (typeof window === "undefined") return;
|
|
490
|
+
try {
|
|
491
|
+
window.sessionStorage.setItem(cacheKey(url), JSON.stringify(entry));
|
|
492
|
+
} catch {
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
function resolveConversionConfig(options) {
|
|
496
|
+
const cached = readCache(options.cdnUrl);
|
|
497
|
+
let current = cached?.config ?? options.baked ?? null;
|
|
498
|
+
let etag = cached?.etag ?? null;
|
|
499
|
+
const goalsByKey = /* @__PURE__ */ new Map();
|
|
500
|
+
function rebuildIndex() {
|
|
501
|
+
goalsByKey.clear();
|
|
502
|
+
for (const goal of current?.goals ?? []) {
|
|
503
|
+
goalsByKey.set(goal.key, goal);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
function adopt(next, nextEtag) {
|
|
507
|
+
if (!next) return;
|
|
508
|
+
if (current && next.config_version <= current.config_version) return;
|
|
509
|
+
current = next;
|
|
510
|
+
etag = nextEtag;
|
|
511
|
+
rebuildIndex();
|
|
512
|
+
writeCache(options.cdnUrl, { etag, config: next });
|
|
513
|
+
}
|
|
514
|
+
async function revalidate() {
|
|
515
|
+
if (typeof window === "undefined") return;
|
|
516
|
+
try {
|
|
517
|
+
const doFetch = options.fetchImpl ?? globalThis.fetch;
|
|
518
|
+
if (!doFetch) return;
|
|
519
|
+
const headers = {};
|
|
520
|
+
if (etag) headers["If-None-Match"] = etag;
|
|
521
|
+
const response = await doFetch(options.cdnUrl, {
|
|
522
|
+
method: "GET",
|
|
523
|
+
headers
|
|
524
|
+
});
|
|
525
|
+
if (response.status === 304 || !response.ok) return;
|
|
526
|
+
adopt(parseConversionConfig(await response.json()), response.headers.get("ETag"));
|
|
527
|
+
} catch {
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
rebuildIndex();
|
|
531
|
+
void revalidate();
|
|
532
|
+
return {
|
|
533
|
+
getFiring: (key) => goalsByKey.get(key)?.firing ?? null,
|
|
534
|
+
getGoal: (key) => goalsByKey.get(key) ?? null,
|
|
535
|
+
listGoals: () => [...goalsByKey.values()],
|
|
536
|
+
current: () => current,
|
|
537
|
+
revalidate
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// ../tracking-core/src/resources/sales/money.ts
|
|
542
|
+
var MINOR_UNIT_EXPONENT = {
|
|
543
|
+
USD: 2,
|
|
544
|
+
CAD: 2
|
|
545
|
+
};
|
|
546
|
+
function exponentFor(currency) {
|
|
547
|
+
return MINOR_UNIT_EXPONENT[currency] ?? 2;
|
|
548
|
+
}
|
|
549
|
+
function toMinor(amount, currency) {
|
|
550
|
+
return Math.round(amount * 10 ** exponentFor(currency));
|
|
551
|
+
}
|
|
552
|
+
function fromMinor(cents, currency) {
|
|
553
|
+
return cents / 10 ** exponentFor(currency);
|
|
554
|
+
}
|
|
555
|
+
function formatMoney(cents, currency, locale) {
|
|
556
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
|
|
557
|
+
fromMinor(cents, currency)
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
function formatDateInTz(iso, timeZone, opts, locale) {
|
|
561
|
+
const date = new Date(iso);
|
|
562
|
+
if (Number.isNaN(date.getTime())) return iso;
|
|
563
|
+
return new Intl.DateTimeFormat(locale, {
|
|
564
|
+
year: "numeric",
|
|
565
|
+
month: "short",
|
|
566
|
+
day: "2-digit",
|
|
567
|
+
hour: "2-digit",
|
|
568
|
+
minute: "2-digit",
|
|
569
|
+
...opts,
|
|
570
|
+
timeZone
|
|
571
|
+
}).format(date);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// ../tracking-core/src/resources/conversion-autofire.ts
|
|
575
|
+
function thresholdMet(goal, eventType, metadata) {
|
|
576
|
+
const t = goal.trigger;
|
|
577
|
+
if (!t || t.event_type !== eventType) return false;
|
|
578
|
+
switch (eventType) {
|
|
579
|
+
case "scroll_depth":
|
|
580
|
+
return typeof metadata.depth_percent === "number" && t.threshold_percent != null && metadata.depth_percent >= t.threshold_percent;
|
|
581
|
+
case "time_on_site":
|
|
582
|
+
return typeof metadata.duration_ms === "number" && t.threshold_seconds != null && metadata.duration_ms >= t.threshold_seconds * 1e3;
|
|
583
|
+
case "multi_page_session":
|
|
584
|
+
return typeof metadata.page_count === "number" && t.page_threshold != null && metadata.page_count >= t.page_threshold;
|
|
585
|
+
case "specific_page_visit":
|
|
586
|
+
return typeof metadata.page_name === "string" && metadata.page_name === t.page_name;
|
|
587
|
+
case "page_view":
|
|
588
|
+
case "form_start":
|
|
589
|
+
return true;
|
|
590
|
+
// no threshold — fire whenever the detector emits
|
|
591
|
+
default:
|
|
592
|
+
return false;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
function currentPath() {
|
|
596
|
+
return typeof window === "undefined" ? "" : window.location.pathname;
|
|
597
|
+
}
|
|
598
|
+
function createConversionAutoFire(store) {
|
|
599
|
+
return {
|
|
600
|
+
onAutomaticEvent(eventType, metadata) {
|
|
601
|
+
for (const goal of store.listGoals()) {
|
|
602
|
+
if (goal.kind !== "event" || !goal.firing) continue;
|
|
603
|
+
if (!thresholdMet(goal, eventType, metadata)) continue;
|
|
604
|
+
const firing = goal.firing;
|
|
605
|
+
const cents = firing.value_cents ?? null;
|
|
606
|
+
const currency = firing.currency ?? null;
|
|
607
|
+
fireConversionWithConsent({
|
|
608
|
+
sendTo: firing.send_to,
|
|
609
|
+
value: cents != null && currency ? fromMinor(cents, currency) : null,
|
|
610
|
+
currency,
|
|
611
|
+
// Page-scoped txn id → fire once per (goal, path) per session; engagement conversions
|
|
612
|
+
// shouldn't re-fire as the visitor scrolls back and forth or re-enters a page.
|
|
613
|
+
transactionId: `auto:${goal.key}:${currentPath()}`
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
function withConversionAutoFire(client, autoFire) {
|
|
620
|
+
return {
|
|
621
|
+
...client,
|
|
622
|
+
trackEvent: (input) => {
|
|
623
|
+
client.trackEvent(input);
|
|
624
|
+
try {
|
|
625
|
+
autoFire.onAutomaticEvent(input.eventType, input.metadata ?? {});
|
|
626
|
+
} catch {
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
|
|
316
632
|
// ../tracking-core/src/session.ts
|
|
317
633
|
var VISITOR_STORAGE_KEY = "aranova_tracking_visitor";
|
|
318
634
|
var SESSION_STORAGE_KEY = "aranova_tracking_session";
|
|
@@ -1049,7 +1365,7 @@ function attachScrollDepth(client, config) {
|
|
|
1049
1365
|
}
|
|
1050
1366
|
const thresholds = new Set(config.thresholds);
|
|
1051
1367
|
let firedForPath = /* @__PURE__ */ new Set();
|
|
1052
|
-
let
|
|
1368
|
+
let currentPath2 = window.location.pathname;
|
|
1053
1369
|
let rafId = null;
|
|
1054
1370
|
function getScrollPercent() {
|
|
1055
1371
|
const doc = document.documentElement;
|
|
@@ -1068,7 +1384,7 @@ function attachScrollDepth(client, config) {
|
|
|
1068
1384
|
eventType: "scroll_depth",
|
|
1069
1385
|
metadata: {
|
|
1070
1386
|
depth_percent: threshold,
|
|
1071
|
-
page: { path:
|
|
1387
|
+
page: { path: currentPath2 }
|
|
1072
1388
|
},
|
|
1073
1389
|
pageUrl: window.location.href,
|
|
1074
1390
|
occurredAt: null
|
|
@@ -1085,8 +1401,8 @@ function attachScrollDepth(client, config) {
|
|
|
1085
1401
|
}
|
|
1086
1402
|
function resetIfPathChanged() {
|
|
1087
1403
|
const newPath = window.location.pathname;
|
|
1088
|
-
if (newPath ===
|
|
1089
|
-
|
|
1404
|
+
if (newPath === currentPath2) return;
|
|
1405
|
+
currentPath2 = newPath;
|
|
1090
1406
|
firedForPath = /* @__PURE__ */ new Set();
|
|
1091
1407
|
setTimeout(checkThresholds, 0);
|
|
1092
1408
|
}
|
|
@@ -1122,7 +1438,7 @@ function attachFormStart(client, config) {
|
|
|
1122
1438
|
}
|
|
1123
1439
|
const selector = config.selector ?? "form";
|
|
1124
1440
|
let firedForms = /* @__PURE__ */ new Set();
|
|
1125
|
-
let
|
|
1441
|
+
let currentPath2 = window.location.pathname;
|
|
1126
1442
|
function getFormKey(form) {
|
|
1127
1443
|
if (form.id) return `id:${form.id}`;
|
|
1128
1444
|
const explicitAction = form.getAttribute("action");
|
|
@@ -1153,8 +1469,8 @@ function attachFormStart(client, config) {
|
|
|
1153
1469
|
}
|
|
1154
1470
|
function resetIfPathChanged() {
|
|
1155
1471
|
const newPath = window.location.pathname;
|
|
1156
|
-
if (newPath ===
|
|
1157
|
-
|
|
1472
|
+
if (newPath === currentPath2) return;
|
|
1473
|
+
currentPath2 = newPath;
|
|
1158
1474
|
firedForms = /* @__PURE__ */ new Set();
|
|
1159
1475
|
}
|
|
1160
1476
|
const originalPushState = history.pushState.bind(history);
|
|
@@ -1233,21 +1549,64 @@ async function salesRequest(config, method, path, body) {
|
|
|
1233
1549
|
}
|
|
1234
1550
|
|
|
1235
1551
|
// ../tracking-core/src/resources/sales/client.ts
|
|
1552
|
+
function fireRecordedConversions(firing, input, recorded, sale, currency) {
|
|
1553
|
+
if (!firing) return;
|
|
1554
|
+
const txnBase = input.external_id ?? sale.id;
|
|
1555
|
+
for (const item of recorded) {
|
|
1556
|
+
if (!item.service) continue;
|
|
1557
|
+
const config = firing.getFiring(item.service);
|
|
1558
|
+
if (!config) continue;
|
|
1559
|
+
const cents = item.amount_cents ?? config.value_cents ?? null;
|
|
1560
|
+
fireConversionWithConsent({
|
|
1561
|
+
sendTo: config.send_to,
|
|
1562
|
+
value: cents != null ? fromMinor(cents, currency) : null,
|
|
1563
|
+
currency: config.currency ?? currency,
|
|
1564
|
+
transactionId: `${txnBase}:${item.service}`
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1236
1568
|
function createSalesClient(config) {
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1569
|
+
async function record(input) {
|
|
1570
|
+
const currency = input.currency ?? config.defaultCurrency;
|
|
1571
|
+
if (!currency) {
|
|
1572
|
+
throw new Error(
|
|
1573
|
+
"record: `currency` is required (pass it on the sale or set config.defaultCurrency)"
|
|
1574
|
+
);
|
|
1575
|
+
}
|
|
1576
|
+
const body = {
|
|
1577
|
+
...input,
|
|
1578
|
+
currency,
|
|
1579
|
+
occurred_at: input.occurred_at ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
1580
|
+
};
|
|
1581
|
+
const sale = await salesRequest(config, "POST", "/sales", body);
|
|
1582
|
+
const recorded = input.services?.length ? input.services.map((s) => ({
|
|
1583
|
+
service: s.service,
|
|
1584
|
+
amount_cents: s.amount_cents
|
|
1585
|
+
})) : [
|
|
1586
|
+
{
|
|
1587
|
+
service: input.service,
|
|
1588
|
+
amount_cents: input.amount_total_cents ?? null
|
|
1244
1589
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1590
|
+
];
|
|
1591
|
+
fireRecordedConversions(config.firing, input, recorded, sale, currency);
|
|
1592
|
+
return sale;
|
|
1593
|
+
}
|
|
1594
|
+
return {
|
|
1595
|
+
record,
|
|
1596
|
+
// recordSale is the intent-revealing alias — same behavior, clearer call site.
|
|
1597
|
+
recordSale: record,
|
|
1598
|
+
trackConversion(key, options) {
|
|
1599
|
+
const firing = config.firing?.getFiring(key);
|
|
1600
|
+
if (!firing) return;
|
|
1601
|
+
const currency = firing.currency ?? options?.currency ?? config.defaultCurrency ?? null;
|
|
1602
|
+
const cents = firing.value_cents ?? null;
|
|
1603
|
+
const value = options?.value ?? (cents != null && currency ? fromMinor(cents, currency) : null);
|
|
1604
|
+
fireConversionWithConsent({
|
|
1605
|
+
sendTo: firing.send_to,
|
|
1606
|
+
value,
|
|
1247
1607
|
currency,
|
|
1248
|
-
|
|
1249
|
-
};
|
|
1250
|
-
return salesRequest(config, "POST", "/sales", body);
|
|
1608
|
+
transactionId: options?.transactionId ?? null
|
|
1609
|
+
});
|
|
1251
1610
|
},
|
|
1252
1611
|
async list(query) {
|
|
1253
1612
|
const { cursor, limit, sort, order, want_total, ...filters } = query ?? {};
|
|
@@ -1341,39 +1700,6 @@ function createSalesClient(config) {
|
|
|
1341
1700
|
};
|
|
1342
1701
|
}
|
|
1343
1702
|
|
|
1344
|
-
// ../tracking-core/src/resources/sales/money.ts
|
|
1345
|
-
var MINOR_UNIT_EXPONENT = {
|
|
1346
|
-
USD: 2,
|
|
1347
|
-
CAD: 2
|
|
1348
|
-
};
|
|
1349
|
-
function exponentFor(currency) {
|
|
1350
|
-
return MINOR_UNIT_EXPONENT[currency] ?? 2;
|
|
1351
|
-
}
|
|
1352
|
-
function toMinor(amount, currency) {
|
|
1353
|
-
return Math.round(amount * 10 ** exponentFor(currency));
|
|
1354
|
-
}
|
|
1355
|
-
function fromMinor(cents, currency) {
|
|
1356
|
-
return cents / 10 ** exponentFor(currency);
|
|
1357
|
-
}
|
|
1358
|
-
function formatMoney(cents, currency, locale) {
|
|
1359
|
-
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
|
|
1360
|
-
fromMinor(cents, currency)
|
|
1361
|
-
);
|
|
1362
|
-
}
|
|
1363
|
-
function formatDateInTz(iso, timeZone, opts, locale) {
|
|
1364
|
-
const date = new Date(iso);
|
|
1365
|
-
if (Number.isNaN(date.getTime())) return iso;
|
|
1366
|
-
return new Intl.DateTimeFormat(locale, {
|
|
1367
|
-
year: "numeric",
|
|
1368
|
-
month: "short",
|
|
1369
|
-
day: "2-digit",
|
|
1370
|
-
hour: "2-digit",
|
|
1371
|
-
minute: "2-digit",
|
|
1372
|
-
...opts,
|
|
1373
|
-
timeZone
|
|
1374
|
-
}).format(date);
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
1703
|
// ../tracking-core/src/resources/sales/schema.ts
|
|
1378
1704
|
import { z as z11 } from "zod";
|
|
1379
1705
|
var SUPPORTED_CURRENCIES = ["USD", "CAD"];
|
|
@@ -1838,7 +2164,7 @@ function GoogleAdsTracking(props) {
|
|
|
1838
2164
|
import { usePathname, useSearchParams } from "next/navigation";
|
|
1839
2165
|
|
|
1840
2166
|
// package.json
|
|
1841
|
-
var version = "0.
|
|
2167
|
+
var version = "0.14.0";
|
|
1842
2168
|
|
|
1843
2169
|
// src/factory.tsx
|
|
1844
2170
|
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect3, useMemo as useMemo2, useRef } from "react";
|
|
@@ -1939,7 +2265,7 @@ var PhoneField = forwardRef(function PhoneField2({ country, value, defaultValue,
|
|
|
1939
2265
|
// src/factory.tsx
|
|
1940
2266
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1941
2267
|
function createTracking(options) {
|
|
1942
|
-
const { apiKey, endpoint, triggers, environment, gtagIds, debug, phone } = options;
|
|
2268
|
+
const { apiKey, endpoint, triggers, environment, gtagIds, debug, phone, conversionConfig } = options;
|
|
1943
2269
|
if (!apiKey || !endpoint) {
|
|
1944
2270
|
if (apiKey || endpoint) {
|
|
1945
2271
|
console.warn(
|
|
@@ -1983,6 +2309,17 @@ function createTracking(options) {
|
|
|
1983
2309
|
),
|
|
1984
2310
|
[]
|
|
1985
2311
|
);
|
|
2312
|
+
const conversionStore = useMemo2(
|
|
2313
|
+
() => conversionConfig ? resolveConversionConfig({
|
|
2314
|
+
cdnUrl: conversionConfig.cdnUrl,
|
|
2315
|
+
baked: conversionConfig.baked
|
|
2316
|
+
}) : null,
|
|
2317
|
+
[]
|
|
2318
|
+
);
|
|
2319
|
+
const wrapClient = useMemo2(() => {
|
|
2320
|
+
const autoFire = conversionStore ? createConversionAutoFire(conversionStore) : null;
|
|
2321
|
+
return (c) => autoFire ? withConversionAutoFire(c, autoFire) : c;
|
|
2322
|
+
}, [conversionStore]);
|
|
1986
2323
|
useEffect3(() => {
|
|
1987
2324
|
const rawClient = getOrCreateTrackingClient({
|
|
1988
2325
|
apiKey,
|
|
@@ -1994,7 +2331,7 @@ function createTracking(options) {
|
|
|
1994
2331
|
activeGtagIds: gtagIds,
|
|
1995
2332
|
debug
|
|
1996
2333
|
});
|
|
1997
|
-
fireManualPageView(rawClient);
|
|
2334
|
+
fireManualPageView(wrapClient(rawClient));
|
|
1998
2335
|
}, [pathname, searchParams]);
|
|
1999
2336
|
const firedPagesRef = useRef(/* @__PURE__ */ new Set());
|
|
2000
2337
|
useEffect3(() => {
|
|
@@ -2009,14 +2346,18 @@ function createTracking(options) {
|
|
|
2009
2346
|
activeGtagIds: gtagIds,
|
|
2010
2347
|
debug
|
|
2011
2348
|
});
|
|
2349
|
+
const detectorClient = wrapClient(rawClient);
|
|
2012
2350
|
for (const { name, pathPattern } of specificPageVisitConfig.pages) {
|
|
2013
2351
|
if (!pathPattern.test(pathname)) continue;
|
|
2014
2352
|
const key = `${name}:${pathname}`;
|
|
2015
2353
|
if (firedPagesRef.current.has(key)) continue;
|
|
2016
2354
|
firedPagesRef.current.add(key);
|
|
2017
|
-
|
|
2355
|
+
detectorClient.trackEvent({
|
|
2018
2356
|
eventType: "specific_page_visit",
|
|
2019
|
-
metadata: {
|
|
2357
|
+
metadata: {
|
|
2358
|
+
page_name: name,
|
|
2359
|
+
page: { path: pathname }
|
|
2360
|
+
},
|
|
2020
2361
|
pageUrl: null,
|
|
2021
2362
|
occurredAt: null
|
|
2022
2363
|
});
|
|
@@ -2033,7 +2374,7 @@ function createTracking(options) {
|
|
|
2033
2374
|
activeGtagIds: gtagIds,
|
|
2034
2375
|
debug
|
|
2035
2376
|
});
|
|
2036
|
-
return attachBfcacheRestore(rawClient);
|
|
2377
|
+
return attachBfcacheRestore(wrapClient(rawClient));
|
|
2037
2378
|
}, []);
|
|
2038
2379
|
useEffect3(() => {
|
|
2039
2380
|
if (!timeOnSiteConfig) return;
|
|
@@ -2047,7 +2388,7 @@ function createTracking(options) {
|
|
|
2047
2388
|
activeGtagIds: gtagIds,
|
|
2048
2389
|
debug
|
|
2049
2390
|
});
|
|
2050
|
-
return attachTimeOnSite(rawClient, timeOnSiteConfig);
|
|
2391
|
+
return attachTimeOnSite(wrapClient(rawClient), timeOnSiteConfig);
|
|
2051
2392
|
}, []);
|
|
2052
2393
|
const multiPageSessionConfig = triggers.automatic.multi_page_session ?? null;
|
|
2053
2394
|
const mpsLastPathRef = useRef(null);
|
|
@@ -2085,7 +2426,7 @@ function createTracking(options) {
|
|
|
2085
2426
|
activeGtagIds: gtagIds,
|
|
2086
2427
|
debug
|
|
2087
2428
|
});
|
|
2088
|
-
rawClient.trackEvent({
|
|
2429
|
+
wrapClient(rawClient).trackEvent({
|
|
2089
2430
|
eventType: "multi_page_session",
|
|
2090
2431
|
metadata: {
|
|
2091
2432
|
page_count: paths.size,
|
|
@@ -2110,13 +2451,14 @@ function createTracking(options) {
|
|
|
2110
2451
|
activeGtagIds: gtagIds,
|
|
2111
2452
|
debug
|
|
2112
2453
|
});
|
|
2454
|
+
const detectorClient = wrapClient(rawClient);
|
|
2113
2455
|
const scrollDepth = triggers.automatic.scroll_depth;
|
|
2114
2456
|
if (scrollDepth) {
|
|
2115
|
-
detachers.push(attachScrollDepth(
|
|
2457
|
+
detachers.push(attachScrollDepth(detectorClient, scrollDepth));
|
|
2116
2458
|
}
|
|
2117
2459
|
const formStart = triggers.automatic.form_start;
|
|
2118
2460
|
if (formStart) {
|
|
2119
|
-
detachers.push(attachFormStart(
|
|
2461
|
+
detachers.push(attachFormStart(detectorClient, formStart));
|
|
2120
2462
|
}
|
|
2121
2463
|
return () => {
|
|
2122
2464
|
for (let i = detachers.length - 1; i >= 0; i--) {
|
|
@@ -2164,6 +2506,7 @@ export {
|
|
|
2164
2506
|
parsePhone,
|
|
2165
2507
|
phoneField,
|
|
2166
2508
|
resetConsent,
|
|
2509
|
+
resolveConversionConfig,
|
|
2167
2510
|
saleCreateSchema,
|
|
2168
2511
|
saleItemSchema,
|
|
2169
2512
|
saleServiceSchema,
|