@aranova/tracking-next 0.18.1 → 0.19.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/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +193 -58
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +191 -58
- package/dist/index.mjs.map +1 -1
- package/dist/middleware.js +8 -3
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +8 -3
- package/dist/middleware.mjs.map +1 -1
- package/dist/{phone-utils-CVCzW04Z.d.mts → phone-utils-B2vHJkNz.d.mts} +10 -0
- package/dist/{phone-utils-CVCzW04Z.d.ts → phone-utils-B2vHJkNz.d.ts} +10 -0
- package/dist/phone.d.mts +1 -1
- package/dist/phone.d.ts +1 -1
- package/dist/phone.js +40 -40
- package/dist/phone.js.map +1 -1
- package/dist/phone.mjs +40 -40
- package/dist/phone.mjs.map +1 -1
- package/dist/{sales-QqKh6_iy.d.mts → sales--WzOzyiO.d.mts} +18 -1
- package/dist/{sales-QqKh6_iy.d.ts → sales--WzOzyiO.d.ts} +18 -1
- package/dist/sales.d.mts +2 -1
- package/dist/sales.d.ts +2 -1
- package/dist/sales.js +97 -17
- package/dist/sales.js.map +1 -1
- package/dist/sales.mjs +97 -17
- package/dist/sales.mjs.map +1 -1
- package/dist/server.d.mts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +10 -3
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +10 -3
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,137 @@
|
|
|
1
|
+
// ../tracking-core/src/phone.ts
|
|
2
|
+
import { AsYouType, parsePhoneNumberFromString } from "libphonenumber-js";
|
|
3
|
+
var DEFAULT_PHONE_COUNTRY = "CA";
|
|
4
|
+
function parsePhone(raw, country) {
|
|
5
|
+
const region = country ?? DEFAULT_PHONE_COUNTRY;
|
|
6
|
+
const parsed = parsePhoneNumberFromString(raw ?? "", region);
|
|
7
|
+
if (!parsed) {
|
|
8
|
+
return { e164: null, national: "", international: "", country: region, isValid: false };
|
|
9
|
+
}
|
|
10
|
+
const isValid = parsed.isValid();
|
|
11
|
+
return {
|
|
12
|
+
// E.164 is only surfaced for a *valid* number — a possible-but-invalid input
|
|
13
|
+
// (e.g. too few digits) still parses but must not be transmitted.
|
|
14
|
+
e164: isValid ? parsed.number : null,
|
|
15
|
+
national: parsed.formatNational(),
|
|
16
|
+
international: parsed.formatInternational(),
|
|
17
|
+
country: parsed.country ?? region,
|
|
18
|
+
isValid
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function toE164(raw, country) {
|
|
22
|
+
return parsePhone(raw, country).e164;
|
|
23
|
+
}
|
|
24
|
+
function formatPhone(value, format = "national", country) {
|
|
25
|
+
const parsed = parsePhone(value, country);
|
|
26
|
+
if (typeof format === "function") return format(parsed);
|
|
27
|
+
switch (format) {
|
|
28
|
+
case "international":
|
|
29
|
+
return parsed.international || value;
|
|
30
|
+
case "e164":
|
|
31
|
+
return parsed.e164 ?? value;
|
|
32
|
+
case "national":
|
|
33
|
+
default:
|
|
34
|
+
return parsed.national || value;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function formatPhoneAsTyped(raw, country) {
|
|
38
|
+
return new AsYouType(country ?? DEFAULT_PHONE_COUNTRY).input(raw ?? "");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ../tracking-core/src/user-data.ts
|
|
42
|
+
var EMAIL_SHAPE = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
|
|
43
|
+
var EMAIL_NAME_HINT = /e[-_]?mail/i;
|
|
44
|
+
var PHONE_NAME_HINT = /(^|[^a-z])(phone|tel|mobile|cell)/i;
|
|
45
|
+
var stash = { email: null, phoneNumber: null };
|
|
46
|
+
function normalizeEmail(raw) {
|
|
47
|
+
if (typeof raw !== "string") return null;
|
|
48
|
+
const cleaned = raw.trim().toLowerCase();
|
|
49
|
+
return EMAIL_SHAPE.test(cleaned) ? cleaned : null;
|
|
50
|
+
}
|
|
51
|
+
function fieldText(field, key) {
|
|
52
|
+
const value = field[key];
|
|
53
|
+
return typeof value === "string" ? value : "";
|
|
54
|
+
}
|
|
55
|
+
function extractUserDataFromFormFields(fields, country) {
|
|
56
|
+
const result = { email: null, phoneNumber: null };
|
|
57
|
+
if (!Array.isArray(fields)) return result;
|
|
58
|
+
const passes = [
|
|
59
|
+
(field, _hint, type) => fieldText(field, "type").toLowerCase() === type,
|
|
60
|
+
(field, hint) => hint.test(fieldText(field, "name")) || hint.test(fieldText(field, "label"))
|
|
61
|
+
];
|
|
62
|
+
for (const matches of passes) {
|
|
63
|
+
for (const raw of fields) {
|
|
64
|
+
if (raw === null || typeof raw !== "object") continue;
|
|
65
|
+
const field = raw;
|
|
66
|
+
if (typeof field.value !== "string" || field.value.length === 0) continue;
|
|
67
|
+
if (result.email === null && matches(field, EMAIL_NAME_HINT, "email")) {
|
|
68
|
+
result.email = normalizeEmail(field.value);
|
|
69
|
+
}
|
|
70
|
+
if (result.phoneNumber === null && matches(field, PHONE_NAME_HINT, "tel")) {
|
|
71
|
+
try {
|
|
72
|
+
result.phoneNumber = toE164(field.value, country);
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (result.email !== null && result.phoneNumber !== null) break;
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
function stashUserData(data, country) {
|
|
82
|
+
const email = normalizeEmail(data.email);
|
|
83
|
+
let phoneNumber = null;
|
|
84
|
+
if (typeof data.phone === "string" && data.phone.length > 0) {
|
|
85
|
+
try {
|
|
86
|
+
phoneNumber = toE164(data.phone, country);
|
|
87
|
+
} catch {
|
|
88
|
+
phoneNumber = null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
stash = {
|
|
92
|
+
email: email ?? stash.email,
|
|
93
|
+
phoneNumber: phoneNumber ?? stash.phoneNumber
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function stashUserDataFromFormFields(fields, country) {
|
|
97
|
+
try {
|
|
98
|
+
const extracted = extractUserDataFromFormFields(fields, country);
|
|
99
|
+
stash = {
|
|
100
|
+
email: extracted.email ?? stash.email,
|
|
101
|
+
phoneNumber: extracted.phoneNumber ?? stash.phoneNumber
|
|
102
|
+
};
|
|
103
|
+
} catch {
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function clearStashedUserData() {
|
|
107
|
+
stash = { email: null, phoneNumber: null };
|
|
108
|
+
}
|
|
109
|
+
function applyUserDataForConversion(explicit, country) {
|
|
110
|
+
if (typeof window === "undefined" || typeof window.gtag !== "function") return false;
|
|
111
|
+
let email = stash.email;
|
|
112
|
+
let phoneNumber = stash.phoneNumber;
|
|
113
|
+
if (explicit) {
|
|
114
|
+
const normalizedEmail = normalizeEmail(explicit.email);
|
|
115
|
+
if (normalizedEmail) email = normalizedEmail;
|
|
116
|
+
if (typeof explicit.phone === "string" && explicit.phone.length > 0) {
|
|
117
|
+
try {
|
|
118
|
+
phoneNumber = toE164(explicit.phone, country) ?? phoneNumber;
|
|
119
|
+
} catch {
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (email === null && phoneNumber === null) return false;
|
|
124
|
+
try {
|
|
125
|
+
window.gtag("set", "user_data", {
|
|
126
|
+
...email !== null ? { email } : {},
|
|
127
|
+
...phoneNumber !== null ? { phone_number: phoneNumber } : {}
|
|
128
|
+
});
|
|
129
|
+
return true;
|
|
130
|
+
} catch {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
1
135
|
// ../tracking-core/src/consent.ts
|
|
2
136
|
var CONSENT_STATE_KEY = "consent_state";
|
|
3
137
|
var CONSENT_TIMESTAMP_KEY = "consent_timestamp";
|
|
@@ -83,6 +217,13 @@ function setConsentState(state, options) {
|
|
|
83
217
|
} catch {
|
|
84
218
|
}
|
|
85
219
|
pushConsentToPlatforms(state);
|
|
220
|
+
if (state === "denied") {
|
|
221
|
+
clearStashedUserData();
|
|
222
|
+
try {
|
|
223
|
+
if (typeof window.gtag === "function") window.gtag("set", "user_data", null);
|
|
224
|
+
} catch {
|
|
225
|
+
}
|
|
226
|
+
}
|
|
86
227
|
notifyConsentChanged({ state, source: "explicit", updatedAt, expiresAt });
|
|
87
228
|
}
|
|
88
229
|
function optIn() {
|
|
@@ -121,6 +262,11 @@ var aranovaConsent = (function () {
|
|
|
121
262
|
var TRACKING_COOKIE_MAX_AGE_SECONDS = 7776e3;
|
|
122
263
|
var TRACKING_PARAM_KEYS = [
|
|
123
264
|
"gclid",
|
|
265
|
+
// Google's iOS/Safari replacement click IDs — issued when privacy features
|
|
266
|
+
// withhold gclid (wbraid: web-to-web, gbraid: app-to-web). First-class
|
|
267
|
+
// citizens: captured, persisted, and attributed exactly like gclid.
|
|
268
|
+
"wbraid",
|
|
269
|
+
"gbraid",
|
|
124
270
|
"fbclid",
|
|
125
271
|
"utm_source",
|
|
126
272
|
"utm_medium",
|
|
@@ -131,6 +277,8 @@ var TRACKING_PARAM_KEYS = [
|
|
|
131
277
|
function createEmptyTrackingParams() {
|
|
132
278
|
return {
|
|
133
279
|
gclid: null,
|
|
280
|
+
wbraid: null,
|
|
281
|
+
gbraid: null,
|
|
134
282
|
fbclid: null,
|
|
135
283
|
utm_source: null,
|
|
136
284
|
utm_medium: null,
|
|
@@ -433,6 +581,8 @@ function buildLandingPayloadFields(sessionId, override) {
|
|
|
433
581
|
if (params === null) return {};
|
|
434
582
|
return {
|
|
435
583
|
landing_gclid: params.gclid ?? null,
|
|
584
|
+
landing_wbraid: params.wbraid ?? null,
|
|
585
|
+
landing_gbraid: params.gbraid ?? null,
|
|
436
586
|
landing_fbclid: params.fbclid ?? null,
|
|
437
587
|
landing_utm_source: params.utm_source ?? null,
|
|
438
588
|
landing_utm_medium: params.utm_medium ?? null,
|
|
@@ -460,6 +610,8 @@ function createTrackingSessionUpsertPayload(trackingParams, input, context) {
|
|
|
460
610
|
session_id: input.sessionId,
|
|
461
611
|
visitor_id: input.visitorId ?? null,
|
|
462
612
|
gclid: trackingParams.gclid,
|
|
613
|
+
wbraid: trackingParams.wbraid,
|
|
614
|
+
gbraid: trackingParams.gbraid,
|
|
463
615
|
fbclid: trackingParams.fbclid,
|
|
464
616
|
fbc: getFbcCookie(),
|
|
465
617
|
fbp: getFbpCookie(),
|
|
@@ -481,6 +633,8 @@ function createTrackingEventCreatePayload(trackingParams, input, context) {
|
|
|
481
633
|
session_id: input.sessionId,
|
|
482
634
|
event_type: input.eventType,
|
|
483
635
|
gclid: trackingParams.gclid,
|
|
636
|
+
wbraid: trackingParams.wbraid,
|
|
637
|
+
gbraid: trackingParams.gbraid,
|
|
484
638
|
fbclid: trackingParams.fbclid,
|
|
485
639
|
fbc: getFbcCookie(),
|
|
486
640
|
fbp: getFbpCookie(),
|
|
@@ -510,14 +664,12 @@ function markFired(input) {
|
|
|
510
664
|
} catch {
|
|
511
665
|
}
|
|
512
666
|
}
|
|
513
|
-
function
|
|
667
|
+
function fireConversionWithConsent(input, options) {
|
|
668
|
+
if (getConsentState() === "denied") return;
|
|
514
669
|
if (alreadyFired(input)) return;
|
|
670
|
+
applyUserDataForConversion(options?.userData);
|
|
515
671
|
if (fireGtagConversion(input)) markFired(input);
|
|
516
672
|
}
|
|
517
|
-
function fireConversionWithConsent(input) {
|
|
518
|
-
if (getConsentState() === "denied") return;
|
|
519
|
-
fireOnce(input);
|
|
520
|
-
}
|
|
521
673
|
|
|
522
674
|
// ../tracking-core/src/resources/conversion-config.ts
|
|
523
675
|
function isStringMap(value) {
|
|
@@ -962,6 +1114,7 @@ var TrackingConfigRuntime = class {
|
|
|
962
1114
|
if (!firing || getConsentState() === "denied") continue;
|
|
963
1115
|
const currency = item.currency ?? firing.currency ?? null;
|
|
964
1116
|
const value = item.value ?? (firing.value_cents != null && currency ? fromMinor(firing.value_cents, currency) : null);
|
|
1117
|
+
applyUserDataForConversion();
|
|
965
1118
|
fireGtagConversion({
|
|
966
1119
|
sendTo: firing.send_to,
|
|
967
1120
|
value,
|
|
@@ -1455,6 +1608,8 @@ function createTrackingClient(config) {
|
|
|
1455
1608
|
session_id: sessionId,
|
|
1456
1609
|
visitor_id: visitorId,
|
|
1457
1610
|
gclid: params.gclid,
|
|
1611
|
+
wbraid: params.wbraid,
|
|
1612
|
+
gbraid: params.gbraid,
|
|
1458
1613
|
fbclid: params.fbclid,
|
|
1459
1614
|
fbc: getFbcCookie(),
|
|
1460
1615
|
fbp: getFbpCookie(),
|
|
@@ -1501,6 +1656,13 @@ function createTrackingClient(config) {
|
|
|
1501
1656
|
function trackEvent(input) {
|
|
1502
1657
|
if (destroyed) return;
|
|
1503
1658
|
if (!input || typeof input.eventType !== "string" || input.eventType.length === 0) return;
|
|
1659
|
+
if (input.eventType === "form_submit" && getConsentState() !== "denied") {
|
|
1660
|
+
try {
|
|
1661
|
+
const fields = input.metadata?.form?.fields;
|
|
1662
|
+
if (fields) stashUserDataFromFormFields(fields, config.phone?.defaultCountry);
|
|
1663
|
+
} catch {
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1504
1666
|
const occurredAt = input.occurredAt instanceof Date ? input.occurredAt.toISOString() : typeof input.occurredAt === "string" ? input.occurredAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
1505
1667
|
queue.push({
|
|
1506
1668
|
event_type: input.eventType,
|
|
@@ -2329,46 +2491,6 @@ function attachCtaClickCapture(client, config) {
|
|
|
2329
2491
|
};
|
|
2330
2492
|
}
|
|
2331
2493
|
|
|
2332
|
-
// ../tracking-core/src/phone.ts
|
|
2333
|
-
import { AsYouType, parsePhoneNumberFromString } from "libphonenumber-js";
|
|
2334
|
-
var DEFAULT_PHONE_COUNTRY = "CA";
|
|
2335
|
-
function parsePhone(raw, country) {
|
|
2336
|
-
const region = country ?? DEFAULT_PHONE_COUNTRY;
|
|
2337
|
-
const parsed = parsePhoneNumberFromString(raw ?? "", region);
|
|
2338
|
-
if (!parsed) {
|
|
2339
|
-
return { e164: null, national: "", international: "", country: region, isValid: false };
|
|
2340
|
-
}
|
|
2341
|
-
const isValid = parsed.isValid();
|
|
2342
|
-
return {
|
|
2343
|
-
// E.164 is only surfaced for a *valid* number — a possible-but-invalid input
|
|
2344
|
-
// (e.g. too few digits) still parses but must not be transmitted.
|
|
2345
|
-
e164: isValid ? parsed.number : null,
|
|
2346
|
-
national: parsed.formatNational(),
|
|
2347
|
-
international: parsed.formatInternational(),
|
|
2348
|
-
country: parsed.country ?? region,
|
|
2349
|
-
isValid
|
|
2350
|
-
};
|
|
2351
|
-
}
|
|
2352
|
-
function toE164(raw, country) {
|
|
2353
|
-
return parsePhone(raw, country).e164;
|
|
2354
|
-
}
|
|
2355
|
-
function formatPhone(value, format = "national", country) {
|
|
2356
|
-
const parsed = parsePhone(value, country);
|
|
2357
|
-
if (typeof format === "function") return format(parsed);
|
|
2358
|
-
switch (format) {
|
|
2359
|
-
case "international":
|
|
2360
|
-
return parsed.international || value;
|
|
2361
|
-
case "e164":
|
|
2362
|
-
return parsed.e164 ?? value;
|
|
2363
|
-
case "national":
|
|
2364
|
-
default:
|
|
2365
|
-
return parsed.national || value;
|
|
2366
|
-
}
|
|
2367
|
-
}
|
|
2368
|
-
function formatPhoneAsTyped(raw, country) {
|
|
2369
|
-
return new AsYouType(country ?? DEFAULT_PHONE_COUNTRY).input(raw ?? "");
|
|
2370
|
-
}
|
|
2371
|
-
|
|
2372
2494
|
// ../tracking-core/src/triggers/phone-click-capture.ts
|
|
2373
2495
|
var DEFAULT_TEL_SELECTOR = 'a[href^="tel:"]';
|
|
2374
2496
|
function safeDecodeURIComponent(value) {
|
|
@@ -2478,6 +2600,8 @@ async function salesRequest(config, method, path, body) {
|
|
|
2478
2600
|
// ../tracking-core/src/resources/sales/client.ts
|
|
2479
2601
|
function fireRecordedConversions(firing, input, recorded, sale, currency) {
|
|
2480
2602
|
if (!firing) return;
|
|
2603
|
+
const userData = input.customer_email || input.customer_phone ? { email: input.customer_email ?? null, phone: input.customer_phone ?? null } : null;
|
|
2604
|
+
if (userData && getConsentState() !== "denied") stashUserData(userData);
|
|
2481
2605
|
const txnBase = input.external_id ?? sale.id;
|
|
2482
2606
|
for (const item of recorded) {
|
|
2483
2607
|
if (!item.service) continue;
|
|
@@ -2492,12 +2616,15 @@ function fireRecordedConversions(firing, input, recorded, sale, currency) {
|
|
|
2492
2616
|
const config = firing.getFiring(item.service);
|
|
2493
2617
|
if (!config) continue;
|
|
2494
2618
|
const cents = item.amount_cents ?? config.value_cents ?? null;
|
|
2495
|
-
fireConversionWithConsent(
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2619
|
+
fireConversionWithConsent(
|
|
2620
|
+
{
|
|
2621
|
+
sendTo: config.send_to,
|
|
2622
|
+
value: cents != null ? fromMinor(cents, currency) : null,
|
|
2623
|
+
currency: config.currency ?? currency,
|
|
2624
|
+
transactionId: `${txnBase}:${item.service}`
|
|
2625
|
+
},
|
|
2626
|
+
{ userData }
|
|
2627
|
+
);
|
|
2501
2628
|
}
|
|
2502
2629
|
}
|
|
2503
2630
|
function createSalesClient(config) {
|
|
@@ -2532,6 +2659,7 @@ function createSalesClient(config) {
|
|
|
2532
2659
|
recordSale: record,
|
|
2533
2660
|
trackConversion(key, options) {
|
|
2534
2661
|
if (config.firing && "fireConversion" in config.firing) {
|
|
2662
|
+
if (options?.userData && getConsentState() !== "denied") stashUserData(options.userData);
|
|
2535
2663
|
config.firing.fireConversion(key, {
|
|
2536
2664
|
value: options?.value ?? void 0,
|
|
2537
2665
|
currency: options?.currency ?? config.defaultCurrency ?? void 0,
|
|
@@ -2544,12 +2672,15 @@ function createSalesClient(config) {
|
|
|
2544
2672
|
const currency = firing.currency ?? options?.currency ?? config.defaultCurrency ?? null;
|
|
2545
2673
|
const cents = firing.value_cents ?? null;
|
|
2546
2674
|
const value = options?.value ?? (cents != null && currency ? fromMinor(cents, currency) : null);
|
|
2547
|
-
fireConversionWithConsent(
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2675
|
+
fireConversionWithConsent(
|
|
2676
|
+
{
|
|
2677
|
+
sendTo: firing.send_to,
|
|
2678
|
+
value,
|
|
2679
|
+
currency,
|
|
2680
|
+
transactionId: options?.transactionId ?? null
|
|
2681
|
+
},
|
|
2682
|
+
{ userData: options?.userData }
|
|
2683
|
+
);
|
|
2553
2684
|
},
|
|
2554
2685
|
async list(query) {
|
|
2555
2686
|
const { cursor, limit, sort, order, want_total, ...filters } = query ?? {};
|
|
@@ -3111,7 +3242,7 @@ function GoogleAdsTracking(props) {
|
|
|
3111
3242
|
import { usePathname, useSearchParams } from "next/navigation";
|
|
3112
3243
|
|
|
3113
3244
|
// package.json
|
|
3114
|
-
var version = "0.
|
|
3245
|
+
var version = "0.19.0";
|
|
3115
3246
|
|
|
3116
3247
|
// src/factory.tsx
|
|
3117
3248
|
import {
|
|
@@ -3457,6 +3588,7 @@ export {
|
|
|
3457
3588
|
TRACKING_PARAM_KEYS,
|
|
3458
3589
|
TRACKING_RANGES,
|
|
3459
3590
|
captureTrackingParamsFromLocation,
|
|
3591
|
+
clearStashedUserData,
|
|
3460
3592
|
createSalesClient,
|
|
3461
3593
|
createTracking,
|
|
3462
3594
|
createTrackingClientContext,
|
|
@@ -3485,6 +3617,7 @@ export {
|
|
|
3485
3617
|
saleUpdateSchema,
|
|
3486
3618
|
salesRequest,
|
|
3487
3619
|
setConsentState,
|
|
3620
|
+
stashUserData,
|
|
3488
3621
|
toE164,
|
|
3489
3622
|
toMinor,
|
|
3490
3623
|
useConsent,
|