@aranova/tracking-next 0.11.0 → 0.12.1
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 +79 -71
- package/dist/index.d.mts +137 -722
- package/dist/index.d.ts +137 -722
- package/dist/index.js +408 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +385 -60
- package/dist/index.mjs.map +1 -1
- package/dist/middleware.js +101 -0
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +101 -0
- package/dist/middleware.mjs.map +1 -1
- package/dist/phone-utils-dd1tW7sb.d.mts +344 -0
- package/dist/phone-utils-dd1tW7sb.d.ts +344 -0
- package/dist/phone.d.mts +3 -0
- package/dist/phone.d.ts +3 -0
- package/dist/phone.js +416 -0
- package/dist/phone.js.map +1 -0
- package/dist/phone.mjs +384 -0
- package/dist/phone.mjs.map +1 -0
- package/dist/sales.d.mts +784 -0
- package/dist/sales.d.ts +784 -0
- package/dist/sales.js +400 -0
- package/dist/sales.js.map +1 -0
- package/dist/sales.mjs +359 -0
- package/dist/sales.mjs.map +1 -0
- package/dist/server.d.mts +3 -1
- package/dist/server.d.ts +3 -1
- package/dist/server.js +101 -0
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +101 -0
- package/dist/server.mjs.map +1 -1
- package/package.json +51 -10
- package/dist/types-BPJLgMsG.d.mts +0 -161
- package/dist/types-BPJLgMsG.d.ts +0 -161
package/dist/index.js
CHANGED
|
@@ -32,8 +32,13 @@ var src_exports = {};
|
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
AranovaApiError: () => AranovaApiError,
|
|
34
34
|
ConsentBanner: () => ConsentBanner,
|
|
35
|
+
DEFAULT_PHONE_COUNTRY: () => DEFAULT_PHONE_COUNTRY,
|
|
35
36
|
GoogleAdsTracking: () => GoogleAdsTracking,
|
|
37
|
+
NAMED_RANGES: () => NAMED_RANGES,
|
|
38
|
+
PhoneField: () => PhoneField,
|
|
39
|
+
SUPPORTED_CURRENCIES: () => SUPPORTED_CURRENCIES,
|
|
36
40
|
TRACKING_PARAM_KEYS: () => TRACKING_PARAM_KEYS,
|
|
41
|
+
TRACKING_RANGES: () => TRACKING_RANGES,
|
|
37
42
|
captureTrackingParamsFromLocation: () => captureTrackingParamsFromLocation,
|
|
38
43
|
createSalesClient: () => createSalesClient,
|
|
39
44
|
createTracking: () => createTracking,
|
|
@@ -41,15 +46,28 @@ __export(src_exports, {
|
|
|
41
46
|
createTrackingEventCreatePayload: () => createTrackingEventCreatePayload,
|
|
42
47
|
createTrackingSessionUpsertPayload: () => createTrackingSessionUpsertPayload,
|
|
43
48
|
fetchServices: () => fetchServices,
|
|
49
|
+
formatDateInTz: () => formatDateInTz,
|
|
44
50
|
formatMoney: () => formatMoney,
|
|
51
|
+
formatPhone: () => formatPhone,
|
|
52
|
+
formatPhoneAsTyped: () => formatPhoneAsTyped,
|
|
45
53
|
fromMinor: () => fromMinor,
|
|
46
54
|
getConsentState: () => getConsentState,
|
|
55
|
+
parsePhone: () => parsePhone,
|
|
56
|
+
phoneField: () => phoneField,
|
|
47
57
|
resetConsent: () => resetConsent,
|
|
58
|
+
saleCreateSchema: () => saleCreateSchema,
|
|
59
|
+
saleItemSchema: () => saleItemSchema,
|
|
60
|
+
saleServiceSchema: () => saleServiceSchema,
|
|
61
|
+
saleUpdateSchema: () => saleUpdateSchema,
|
|
62
|
+
salesRequest: () => salesRequest,
|
|
48
63
|
setConsentState: () => setConsentState,
|
|
64
|
+
toE164: () => toE164,
|
|
49
65
|
toMinor: () => toMinor,
|
|
50
66
|
useConsent: () => useConsent,
|
|
51
67
|
useConsentState: () => useConsentState,
|
|
52
68
|
useGclid: () => useGclid,
|
|
69
|
+
usePhoneConfig: () => usePhoneConfig,
|
|
70
|
+
usePhoneField: () => usePhoneField,
|
|
53
71
|
useTrackingParams: () => useTrackingParams
|
|
54
72
|
});
|
|
55
73
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -66,24 +84,20 @@ function buildConsentPayload(state) {
|
|
|
66
84
|
};
|
|
67
85
|
}
|
|
68
86
|
function getConsentState() {
|
|
69
|
-
if (typeof window === "undefined")
|
|
70
|
-
return "pending";
|
|
87
|
+
if (typeof window === "undefined") return "pending";
|
|
71
88
|
const storedState = window.localStorage.getItem(CONSENT_STATE_KEY);
|
|
72
|
-
if (storedState === "granted" || storedState === "denied")
|
|
73
|
-
return storedState;
|
|
89
|
+
if (storedState === "granted" || storedState === "denied") return storedState;
|
|
74
90
|
return "pending";
|
|
75
91
|
}
|
|
76
92
|
function setConsentState(state) {
|
|
77
|
-
if (typeof window === "undefined")
|
|
78
|
-
return;
|
|
93
|
+
if (typeof window === "undefined") return;
|
|
79
94
|
window.localStorage.setItem(CONSENT_STATE_KEY, state);
|
|
80
95
|
window.localStorage.setItem(CONSENT_TIMESTAMP_KEY, (/* @__PURE__ */ new Date()).toISOString());
|
|
81
96
|
if (typeof window.gtag === "function")
|
|
82
97
|
window.gtag("consent", "update", buildConsentPayload(state));
|
|
83
98
|
}
|
|
84
99
|
function resetConsent() {
|
|
85
|
-
if (typeof window === "undefined")
|
|
86
|
-
return;
|
|
100
|
+
if (typeof window === "undefined") return;
|
|
87
101
|
window.localStorage.removeItem(CONSENT_STATE_KEY);
|
|
88
102
|
window.localStorage.removeItem(CONSENT_TIMESTAMP_KEY);
|
|
89
103
|
}
|
|
@@ -224,18 +238,15 @@ function getTrackingQueryValues(searchParams) {
|
|
|
224
238
|
}, {});
|
|
225
239
|
}
|
|
226
240
|
function getCookieValueFromDocument(key) {
|
|
227
|
-
if (typeof document === "undefined")
|
|
228
|
-
return null;
|
|
241
|
+
if (typeof document === "undefined") return null;
|
|
229
242
|
const cookies = document.cookie ? document.cookie.split("; ") : [];
|
|
230
243
|
const match = cookies.find((cookie) => cookie.startsWith(`${key}=`));
|
|
231
|
-
if (!match)
|
|
232
|
-
return null;
|
|
244
|
+
if (!match) return null;
|
|
233
245
|
const [, rawValue = ""] = match.split("=");
|
|
234
246
|
return normalizeTrackingCookieValue(decodeURIComponent(rawValue));
|
|
235
247
|
}
|
|
236
248
|
function setTrackingCookie(key, value, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
|
|
237
|
-
if (typeof document === "undefined")
|
|
238
|
-
return;
|
|
249
|
+
if (typeof document === "undefined") return;
|
|
239
250
|
const encodedValue = encodeURIComponent(value);
|
|
240
251
|
document.cookie = `${key}=${encodedValue}; Max-Age=${maxAgeSeconds}; Path=/; SameSite=Lax`;
|
|
241
252
|
}
|
|
@@ -275,18 +286,15 @@ function writeLocalStorage(key, value) {
|
|
|
275
286
|
}
|
|
276
287
|
}
|
|
277
288
|
function getVisitorId() {
|
|
278
|
-
if (typeof window === "undefined")
|
|
279
|
-
return safeUuid();
|
|
289
|
+
if (typeof window === "undefined") return safeUuid();
|
|
280
290
|
const existing = readLocalStorage(VISITOR_STORAGE_KEY);
|
|
281
|
-
if (existing && existing.length > 0)
|
|
282
|
-
return existing;
|
|
291
|
+
if (existing && existing.length > 0) return existing;
|
|
283
292
|
const fresh = safeUuid();
|
|
284
293
|
writeLocalStorage(VISITOR_STORAGE_KEY, fresh);
|
|
285
294
|
return fresh;
|
|
286
295
|
}
|
|
287
296
|
function getOrRotateSessionId(now = Date.now()) {
|
|
288
|
-
if (typeof window === "undefined")
|
|
289
|
-
return { id: safeUuid(), isNew: true };
|
|
297
|
+
if (typeof window === "undefined") return { id: safeUuid(), isNew: true };
|
|
290
298
|
const raw = readLocalStorage(SESSION_STORAGE_KEY);
|
|
291
299
|
if (raw) {
|
|
292
300
|
try {
|
|
@@ -359,8 +367,7 @@ function setLastFiredUrl(url) {
|
|
|
359
367
|
writeSessionStorage(LAST_FIRED_URL_STORAGE_KEY, url);
|
|
360
368
|
}
|
|
361
369
|
function buildPageViewMetadata(referrerOverride) {
|
|
362
|
-
if (typeof window === "undefined" || typeof document === "undefined")
|
|
363
|
-
return null;
|
|
370
|
+
if (typeof window === "undefined" || typeof document === "undefined") return null;
|
|
364
371
|
return pageViewMetadataSchema.parse({
|
|
365
372
|
page: {
|
|
366
373
|
title: document.title || null,
|
|
@@ -373,8 +380,7 @@ function buildPageViewMetadata(referrerOverride) {
|
|
|
373
380
|
});
|
|
374
381
|
}
|
|
375
382
|
function fireManualPageView(client) {
|
|
376
|
-
if (typeof window === "undefined")
|
|
377
|
-
return;
|
|
383
|
+
if (typeof window === "undefined") return;
|
|
378
384
|
const currentHref = window.location.href;
|
|
379
385
|
const previousFiredUrl = getLastFiredUrl();
|
|
380
386
|
const internalReferrer = previousFiredUrl !== null && previousFiredUrl !== currentHref ? previousFiredUrl : null;
|
|
@@ -476,8 +482,7 @@ function buildContext(surface, sdkVersion, packageName, environment, activeGtagI
|
|
|
476
482
|
};
|
|
477
483
|
}
|
|
478
484
|
function readTrackingParams() {
|
|
479
|
-
if (typeof window === "undefined")
|
|
480
|
-
return createEmptyTrackingParams();
|
|
485
|
+
if (typeof window === "undefined") return createEmptyTrackingParams();
|
|
481
486
|
try {
|
|
482
487
|
captureTrackingParamsFromLocation();
|
|
483
488
|
} catch {
|
|
@@ -492,8 +497,7 @@ function consentSnapshot() {
|
|
|
492
497
|
}
|
|
493
498
|
}
|
|
494
499
|
async function postWithFetch(url, body, apiKey, identity, keepalive) {
|
|
495
|
-
if (typeof fetch !== "function")
|
|
496
|
-
return;
|
|
500
|
+
if (typeof fetch !== "function") return;
|
|
497
501
|
try {
|
|
498
502
|
await fetch(url, {
|
|
499
503
|
method: "POST",
|
|
@@ -553,8 +557,7 @@ function createTrackingClient(config) {
|
|
|
553
557
|
const visitorId = getVisitorId();
|
|
554
558
|
const initialSession = getOrRotateSessionId();
|
|
555
559
|
let sessionId = initialSession.id;
|
|
556
|
-
if (typeof window !== "undefined")
|
|
557
|
-
firstPage = window.location.href;
|
|
560
|
+
if (typeof window !== "undefined") firstPage = window.location.href;
|
|
558
561
|
function enqueueHeartbeat() {
|
|
559
562
|
const metadata = buildHeartbeatMetadata(
|
|
560
563
|
config.surface,
|
|
@@ -580,7 +583,13 @@ function createTrackingClient(config) {
|
|
|
580
583
|
}
|
|
581
584
|
sessionId = rotated.id;
|
|
582
585
|
const params = readTrackingParams();
|
|
583
|
-
const context = buildContext(
|
|
586
|
+
const context = buildContext(
|
|
587
|
+
config.surface,
|
|
588
|
+
sdkVersion,
|
|
589
|
+
packageName,
|
|
590
|
+
environment,
|
|
591
|
+
activeGtagIds
|
|
592
|
+
);
|
|
584
593
|
return {
|
|
585
594
|
session_id: sessionId,
|
|
586
595
|
visitor_id: visitorId,
|
|
@@ -597,8 +606,7 @@ function createTrackingClient(config) {
|
|
|
597
606
|
};
|
|
598
607
|
}
|
|
599
608
|
function scheduleFlush() {
|
|
600
|
-
if (flushTimer !== null || destroyed)
|
|
601
|
-
return;
|
|
609
|
+
if (flushTimer !== null || destroyed) return;
|
|
602
610
|
flushTimer = setTimeout(() => {
|
|
603
611
|
flushTimer = null;
|
|
604
612
|
void flush();
|
|
@@ -611,8 +619,7 @@ function createTrackingClient(config) {
|
|
|
611
619
|
}
|
|
612
620
|
}
|
|
613
621
|
async function flush() {
|
|
614
|
-
if (queue.length === 0)
|
|
615
|
-
return;
|
|
622
|
+
if (queue.length === 0) return;
|
|
616
623
|
const events = queue.slice(0, HARD_MAX_BATCH);
|
|
617
624
|
queue = queue.slice(events.length);
|
|
618
625
|
clearScheduledFlush();
|
|
@@ -624,10 +631,8 @@ function createTrackingClient(config) {
|
|
|
624
631
|
await postWithFetch(eventsUrl, serialized, config.apiKey, identityHeaders2, false);
|
|
625
632
|
}
|
|
626
633
|
function trackEvent(input) {
|
|
627
|
-
if (destroyed)
|
|
628
|
-
|
|
629
|
-
if (!input || typeof input.eventType !== "string" || input.eventType.length === 0)
|
|
630
|
-
return;
|
|
634
|
+
if (destroyed) return;
|
|
635
|
+
if (!input || typeof input.eventType !== "string" || input.eventType.length === 0) return;
|
|
631
636
|
const occurredAt = input.occurredAt instanceof Date ? input.occurredAt.toISOString() : typeof input.occurredAt === "string" ? input.occurredAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
632
637
|
queue.push({
|
|
633
638
|
event_type: input.eventType,
|
|
@@ -642,8 +647,7 @@ function createTrackingClient(config) {
|
|
|
642
647
|
}
|
|
643
648
|
}
|
|
644
649
|
function flushOnUnload() {
|
|
645
|
-
if (queue.length === 0)
|
|
646
|
-
return;
|
|
650
|
+
if (queue.length === 0) return;
|
|
647
651
|
const events = queue.slice(0, HARD_MAX_BATCH);
|
|
648
652
|
queue = queue.slice(events.length);
|
|
649
653
|
clearScheduledFlush();
|
|
@@ -1183,21 +1187,40 @@ function createSalesClient(config) {
|
|
|
1183
1187
|
return salesRequest(config, "POST", "/sales", body);
|
|
1184
1188
|
},
|
|
1185
1189
|
async list(query) {
|
|
1186
|
-
const { cursor, limit, ...filters } = query ?? {};
|
|
1190
|
+
const { cursor, limit, sort, order, want_total, ...filters } = query ?? {};
|
|
1187
1191
|
return salesRequest(config, "POST", "/sales/query", {
|
|
1188
1192
|
filters,
|
|
1189
1193
|
...limit !== void 0 ? { limit } : {},
|
|
1190
|
-
...cursor !== void 0 ? { cursor } : {}
|
|
1194
|
+
...cursor !== void 0 ? { cursor } : {},
|
|
1195
|
+
...sort !== void 0 ? { sort } : {},
|
|
1196
|
+
...order !== void 0 ? { order } : {},
|
|
1197
|
+
...want_total !== void 0 ? { want_total } : {}
|
|
1191
1198
|
});
|
|
1192
1199
|
},
|
|
1193
1200
|
async summary(query) {
|
|
1194
|
-
const {
|
|
1201
|
+
const {
|
|
1202
|
+
range,
|
|
1203
|
+
include_categories,
|
|
1204
|
+
include_deleted_services,
|
|
1205
|
+
top_n,
|
|
1206
|
+
since,
|
|
1207
|
+
until,
|
|
1208
|
+
timezone,
|
|
1209
|
+
granularity,
|
|
1210
|
+
compare_to,
|
|
1211
|
+
...filters
|
|
1212
|
+
} = query;
|
|
1195
1213
|
return salesRequest(config, "POST", "/sales/summary", {
|
|
1196
1214
|
filters,
|
|
1197
|
-
range,
|
|
1215
|
+
...range !== void 0 ? { range } : {},
|
|
1198
1216
|
...include_categories !== void 0 ? { include_categories } : {},
|
|
1199
1217
|
...include_deleted_services !== void 0 ? { include_deleted_services } : {},
|
|
1200
|
-
...top_n !== void 0 ? { top_n } : {}
|
|
1218
|
+
...top_n !== void 0 ? { top_n } : {},
|
|
1219
|
+
...since !== void 0 ? { since } : {},
|
|
1220
|
+
...until !== void 0 ? { until } : {},
|
|
1221
|
+
...timezone !== void 0 ? { timezone } : {},
|
|
1222
|
+
...granularity !== void 0 ? { granularity } : {},
|
|
1223
|
+
...compare_to !== void 0 ? { compare_to } : {}
|
|
1201
1224
|
});
|
|
1202
1225
|
},
|
|
1203
1226
|
async get(id) {
|
|
@@ -1208,15 +1231,53 @@ function createSalesClient(config) {
|
|
|
1208
1231
|
},
|
|
1209
1232
|
async delete(id) {
|
|
1210
1233
|
await salesRequest(config, "DELETE", `/sales/${id}`);
|
|
1234
|
+
},
|
|
1235
|
+
customers: {
|
|
1236
|
+
async list(query) {
|
|
1237
|
+
const { segment, sort, order, cursor, limit, want_total, ...filters } = query ?? {};
|
|
1238
|
+
return salesRequest(config, "POST", "/customers/query", {
|
|
1239
|
+
filters,
|
|
1240
|
+
...segment !== void 0 ? { segment } : {},
|
|
1241
|
+
...sort !== void 0 ? { sort } : {},
|
|
1242
|
+
...order !== void 0 ? { order } : {},
|
|
1243
|
+
...cursor !== void 0 ? { cursor } : {},
|
|
1244
|
+
...limit !== void 0 ? { limit } : {},
|
|
1245
|
+
...want_total !== void 0 ? { want_total } : {}
|
|
1246
|
+
});
|
|
1247
|
+
},
|
|
1248
|
+
async get(id, options) {
|
|
1249
|
+
const params = new URLSearchParams();
|
|
1250
|
+
if (options?.include_sales !== void 0)
|
|
1251
|
+
params.set("include_sales", String(options.include_sales));
|
|
1252
|
+
if (options?.limit !== void 0) params.set("limit", String(options.limit));
|
|
1253
|
+
if (options?.cursor != null) params.set("cursor", options.cursor);
|
|
1254
|
+
const qs = params.toString();
|
|
1255
|
+
return salesRequest(
|
|
1256
|
+
config,
|
|
1257
|
+
"GET",
|
|
1258
|
+
`/customers/${encodeURIComponent(id)}${qs ? `?${qs}` : ""}`
|
|
1259
|
+
);
|
|
1260
|
+
},
|
|
1261
|
+
async summary(query) {
|
|
1262
|
+
const { range, since, until, timezone, compare_to, ...filters } = query ?? {};
|
|
1263
|
+
return salesRequest(config, "POST", "/customers/summary", {
|
|
1264
|
+
filters,
|
|
1265
|
+
...range !== void 0 ? { range } : {},
|
|
1266
|
+
...since !== void 0 ? { since } : {},
|
|
1267
|
+
...until !== void 0 ? { until } : {},
|
|
1268
|
+
...timezone !== void 0 ? { timezone } : {},
|
|
1269
|
+
...compare_to !== void 0 ? { compare_to } : {}
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
},
|
|
1273
|
+
business: {
|
|
1274
|
+
async config() {
|
|
1275
|
+
return salesRequest(config, "GET", "/business/config");
|
|
1276
|
+
}
|
|
1211
1277
|
}
|
|
1212
1278
|
};
|
|
1213
1279
|
}
|
|
1214
1280
|
|
|
1215
|
-
// ../tracking-core/src/resources/services.ts
|
|
1216
|
-
async function fetchServices(config) {
|
|
1217
|
-
return salesRequest(config, "GET", "/services");
|
|
1218
|
-
}
|
|
1219
|
-
|
|
1220
1281
|
// ../tracking-core/src/resources/sales/money.ts
|
|
1221
1282
|
var MINOR_UNIT_EXPONENT = {
|
|
1222
1283
|
USD: 2,
|
|
@@ -1236,6 +1297,181 @@ function formatMoney(cents, currency, locale) {
|
|
|
1236
1297
|
fromMinor(cents, currency)
|
|
1237
1298
|
);
|
|
1238
1299
|
}
|
|
1300
|
+
function formatDateInTz(iso, timeZone, opts, locale) {
|
|
1301
|
+
const date = new Date(iso);
|
|
1302
|
+
if (Number.isNaN(date.getTime())) return iso;
|
|
1303
|
+
return new Intl.DateTimeFormat(locale, {
|
|
1304
|
+
year: "numeric",
|
|
1305
|
+
month: "short",
|
|
1306
|
+
day: "2-digit",
|
|
1307
|
+
hour: "2-digit",
|
|
1308
|
+
minute: "2-digit",
|
|
1309
|
+
...opts,
|
|
1310
|
+
timeZone
|
|
1311
|
+
}).format(date);
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// ../tracking-core/src/resources/sales/schema.ts
|
|
1315
|
+
var import_zod11 = require("zod");
|
|
1316
|
+
var SUPPORTED_CURRENCIES = ["USD", "CAD"];
|
|
1317
|
+
var TRACKING_ENVIRONMENTS = ["production", "development"];
|
|
1318
|
+
var currencySchema = import_zod11.z.enum(SUPPORTED_CURRENCIES);
|
|
1319
|
+
var centsSchema = import_zod11.z.number().int().nonnegative();
|
|
1320
|
+
var quantitySchema = import_zod11.z.string().regex(/^\d+(\.\d{1,3})?$/);
|
|
1321
|
+
var metadataSchema = import_zod11.z.record(import_zod11.z.unknown());
|
|
1322
|
+
var saleItemSchema = import_zod11.z.object({
|
|
1323
|
+
external_item_id: import_zod11.z.string().nullable().optional(),
|
|
1324
|
+
name: import_zod11.z.string().nullable().optional(),
|
|
1325
|
+
category: import_zod11.z.string().nullable().optional(),
|
|
1326
|
+
quantity: quantitySchema,
|
|
1327
|
+
unit_price_cents: centsSchema,
|
|
1328
|
+
// Non-negativity validated on the wire — same contract as the other cents
|
|
1329
|
+
// fields — and backstopped by the DB CHECK.
|
|
1330
|
+
unit_cost_cents: centsSchema.nullable().optional()
|
|
1331
|
+
}).strict();
|
|
1332
|
+
var saleServiceSchema = import_zod11.z.object({
|
|
1333
|
+
service: import_zod11.z.string(),
|
|
1334
|
+
amount_cents: centsSchema
|
|
1335
|
+
}).strict();
|
|
1336
|
+
var customerNameSchema = import_zod11.z.string().max(200);
|
|
1337
|
+
var customerPhoneSchema = import_zod11.z.string().max(64);
|
|
1338
|
+
var customerEmailSchema = import_zod11.z.string().max(320).email();
|
|
1339
|
+
function refineServiceXor(val, ctx, { requireAmount }) {
|
|
1340
|
+
if (val.services != null) {
|
|
1341
|
+
if (val.service != null) {
|
|
1342
|
+
ctx.addIssue({
|
|
1343
|
+
code: import_zod11.z.ZodIssueCode.custom,
|
|
1344
|
+
message: "pass either `service` or `services`, not both",
|
|
1345
|
+
path: ["services"]
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
if (val.services.length === 0) {
|
|
1349
|
+
ctx.addIssue({
|
|
1350
|
+
code: import_zod11.z.ZodIssueCode.custom,
|
|
1351
|
+
message: "`services` must not be empty",
|
|
1352
|
+
path: ["services"]
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
const keys = val.services.map((s) => s.service);
|
|
1356
|
+
if (new Set(keys).size !== keys.length) {
|
|
1357
|
+
ctx.addIssue({
|
|
1358
|
+
code: import_zod11.z.ZodIssueCode.custom,
|
|
1359
|
+
message: "`services` must not list the same service more than once",
|
|
1360
|
+
path: ["services"]
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
if (val.amount_total_cents != null) {
|
|
1364
|
+
const sum = val.services.reduce((acc, s) => acc + s.amount_cents, 0);
|
|
1365
|
+
if (val.amount_total_cents !== sum) {
|
|
1366
|
+
ctx.addIssue({
|
|
1367
|
+
code: import_zod11.z.ZodIssueCode.custom,
|
|
1368
|
+
message: "amount_total_cents must equal the sum of the services amounts (omit it to derive it automatically)",
|
|
1369
|
+
path: ["amount_total_cents"]
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
} else if (requireAmount && val.amount_total_cents == null) {
|
|
1374
|
+
ctx.addIssue({
|
|
1375
|
+
code: import_zod11.z.ZodIssueCode.custom,
|
|
1376
|
+
message: "amount_total_cents is required unless `services` is provided",
|
|
1377
|
+
path: ["amount_total_cents"]
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
var saleCreateSchema = import_zod11.z.object({
|
|
1382
|
+
external_id: import_zod11.z.string().nullable().optional(),
|
|
1383
|
+
description: import_zod11.z.string().nullable().optional(),
|
|
1384
|
+
service: import_zod11.z.string().nullable().optional(),
|
|
1385
|
+
services: import_zod11.z.array(saleServiceSchema).nullable().optional(),
|
|
1386
|
+
currency: currencySchema,
|
|
1387
|
+
// Optional only because the plural `services` form derives it from the sum
|
|
1388
|
+
// (see refineServiceXor); the singular/serviceless path still requires it.
|
|
1389
|
+
amount_total_cents: centsSchema.nullable().optional(),
|
|
1390
|
+
occurred_at: import_zod11.z.string().datetime(),
|
|
1391
|
+
environment: import_zod11.z.enum(TRACKING_ENVIRONMENTS).default("production"),
|
|
1392
|
+
items: import_zod11.z.array(saleItemSchema).default([]),
|
|
1393
|
+
metadata: metadataSchema.nullable().optional(),
|
|
1394
|
+
customer_name: customerNameSchema.nullable().optional(),
|
|
1395
|
+
customer_phone: customerPhoneSchema.nullable().optional(),
|
|
1396
|
+
customer_email: customerEmailSchema.nullable().optional()
|
|
1397
|
+
}).strict().superRefine((val, ctx) => refineServiceXor(val, ctx, { requireAmount: true }));
|
|
1398
|
+
var saleUpdateSchema = import_zod11.z.object({
|
|
1399
|
+
description: import_zod11.z.string().nullable().optional(),
|
|
1400
|
+
service: import_zod11.z.string().nullable().optional(),
|
|
1401
|
+
services: import_zod11.z.array(saleServiceSchema).nullable().optional(),
|
|
1402
|
+
currency: currencySchema.optional(),
|
|
1403
|
+
amount_total_cents: centsSchema.optional(),
|
|
1404
|
+
occurred_at: import_zod11.z.string().datetime().optional(),
|
|
1405
|
+
items: import_zod11.z.array(saleItemSchema).optional(),
|
|
1406
|
+
metadata: metadataSchema.nullable().optional(),
|
|
1407
|
+
customer_name: customerNameSchema.nullable().optional(),
|
|
1408
|
+
customer_phone: customerPhoneSchema.nullable().optional(),
|
|
1409
|
+
customer_email: customerEmailSchema.nullable().optional()
|
|
1410
|
+
}).strict().superRefine((val, ctx) => refineServiceXor(val, ctx, { requireAmount: false }));
|
|
1411
|
+
var TRACKING_RANGES = ["24h", "7d", "30d"];
|
|
1412
|
+
var NAMED_RANGES = [
|
|
1413
|
+
"today",
|
|
1414
|
+
"yesterday",
|
|
1415
|
+
"wtd",
|
|
1416
|
+
"mtd",
|
|
1417
|
+
"qtd",
|
|
1418
|
+
"ytd",
|
|
1419
|
+
"24h",
|
|
1420
|
+
"7d",
|
|
1421
|
+
"30d",
|
|
1422
|
+
"90d",
|
|
1423
|
+
"custom"
|
|
1424
|
+
];
|
|
1425
|
+
|
|
1426
|
+
// ../tracking-core/src/resources/services.ts
|
|
1427
|
+
async function fetchServices(config) {
|
|
1428
|
+
return salesRequest(config, "GET", "/services");
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
// ../tracking-core/src/phone.ts
|
|
1432
|
+
var import_libphonenumber_js = require("libphonenumber-js");
|
|
1433
|
+
var DEFAULT_PHONE_COUNTRY = "CA";
|
|
1434
|
+
function parsePhone(raw, country) {
|
|
1435
|
+
const region = country ?? DEFAULT_PHONE_COUNTRY;
|
|
1436
|
+
const parsed = (0, import_libphonenumber_js.parsePhoneNumberFromString)(raw ?? "", region);
|
|
1437
|
+
if (!parsed) {
|
|
1438
|
+
return { e164: null, national: "", international: "", country: region, isValid: false };
|
|
1439
|
+
}
|
|
1440
|
+
const isValid = parsed.isValid();
|
|
1441
|
+
return {
|
|
1442
|
+
// E.164 is only surfaced for a *valid* number — a possible-but-invalid input
|
|
1443
|
+
// (e.g. too few digits) still parses but must not be transmitted.
|
|
1444
|
+
e164: isValid ? parsed.number : null,
|
|
1445
|
+
national: parsed.formatNational(),
|
|
1446
|
+
international: parsed.formatInternational(),
|
|
1447
|
+
country: parsed.country ?? region,
|
|
1448
|
+
isValid
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1451
|
+
function toE164(raw, country) {
|
|
1452
|
+
return parsePhone(raw, country).e164;
|
|
1453
|
+
}
|
|
1454
|
+
function formatPhone(value, format = "national", country) {
|
|
1455
|
+
const parsed = parsePhone(value, country);
|
|
1456
|
+
if (typeof format === "function") return format(parsed);
|
|
1457
|
+
switch (format) {
|
|
1458
|
+
case "international":
|
|
1459
|
+
return parsed.international || value;
|
|
1460
|
+
case "e164":
|
|
1461
|
+
return parsed.e164 ?? value;
|
|
1462
|
+
case "national":
|
|
1463
|
+
default:
|
|
1464
|
+
return parsed.national || value;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
function formatPhoneAsTyped(raw, country) {
|
|
1468
|
+
return new import_libphonenumber_js.AsYouType(country ?? DEFAULT_PHONE_COUNTRY).input(raw ?? "");
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
// ../tracking-core/src/phone-field.ts
|
|
1472
|
+
function phoneField(name, raw, country) {
|
|
1473
|
+
return { name, type: "phone", value: toE164(raw, country) };
|
|
1474
|
+
}
|
|
1239
1475
|
|
|
1240
1476
|
// src/ConsentBanner.tsx
|
|
1241
1477
|
var import_react2 = require("react");
|
|
@@ -1504,13 +1740,101 @@ function GoogleAdsTracking(props) {
|
|
|
1504
1740
|
var import_navigation = require("next/navigation");
|
|
1505
1741
|
|
|
1506
1742
|
// package.json
|
|
1507
|
-
var version = "0.
|
|
1743
|
+
var version = "0.12.1";
|
|
1508
1744
|
|
|
1509
1745
|
// src/factory.tsx
|
|
1746
|
+
var import_react4 = require("react");
|
|
1747
|
+
|
|
1748
|
+
// ../tracking-core/src/phone-react.tsx
|
|
1510
1749
|
var import_react3 = require("react");
|
|
1511
1750
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1751
|
+
var _phoneConfigContext;
|
|
1752
|
+
function phoneConfigContext() {
|
|
1753
|
+
return _phoneConfigContext ?? (_phoneConfigContext = (0, import_react3.createContext)(null));
|
|
1754
|
+
}
|
|
1755
|
+
function PhoneConfigProvider({
|
|
1756
|
+
value,
|
|
1757
|
+
children
|
|
1758
|
+
}) {
|
|
1759
|
+
const Ctx = phoneConfigContext();
|
|
1760
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Ctx.Provider, { value, children });
|
|
1761
|
+
}
|
|
1762
|
+
function usePhoneConfig() {
|
|
1763
|
+
const ctx = (0, import_react3.useContext)(phoneConfigContext());
|
|
1764
|
+
return {
|
|
1765
|
+
defaultCountry: ctx?.defaultCountry ?? DEFAULT_PHONE_COUNTRY,
|
|
1766
|
+
display: ctx?.display ?? "national"
|
|
1767
|
+
};
|
|
1768
|
+
}
|
|
1769
|
+
function usePhoneField(opts = {}) {
|
|
1770
|
+
const cfg = usePhoneConfig();
|
|
1771
|
+
const country = opts.country ?? cfg.defaultCountry;
|
|
1772
|
+
const display = opts.display ?? cfg.display;
|
|
1773
|
+
const { onValueChange } = opts;
|
|
1774
|
+
const [value, setValue] = (0, import_react3.useState)(() => formatPhoneAsTyped(opts.defaultValue ?? "", country));
|
|
1775
|
+
const [touched, setTouched] = (0, import_react3.useState)(false);
|
|
1776
|
+
const parsed = (0, import_react3.useMemo)(() => parsePhone(value, country), [value, country]);
|
|
1777
|
+
const onChange = (0, import_react3.useCallback)(
|
|
1778
|
+
(event) => {
|
|
1779
|
+
const next = formatPhoneAsTyped(event.target.value, country);
|
|
1780
|
+
setValue(next);
|
|
1781
|
+
onValueChange?.(parsePhone(next, country).e164);
|
|
1782
|
+
},
|
|
1783
|
+
[country, onValueChange]
|
|
1784
|
+
);
|
|
1785
|
+
const onBlur = (0, import_react3.useCallback)(
|
|
1786
|
+
(_event) => {
|
|
1787
|
+
setTouched(true);
|
|
1788
|
+
setValue((current) => {
|
|
1789
|
+
const p = parsePhone(current, country);
|
|
1790
|
+
return p.isValid ? formatPhone(current, display, country) : current;
|
|
1791
|
+
});
|
|
1792
|
+
},
|
|
1793
|
+
[country, display]
|
|
1794
|
+
);
|
|
1795
|
+
const error = touched && value.length > 0 && !parsed.isValid ? "Enter a valid phone number" : null;
|
|
1796
|
+
return {
|
|
1797
|
+
value,
|
|
1798
|
+
e164: parsed.e164,
|
|
1799
|
+
isValid: parsed.isValid,
|
|
1800
|
+
error,
|
|
1801
|
+
parsed,
|
|
1802
|
+
inputProps: { value, onChange, onBlur, type: "tel", inputMode: "tel", autoComplete: "tel" }
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
var PhoneField = (0, import_react3.forwardRef)(function PhoneField2({ country, value, defaultValue, onChange, onE164Change, ...rest }, ref) {
|
|
1806
|
+
const cfg = usePhoneConfig();
|
|
1807
|
+
const resolvedCountry = country ?? cfg.defaultCountry;
|
|
1808
|
+
const isControlled = value !== void 0;
|
|
1809
|
+
const [internal, setInternal] = (0, import_react3.useState)(
|
|
1810
|
+
() => formatPhoneAsTyped(defaultValue ?? "", resolvedCountry)
|
|
1811
|
+
);
|
|
1812
|
+
const handleChange = (event) => {
|
|
1813
|
+
const formatted = formatPhoneAsTyped(event.target.value, resolvedCountry);
|
|
1814
|
+
event.target.value = formatted;
|
|
1815
|
+
onE164Change?.(parsePhone(formatted, resolvedCountry).e164);
|
|
1816
|
+
if (!isControlled) setInternal(formatted);
|
|
1817
|
+
onChange?.(event);
|
|
1818
|
+
};
|
|
1819
|
+
const shown = isControlled ? formatPhoneAsTyped(value, resolvedCountry) : internal;
|
|
1820
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1821
|
+
"input",
|
|
1822
|
+
{
|
|
1823
|
+
...rest,
|
|
1824
|
+
ref,
|
|
1825
|
+
type: "tel",
|
|
1826
|
+
inputMode: "tel",
|
|
1827
|
+
autoComplete: "tel",
|
|
1828
|
+
value: shown,
|
|
1829
|
+
onChange: handleChange
|
|
1830
|
+
}
|
|
1831
|
+
);
|
|
1832
|
+
});
|
|
1833
|
+
|
|
1834
|
+
// src/factory.tsx
|
|
1835
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1512
1836
|
function createTracking(options) {
|
|
1513
|
-
const { apiKey, endpoint, triggers, environment, gtagIds, debug } = options;
|
|
1837
|
+
const { apiKey, endpoint, triggers, environment, gtagIds, debug, phone } = options;
|
|
1514
1838
|
if (!apiKey || !endpoint) {
|
|
1515
1839
|
if (apiKey || endpoint) {
|
|
1516
1840
|
console.warn(
|
|
@@ -1526,17 +1850,17 @@ function createTracking(options) {
|
|
|
1526
1850
|
getVisitorId: () => ""
|
|
1527
1851
|
};
|
|
1528
1852
|
return {
|
|
1529
|
-
TrackingProvider: ({ children }) => children,
|
|
1853
|
+
TrackingProvider: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PhoneConfigProvider, { value: phone ?? null, children }),
|
|
1530
1854
|
useTracking: () => noopClient
|
|
1531
1855
|
};
|
|
1532
1856
|
}
|
|
1533
|
-
const TrackingContext = (0,
|
|
1857
|
+
const TrackingContext = (0, import_react4.createContext)(null);
|
|
1534
1858
|
const specificPageVisitConfig = triggers.automatic.specific_page_visit ?? null;
|
|
1535
1859
|
const timeOnSiteConfig = triggers.automatic.time_on_site ?? null;
|
|
1536
1860
|
function TrackingProvider({ children }) {
|
|
1537
1861
|
const pathname = (0, import_navigation.usePathname)();
|
|
1538
1862
|
const searchParams = (0, import_navigation.useSearchParams)();
|
|
1539
|
-
const client = (0,
|
|
1863
|
+
const client = (0, import_react4.useMemo)(
|
|
1540
1864
|
() => createTypedClient(
|
|
1541
1865
|
getOrCreateTrackingClient({
|
|
1542
1866
|
apiKey,
|
|
@@ -1554,7 +1878,7 @@ function createTracking(options) {
|
|
|
1554
1878
|
),
|
|
1555
1879
|
[]
|
|
1556
1880
|
);
|
|
1557
|
-
(0,
|
|
1881
|
+
(0, import_react4.useEffect)(() => {
|
|
1558
1882
|
const rawClient = getOrCreateTrackingClient({
|
|
1559
1883
|
apiKey,
|
|
1560
1884
|
endpoint,
|
|
@@ -1567,8 +1891,8 @@ function createTracking(options) {
|
|
|
1567
1891
|
});
|
|
1568
1892
|
fireManualPageView(rawClient);
|
|
1569
1893
|
}, [pathname, searchParams]);
|
|
1570
|
-
const firedPagesRef = (0,
|
|
1571
|
-
(0,
|
|
1894
|
+
const firedPagesRef = (0, import_react4.useRef)(/* @__PURE__ */ new Set());
|
|
1895
|
+
(0, import_react4.useEffect)(() => {
|
|
1572
1896
|
if (!specificPageVisitConfig || pathname === null) return;
|
|
1573
1897
|
const rawClient = getOrCreateTrackingClient({
|
|
1574
1898
|
apiKey,
|
|
@@ -1593,7 +1917,7 @@ function createTracking(options) {
|
|
|
1593
1917
|
});
|
|
1594
1918
|
}
|
|
1595
1919
|
}, [pathname]);
|
|
1596
|
-
(0,
|
|
1920
|
+
(0, import_react4.useEffect)(() => {
|
|
1597
1921
|
const rawClient = getOrCreateTrackingClient({
|
|
1598
1922
|
apiKey,
|
|
1599
1923
|
endpoint,
|
|
@@ -1606,7 +1930,7 @@ function createTracking(options) {
|
|
|
1606
1930
|
});
|
|
1607
1931
|
return attachBfcacheRestore(rawClient);
|
|
1608
1932
|
}, []);
|
|
1609
|
-
(0,
|
|
1933
|
+
(0, import_react4.useEffect)(() => {
|
|
1610
1934
|
if (!timeOnSiteConfig) return;
|
|
1611
1935
|
const rawClient = getOrCreateTrackingClient({
|
|
1612
1936
|
apiKey,
|
|
@@ -1621,8 +1945,8 @@ function createTracking(options) {
|
|
|
1621
1945
|
return attachTimeOnSite(rawClient, timeOnSiteConfig);
|
|
1622
1946
|
}, []);
|
|
1623
1947
|
const multiPageSessionConfig = triggers.automatic.multi_page_session ?? null;
|
|
1624
|
-
const mpsLastPathRef = (0,
|
|
1625
|
-
(0,
|
|
1948
|
+
const mpsLastPathRef = (0, import_react4.useRef)(null);
|
|
1949
|
+
(0, import_react4.useEffect)(() => {
|
|
1626
1950
|
if (!multiPageSessionConfig || pathname === null) return;
|
|
1627
1951
|
if (pathname === mpsLastPathRef.current) return;
|
|
1628
1952
|
mpsLastPathRef.current = pathname;
|
|
@@ -1669,7 +1993,7 @@ function createTracking(options) {
|
|
|
1669
1993
|
} catch {
|
|
1670
1994
|
}
|
|
1671
1995
|
}, [pathname]);
|
|
1672
|
-
(0,
|
|
1996
|
+
(0, import_react4.useEffect)(() => {
|
|
1673
1997
|
const detachers = [];
|
|
1674
1998
|
const rawClient = getOrCreateTrackingClient({
|
|
1675
1999
|
apiKey,
|
|
@@ -1695,10 +2019,10 @@ function createTracking(options) {
|
|
|
1695
2019
|
}
|
|
1696
2020
|
};
|
|
1697
2021
|
}, []);
|
|
1698
|
-
return /* @__PURE__ */ (0,
|
|
2022
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TrackingContext.Provider, { value: client, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PhoneConfigProvider, { value: phone ?? null, children }) });
|
|
1699
2023
|
}
|
|
1700
2024
|
function useTracking() {
|
|
1701
|
-
const client = (0,
|
|
2025
|
+
const client = (0, import_react4.useContext)(TrackingContext);
|
|
1702
2026
|
if (client === null) {
|
|
1703
2027
|
throw new Error(
|
|
1704
2028
|
"useTracking must be called inside a <TrackingProvider> returned by createTracking()"
|
|
@@ -1712,8 +2036,13 @@ function createTracking(options) {
|
|
|
1712
2036
|
0 && (module.exports = {
|
|
1713
2037
|
AranovaApiError,
|
|
1714
2038
|
ConsentBanner,
|
|
2039
|
+
DEFAULT_PHONE_COUNTRY,
|
|
1715
2040
|
GoogleAdsTracking,
|
|
2041
|
+
NAMED_RANGES,
|
|
2042
|
+
PhoneField,
|
|
2043
|
+
SUPPORTED_CURRENCIES,
|
|
1716
2044
|
TRACKING_PARAM_KEYS,
|
|
2045
|
+
TRACKING_RANGES,
|
|
1717
2046
|
captureTrackingParamsFromLocation,
|
|
1718
2047
|
createSalesClient,
|
|
1719
2048
|
createTracking,
|
|
@@ -1721,15 +2050,28 @@ function createTracking(options) {
|
|
|
1721
2050
|
createTrackingEventCreatePayload,
|
|
1722
2051
|
createTrackingSessionUpsertPayload,
|
|
1723
2052
|
fetchServices,
|
|
2053
|
+
formatDateInTz,
|
|
1724
2054
|
formatMoney,
|
|
2055
|
+
formatPhone,
|
|
2056
|
+
formatPhoneAsTyped,
|
|
1725
2057
|
fromMinor,
|
|
1726
2058
|
getConsentState,
|
|
2059
|
+
parsePhone,
|
|
2060
|
+
phoneField,
|
|
1727
2061
|
resetConsent,
|
|
2062
|
+
saleCreateSchema,
|
|
2063
|
+
saleItemSchema,
|
|
2064
|
+
saleServiceSchema,
|
|
2065
|
+
saleUpdateSchema,
|
|
2066
|
+
salesRequest,
|
|
1728
2067
|
setConsentState,
|
|
2068
|
+
toE164,
|
|
1729
2069
|
toMinor,
|
|
1730
2070
|
useConsent,
|
|
1731
2071
|
useConsentState,
|
|
1732
2072
|
useGclid,
|
|
2073
|
+
usePhoneConfig,
|
|
2074
|
+
usePhoneField,
|
|
1733
2075
|
useTrackingParams
|
|
1734
2076
|
});
|
|
1735
2077
|
//# sourceMappingURL=index.js.map
|