@aranova/tracking-react 1.14.0 → 1.15.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/{bookings-Bw2ImtPd.d.ts → bookings-CkfA5XOM.d.ts} +283 -8
- package/dist/{bookings-CDGNZUaH.d.mts → bookings-DFz3BUiP.d.mts} +283 -8
- package/dist/client.d.mts +10 -9
- package/dist/client.d.ts +10 -9
- package/dist/client.js +157 -141
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +157 -141
- package/dist/client.mjs.map +1 -1
- package/dist/index.d.mts +5 -6
- package/dist/index.d.ts +5 -6
- package/dist/index.js +365 -203
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +365 -203
- package/dist/index.mjs.map +1 -1
- package/dist/{submit-DuvP5AGN.d.ts → ingest-typed-BO6Arbw-.d.mts} +2 -252
- package/dist/{submit-rqgXl-Wg.d.mts → ingest-typed-D7I4aQ7p.d.ts} +2 -252
- package/dist/{phone-utils-Cfdx474X.d.mts → phone-utils-CYr6AmEP.d.mts} +55 -2
- package/dist/{phone-utils-D2TGPCQW.d.ts → phone-utils-CYr6AmEP.d.ts} +55 -2
- package/dist/phone.d.mts +1 -2
- package/dist/phone.d.ts +1 -2
- package/dist/{sales-DkdrGIUS.d.ts → sales-C0FMkN4m.d.ts} +1 -1
- package/dist/{sales-D4aU73mR.d.mts → sales-KbTcowYa.d.mts} +1 -1
- package/dist/sales.d.mts +3 -3
- package/dist/sales.d.ts +3 -3
- package/dist/sales.js +1205 -170
- package/dist/sales.js.map +1 -1
- package/dist/sales.mjs +1205 -170
- package/dist/sales.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/form-submit-C_vJXCxh.d.mts +0 -57
- package/dist/form-submit-C_vJXCxh.d.ts +0 -57
package/dist/sales.mjs
CHANGED
|
@@ -89,6 +89,14 @@ var DEFAULT_CHOICE = {
|
|
|
89
89
|
updatedAt: null,
|
|
90
90
|
expiresAt: null
|
|
91
91
|
};
|
|
92
|
+
function buildConsentPayload(state) {
|
|
93
|
+
return {
|
|
94
|
+
ad_storage: state,
|
|
95
|
+
ad_user_data: state,
|
|
96
|
+
ad_personalization: state,
|
|
97
|
+
analytics_storage: state
|
|
98
|
+
};
|
|
99
|
+
}
|
|
92
100
|
function getConsentChoice() {
|
|
93
101
|
if (typeof window === "undefined") return DEFAULT_CHOICE;
|
|
94
102
|
try {
|
|
@@ -117,6 +125,24 @@ function getConsentState() {
|
|
|
117
125
|
}
|
|
118
126
|
|
|
119
127
|
// ../tracking-core/src/gtag.ts
|
|
128
|
+
var GTAG_SCRIPT_HOST = "https://www.googletagmanager.com/gtag/js";
|
|
129
|
+
var TRACKING_SCRIPT_ATTRIBUTE = "data-aranova-tracking";
|
|
130
|
+
function getScriptMarker(id) {
|
|
131
|
+
return `aranova-${id}`;
|
|
132
|
+
}
|
|
133
|
+
var GTAG_ID_PATTERN = /^[A-Z]{1,3}-[A-Za-z0-9_-]+$/;
|
|
134
|
+
function isValidGtagId(id) {
|
|
135
|
+
return GTAG_ID_PATTERN.test(id);
|
|
136
|
+
}
|
|
137
|
+
function ensureGtagFunction() {
|
|
138
|
+
window.dataLayer = window.dataLayer || [];
|
|
139
|
+
if (typeof window.gtag === "function") return window.gtag;
|
|
140
|
+
function gtag() {
|
|
141
|
+
window.dataLayer?.push(arguments);
|
|
142
|
+
}
|
|
143
|
+
window.gtag = gtag;
|
|
144
|
+
return window.gtag;
|
|
145
|
+
}
|
|
120
146
|
var SEND_TO_RE = /^AW-[A-Za-z0-9]+\/[A-Za-z0-9_-]+$/;
|
|
121
147
|
function isValidSendTo(sendTo) {
|
|
122
148
|
return SEND_TO_RE.test(sendTo);
|
|
@@ -135,6 +161,27 @@ function fireGtagConversion(input) {
|
|
|
135
161
|
return false;
|
|
136
162
|
}
|
|
137
163
|
}
|
|
164
|
+
function applyDefaultConsentState() {
|
|
165
|
+
const gtag = ensureGtagFunction();
|
|
166
|
+
gtag(
|
|
167
|
+
"consent",
|
|
168
|
+
"default",
|
|
169
|
+
buildConsentPayload(getConsentState() === "denied" ? "denied" : "granted")
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
function loadGtagScript(gtagId) {
|
|
173
|
+
if (typeof document === "undefined") return;
|
|
174
|
+
const marker = getScriptMarker("gtag-loader");
|
|
175
|
+
const existingScript = document.querySelector(
|
|
176
|
+
`script[${TRACKING_SCRIPT_ATTRIBUTE}="${marker}"]`
|
|
177
|
+
);
|
|
178
|
+
if (existingScript) return;
|
|
179
|
+
const script = document.createElement("script");
|
|
180
|
+
script.async = true;
|
|
181
|
+
script.src = `${GTAG_SCRIPT_HOST}?id=${encodeURIComponent(gtagId)}`;
|
|
182
|
+
script.setAttribute(TRACKING_SCRIPT_ATTRIBUTE, marker);
|
|
183
|
+
document.head.append(script);
|
|
184
|
+
}
|
|
138
185
|
|
|
139
186
|
// ../tracking-core/src/resources/conversion-firing.ts
|
|
140
187
|
var DEDUP_PREFIX = "_aranova_conv_";
|
|
@@ -170,6 +217,77 @@ function fireConversionWithConsent(input, options) {
|
|
|
170
217
|
}
|
|
171
218
|
}
|
|
172
219
|
|
|
220
|
+
// ../tracking-core/src/events/form-submit.ts
|
|
221
|
+
import * as z from "zod/mini";
|
|
222
|
+
var jsonValueSchema = z.lazy(
|
|
223
|
+
() => z.union([
|
|
224
|
+
z.string(),
|
|
225
|
+
z.number(),
|
|
226
|
+
z.boolean(),
|
|
227
|
+
z.null(),
|
|
228
|
+
z.array(jsonValueSchema),
|
|
229
|
+
z.record(z.string(), jsonValueSchema)
|
|
230
|
+
])
|
|
231
|
+
).register(z.globalRegistry, { id: "JsonSerializableValue" });
|
|
232
|
+
var contractNameSchema = z.string().check(z.regex(/^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?$/));
|
|
233
|
+
var contractName = contractNameSchema;
|
|
234
|
+
var violationRole = z.string().check(
|
|
235
|
+
z.maxLength(200),
|
|
236
|
+
z.regex(
|
|
237
|
+
/^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?(\|[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?)*$/
|
|
238
|
+
)
|
|
239
|
+
);
|
|
240
|
+
var MAX_CONTRACT_VIOLATIONS = 50;
|
|
241
|
+
var contractViolationSchema = z.strictObject({
|
|
242
|
+
role: z.nullable(violationRole),
|
|
243
|
+
rule: z.string().check(z.regex(/^[a-z][a-z_]{0,47}$/))
|
|
244
|
+
});
|
|
245
|
+
var formSubmitMetadataSchema = z.strictObject({
|
|
246
|
+
form: z.strictObject({
|
|
247
|
+
id: z.string(),
|
|
248
|
+
action: z.nullable(z.string()),
|
|
249
|
+
fields: z.optional(
|
|
250
|
+
z.array(
|
|
251
|
+
z.strictObject({
|
|
252
|
+
name: z.string(),
|
|
253
|
+
type: z.string(),
|
|
254
|
+
label: z.nullable(z.string()),
|
|
255
|
+
value: jsonValueSchema,
|
|
256
|
+
role: z.optional(z.nullable(contractName))
|
|
257
|
+
})
|
|
258
|
+
)
|
|
259
|
+
),
|
|
260
|
+
kind: z.optional(z.nullable(contractName)),
|
|
261
|
+
contract_version: z.optional(z.nullable(z.int().check(z.gte(1)))),
|
|
262
|
+
contract_hash: z.optional(z.nullable(z.string().check(z.maxLength(64)))),
|
|
263
|
+
extra: z.optional(
|
|
264
|
+
z.nullable(
|
|
265
|
+
z.array(
|
|
266
|
+
z.strictObject({
|
|
267
|
+
key: z.string().check(z.maxLength(64)),
|
|
268
|
+
label: z.string().check(z.maxLength(200)),
|
|
269
|
+
value: jsonValueSchema
|
|
270
|
+
})
|
|
271
|
+
).check(z.maxLength(20))
|
|
272
|
+
)
|
|
273
|
+
),
|
|
274
|
+
contract_violations: z.optional(
|
|
275
|
+
z.nullable(z.array(contractViolationSchema).check(z.maxLength(MAX_CONTRACT_VIOLATIONS)))
|
|
276
|
+
)
|
|
277
|
+
}),
|
|
278
|
+
page: z.strictObject({
|
|
279
|
+
path: z.string()
|
|
280
|
+
})
|
|
281
|
+
});
|
|
282
|
+
var formSubmitConfigSchema = z.strictObject({});
|
|
283
|
+
|
|
284
|
+
// ../tracking-core/src/ingest-typed.ts
|
|
285
|
+
import { parse, safeParse } from "zod/mini";
|
|
286
|
+
var clientSettings = /* @__PURE__ */ new WeakMap();
|
|
287
|
+
function typedClientSettings(client) {
|
|
288
|
+
return clientSettings.get(client) ?? {};
|
|
289
|
+
}
|
|
290
|
+
|
|
173
291
|
// ../../contracts/autoleap-booking-links.json
|
|
174
292
|
var autoleap_booking_links_default = {
|
|
175
293
|
hosts: ["myalp.io"]
|
|
@@ -242,8 +360,108 @@ function nationalDigits(phone) {
|
|
|
242
360
|
}
|
|
243
361
|
|
|
244
362
|
// ../tracking-core/src/lead-forms/lead-forms.gen.ts
|
|
245
|
-
import * as
|
|
363
|
+
import * as z2 from "zod/mini";
|
|
246
364
|
var LEAD_FORM_REGISTRY_VERSION = 2;
|
|
365
|
+
var LEAD_FORM_ROLES = [
|
|
366
|
+
"given_name",
|
|
367
|
+
"family_name",
|
|
368
|
+
"phone",
|
|
369
|
+
"email",
|
|
370
|
+
"service",
|
|
371
|
+
"preferred_date",
|
|
372
|
+
"preferred_time",
|
|
373
|
+
"note",
|
|
374
|
+
"visit",
|
|
375
|
+
"intent",
|
|
376
|
+
"vehicle",
|
|
377
|
+
"drop_off",
|
|
378
|
+
"address",
|
|
379
|
+
"patient_type",
|
|
380
|
+
"matter",
|
|
381
|
+
"language",
|
|
382
|
+
"products",
|
|
383
|
+
"goal",
|
|
384
|
+
"business_type",
|
|
385
|
+
"lead_volume",
|
|
386
|
+
"attribution"
|
|
387
|
+
];
|
|
388
|
+
var leadFormPrimitiveSchemas = /* @__PURE__ */ (() => ({
|
|
389
|
+
string: z2.string().check(z2.maxLength(120)),
|
|
390
|
+
text: z2.string().check(z2.maxLength(2e3)),
|
|
391
|
+
enum: z2.string().check(z2.regex(/^[a-z0-9-]{1,48}$/)),
|
|
392
|
+
multi_enum: z2.array(z2.string().check(z2.regex(/^[a-z0-9-]{1,48}$/))).check(z2.maxLength(10)),
|
|
393
|
+
bool: z2.boolean(),
|
|
394
|
+
date: z2.string().check(z2.regex(/^\d{4}-\d{2}-\d{2}$/)),
|
|
395
|
+
time_window: z2.strictObject({
|
|
396
|
+
start: z2.string().check(z2.regex(/^([01]\d|2[0-3]):[0-5]\d$/)),
|
|
397
|
+
end: z2.nullable(z2.string().check(z2.regex(/^([01]\d|2[0-3]):[0-5]\d$/))),
|
|
398
|
+
label: z2.optional(z2.string().check(z2.maxLength(60)))
|
|
399
|
+
}),
|
|
400
|
+
phone: z2.string().check(z2.regex(/^\+[1-9]\d{6,14}$/)),
|
|
401
|
+
email: z2.string().check(z2.maxLength(320), z2.regex(/^[^\s@]+@[^\s@]+$/)),
|
|
402
|
+
address: z2.strictObject({
|
|
403
|
+
line1: z2.string().check(z2.maxLength(120)),
|
|
404
|
+
line2: z2.optional(z2.string().check(z2.maxLength(120))),
|
|
405
|
+
city: z2.optional(z2.string().check(z2.maxLength(120))),
|
|
406
|
+
region: z2.optional(z2.string().check(z2.maxLength(120))),
|
|
407
|
+
postal_code: z2.optional(z2.string().check(z2.maxLength(120))),
|
|
408
|
+
country: z2.optional(z2.string().check(z2.maxLength(120)))
|
|
409
|
+
}),
|
|
410
|
+
number: z2.number()
|
|
411
|
+
}))();
|
|
412
|
+
var LEAD_FORM_ROLE_SPECS = {
|
|
413
|
+
given_name: { primitive: "string", smsLabel: "", contactIdentity: true },
|
|
414
|
+
family_name: { primitive: "string", smsLabel: "", contactIdentity: true },
|
|
415
|
+
phone: { primitive: "phone", smsLabel: "", contactIdentity: true },
|
|
416
|
+
email: { primitive: "email", smsLabel: "", contactIdentity: true },
|
|
417
|
+
service: { primitive: "multi_enum", smsLabel: "Service" },
|
|
418
|
+
preferred_date: { primitive: "date", smsLabel: "Date" },
|
|
419
|
+
preferred_time: { primitive: "time_window", smsLabel: "Time" },
|
|
420
|
+
note: { primitive: "text", smsLabel: "Note" },
|
|
421
|
+
visit: {
|
|
422
|
+
primitive: "enum",
|
|
423
|
+
smsLabel: "Visit",
|
|
424
|
+
options: [
|
|
425
|
+
{ key: "in-shop", label: "In shop" },
|
|
426
|
+
{ key: "in-home", label: "In home" },
|
|
427
|
+
{ key: "remote", label: "Remote" },
|
|
428
|
+
{ key: "on-site", label: "On site" }
|
|
429
|
+
]
|
|
430
|
+
},
|
|
431
|
+
intent: {
|
|
432
|
+
primitive: "enum",
|
|
433
|
+
smsLabel: "Wants",
|
|
434
|
+
options: [
|
|
435
|
+
{ key: "book", label: "Book" },
|
|
436
|
+
{ key: "quote", label: "Quote" }
|
|
437
|
+
]
|
|
438
|
+
},
|
|
439
|
+
vehicle: { primitive: "string", smsLabel: "Vehicle" },
|
|
440
|
+
drop_off: {
|
|
441
|
+
primitive: "enum",
|
|
442
|
+
smsLabel: "Drop-off",
|
|
443
|
+
options: [
|
|
444
|
+
{ key: "wait-for-it", label: "Waiting" },
|
|
445
|
+
{ key: "drop-off", label: "Dropping off" }
|
|
446
|
+
]
|
|
447
|
+
},
|
|
448
|
+
address: { primitive: "address", smsLabel: "Address" },
|
|
449
|
+
patient_type: { primitive: "enum", smsLabel: "Patient" },
|
|
450
|
+
matter: { primitive: "enum", smsLabel: "Matter" },
|
|
451
|
+
language: { primitive: "enum", smsLabel: "Language" },
|
|
452
|
+
products: { primitive: "multi_enum", smsLabel: "Products" },
|
|
453
|
+
goal: { primitive: "enum", smsLabel: "Goal" },
|
|
454
|
+
business_type: { primitive: "enum", smsLabel: "Business" },
|
|
455
|
+
lead_volume: { primitive: "enum", smsLabel: "Lead volume" },
|
|
456
|
+
add_on: { primitive: "bool", smsLabel: "" },
|
|
457
|
+
attribution: { primitive: "enum", smsLabel: "", uninteresting: true }
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// ../tracking-core/src/lead-forms/submit.ts
|
|
461
|
+
import { safeParse as safeParse2 } from "zod/mini";
|
|
462
|
+
|
|
463
|
+
// ../tracking-core/src/cross-site-link.ts
|
|
464
|
+
import * as z3 from "zod/mini";
|
|
247
465
|
|
|
248
466
|
// ../tracking-core/src/uuid.ts
|
|
249
467
|
function uuidV4() {
|
|
@@ -281,17 +499,348 @@ function peekSessionId(now = Date.now()) {
|
|
|
281
499
|
}
|
|
282
500
|
}
|
|
283
501
|
|
|
284
|
-
// ../tracking-core/src/
|
|
285
|
-
var
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
502
|
+
// ../tracking-core/src/cross-site-link.ts
|
|
503
|
+
var LINK_PARAM = "_arv";
|
|
504
|
+
var LINK_TOKEN_TTL_MS = 5 * 60 * 1e3;
|
|
505
|
+
var FUTURE_SKEW_MS = 60 * 1e3;
|
|
506
|
+
var CARRIED_KEYS = {
|
|
507
|
+
g: "gclid",
|
|
508
|
+
w: "wbraid",
|
|
509
|
+
gb: "gbraid",
|
|
510
|
+
f: "fbclid",
|
|
511
|
+
y: "ylpcid"
|
|
294
512
|
};
|
|
513
|
+
var CARRIED_ENTRIES = Object.entries(CARRIED_KEYS);
|
|
514
|
+
var identifier = z3.string().check(z3.minLength(1), z3.maxLength(128));
|
|
515
|
+
var optionalIdentifier = z3.optional(identifier);
|
|
516
|
+
var linkTokenSchema = z3.object({
|
|
517
|
+
v: identifier,
|
|
518
|
+
s: identifier,
|
|
519
|
+
// Epoch ms in base36.
|
|
520
|
+
t: z3.string().check(z3.regex(/^[0-9a-z]{1,12}$/)),
|
|
521
|
+
g: optionalIdentifier,
|
|
522
|
+
w: optionalIdentifier,
|
|
523
|
+
gb: optionalIdentifier,
|
|
524
|
+
f: optionalIdentifier,
|
|
525
|
+
fc: optionalIdentifier,
|
|
526
|
+
y: optionalIdentifier
|
|
527
|
+
});
|
|
528
|
+
function stripLinkParam(url) {
|
|
529
|
+
try {
|
|
530
|
+
const parsed = new URL(url, typeof window === "undefined" ? void 0 : window.location.href);
|
|
531
|
+
if (!parsed.searchParams.has(LINK_PARAM)) return url;
|
|
532
|
+
parsed.searchParams.delete(LINK_PARAM);
|
|
533
|
+
return parsed.href;
|
|
534
|
+
} catch {
|
|
535
|
+
return url;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// ../tracking-core/src/resources/conversion-config.ts
|
|
540
|
+
var BOOKING_MODES = ["live", "test", "simulated"];
|
|
541
|
+
function isBookingMode(value) {
|
|
542
|
+
return BOOKING_MODES.includes(value);
|
|
543
|
+
}
|
|
544
|
+
function isStringMap(value) {
|
|
545
|
+
return typeof value === "object" && value !== null && Object.values(value).every((v) => typeof v === "string");
|
|
546
|
+
}
|
|
547
|
+
function parseFiring(value) {
|
|
548
|
+
if (!value || typeof value !== "object") return null;
|
|
549
|
+
const f = value;
|
|
550
|
+
if (typeof f.send_to !== "string") return null;
|
|
551
|
+
return {
|
|
552
|
+
send_to: f.send_to,
|
|
553
|
+
value_cents: typeof f.value_cents === "number" ? f.value_cents : null,
|
|
554
|
+
currency: typeof f.currency === "string" ? f.currency : null
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
function isNumberList(value) {
|
|
558
|
+
return Array.isArray(value) && value.every((v) => typeof v === "number");
|
|
559
|
+
}
|
|
560
|
+
function isStringList(value) {
|
|
561
|
+
return Array.isArray(value) && value.every((v) => typeof v === "string");
|
|
562
|
+
}
|
|
563
|
+
function parseWindowsMap(value) {
|
|
564
|
+
const windowsByKey = {};
|
|
565
|
+
if (!value || typeof value !== "object") return windowsByKey;
|
|
566
|
+
for (const [key, windows] of Object.entries(value)) {
|
|
567
|
+
if (!windows || typeof windows !== "object") continue;
|
|
568
|
+
const w = windows;
|
|
569
|
+
windowsByKey[key] = {
|
|
570
|
+
morning: isNumberList(w.morning) ? w.morning : [],
|
|
571
|
+
afternoon: isNumberList(w.afternoon) ? w.afternoon : []
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
return windowsByKey;
|
|
575
|
+
}
|
|
576
|
+
function parseBookingRules(value) {
|
|
577
|
+
if (!value || typeof value !== "object") return null;
|
|
578
|
+
const r = value;
|
|
579
|
+
if (typeof r.min_days_ahead !== "number" || typeof r.max_days_ahead !== "number") return null;
|
|
580
|
+
if (!r.hours || typeof r.hours !== "object") return null;
|
|
581
|
+
const hours = parseWindowsMap(r.hours);
|
|
582
|
+
return {
|
|
583
|
+
min_days_ahead: r.min_days_ahead,
|
|
584
|
+
max_days_ahead: r.max_days_ahead,
|
|
585
|
+
hours,
|
|
586
|
+
closed_dates: isStringList(r.closed_dates) ? r.closed_dates : [],
|
|
587
|
+
special_hours: parseWindowsMap(r.special_hours),
|
|
588
|
+
vehicle_required: r.vehicle_required === true,
|
|
589
|
+
vehicle_deferred: r.vehicle_deferred === true,
|
|
590
|
+
drop_off_options: isStringList(r.drop_off_options) ? r.drop_off_options : []
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
function parseBookingOption(value) {
|
|
594
|
+
if (!value || typeof value !== "object") return [];
|
|
595
|
+
const o = value;
|
|
596
|
+
if (typeof o.key !== "string" || !o.key || typeof o.label !== "string") return [];
|
|
597
|
+
return [
|
|
598
|
+
{
|
|
599
|
+
key: o.key,
|
|
600
|
+
label: o.label,
|
|
601
|
+
group: typeof o.group === "string" && o.group ? o.group : null,
|
|
602
|
+
description: typeof o.description === "string" && o.description ? o.description : null
|
|
603
|
+
}
|
|
604
|
+
];
|
|
605
|
+
}
|
|
606
|
+
function parseIntegrations(value) {
|
|
607
|
+
if (!value || typeof value !== "object") return {};
|
|
608
|
+
const autoleap = value.autoleap;
|
|
609
|
+
if (!autoleap || typeof autoleap !== "object") return {};
|
|
610
|
+
const booking = autoleap.booking;
|
|
611
|
+
if (!booking || typeof booking !== "object") return {};
|
|
612
|
+
const b = booking;
|
|
613
|
+
if (typeof b.fallback_url !== "string" || !b.fallback_url) return {};
|
|
614
|
+
return {
|
|
615
|
+
autoleap: {
|
|
616
|
+
booking: {
|
|
617
|
+
enabled: b.enabled === true,
|
|
618
|
+
fallback_url: b.fallback_url,
|
|
619
|
+
timezone: typeof b.timezone === "string" ? b.timezone : "UTC",
|
|
620
|
+
config_version: typeof b.config_version === "number" ? b.config_version : null,
|
|
621
|
+
accepts_bookings: b.accepts_bookings === true,
|
|
622
|
+
rules: parseBookingRules(b.rules),
|
|
623
|
+
options: Array.isArray(b.options) ? b.options.flatMap(parseBookingOption) : [],
|
|
624
|
+
...isBookingMode(b.mode) ? { mode: b.mode } : {}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
function parseTrigger(value) {
|
|
630
|
+
if (!value || typeof value !== "object") return null;
|
|
631
|
+
const t = value;
|
|
632
|
+
if (typeof t.event_type !== "string") return null;
|
|
633
|
+
const spec = { event_type: t.event_type };
|
|
634
|
+
if (typeof t.threshold_percent === "number") spec.threshold_percent = t.threshold_percent;
|
|
635
|
+
if (typeof t.threshold_seconds === "number") spec.threshold_seconds = t.threshold_seconds;
|
|
636
|
+
if (typeof t.page_threshold === "number") spec.page_threshold = t.page_threshold;
|
|
637
|
+
if (typeof t.page_name === "string") spec.page_name = t.page_name;
|
|
638
|
+
return spec;
|
|
639
|
+
}
|
|
640
|
+
function parseConversionConfig(raw) {
|
|
641
|
+
if (!raw || typeof raw !== "object") return null;
|
|
642
|
+
const obj = raw;
|
|
643
|
+
const servicesRaw = Array.isArray(obj.services) ? obj.services : [];
|
|
644
|
+
const services = servicesRaw.flatMap((entry) => {
|
|
645
|
+
if (!entry || typeof entry !== "object") return [];
|
|
646
|
+
const s = entry;
|
|
647
|
+
if (typeof s.key !== "string") return [];
|
|
648
|
+
return [
|
|
649
|
+
{
|
|
650
|
+
key: s.key,
|
|
651
|
+
label: typeof s.label === "string" ? s.label : void 0,
|
|
652
|
+
firing: parseFiring(s.firing)
|
|
653
|
+
}
|
|
654
|
+
];
|
|
655
|
+
});
|
|
656
|
+
const goalsRaw = Array.isArray(obj.goals) ? obj.goals : null;
|
|
657
|
+
const goals = goalsRaw ? goalsRaw.flatMap((entry) => {
|
|
658
|
+
if (!entry || typeof entry !== "object") return [];
|
|
659
|
+
const g = entry;
|
|
660
|
+
if (typeof g.key !== "string") return [];
|
|
661
|
+
return [
|
|
662
|
+
{
|
|
663
|
+
key: g.key,
|
|
664
|
+
label: typeof g.label === "string" ? g.label : void 0,
|
|
665
|
+
kind: g.kind === "event" ? "event" : "sale",
|
|
666
|
+
trigger: parseTrigger(g.trigger),
|
|
667
|
+
firing: parseFiring(g.firing)
|
|
668
|
+
}
|
|
669
|
+
];
|
|
670
|
+
}) : services.map((s) => ({
|
|
671
|
+
key: s.key,
|
|
672
|
+
label: s.label,
|
|
673
|
+
kind: "sale",
|
|
674
|
+
trigger: null,
|
|
675
|
+
firing: s.firing
|
|
676
|
+
}));
|
|
677
|
+
return {
|
|
678
|
+
schema_version: typeof obj.schema_version === "number" ? obj.schema_version : 1,
|
|
679
|
+
config_version: typeof obj.config_version === "number" ? obj.config_version : 0,
|
|
680
|
+
business_id: typeof obj.business_id === "string" ? obj.business_id : void 0,
|
|
681
|
+
customer_id: typeof obj.customer_id === "string" ? obj.customer_id : null,
|
|
682
|
+
environment: typeof obj.environment === "string" ? obj.environment : void 0,
|
|
683
|
+
google_tracking_state: obj.google_tracking_state === "active" ? "active" : "disabled",
|
|
684
|
+
gtag_ids: isStringMap(obj.gtag_ids) ? obj.gtag_ids : {},
|
|
685
|
+
meta_pixel_ids: isStringMap(obj.meta_pixel_ids) ? obj.meta_pixel_ids : {},
|
|
686
|
+
services,
|
|
687
|
+
goals,
|
|
688
|
+
linked_hostnames: Array.isArray(obj.linked_hostnames) ? obj.linked_hostnames.filter((h) => typeof h === "string" && h.length > 0) : [],
|
|
689
|
+
integrations: parseIntegrations(obj.integrations),
|
|
690
|
+
lead_forms: parseLeadForms(obj.lead_forms)
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function parseLeadForms(value) {
|
|
694
|
+
if (!isRecord(value) || typeof value.registry_version !== "number") return null;
|
|
695
|
+
return {
|
|
696
|
+
registry_version: value.registry_version,
|
|
697
|
+
contracts: records(value.contracts).flatMap(
|
|
698
|
+
(c) => typeof c.form_kind === "string" && typeof c.contract_hash === "string" ? [
|
|
699
|
+
{
|
|
700
|
+
form_kind: c.form_kind,
|
|
701
|
+
requires: records(c.requires).flatMap(
|
|
702
|
+
(r) => typeof r.role === "string" ? [
|
|
703
|
+
{
|
|
704
|
+
role: r.role,
|
|
705
|
+
required_when: parseCondition(r.required_when),
|
|
706
|
+
waived: r.waived === true
|
|
707
|
+
}
|
|
708
|
+
] : []
|
|
709
|
+
),
|
|
710
|
+
requires_any: records(c.requires_any).map((g) => ({
|
|
711
|
+
roles: strings(g.roles),
|
|
712
|
+
waived: g.waived === true
|
|
713
|
+
})),
|
|
714
|
+
options: records(c.options).flatMap(
|
|
715
|
+
(o) => typeof o.role === "string" ? [{ role: o.role, options: records(o.options).flatMap(parseContractOption) }] : []
|
|
716
|
+
),
|
|
717
|
+
contract_hash: c.contract_hash
|
|
718
|
+
}
|
|
719
|
+
] : []
|
|
720
|
+
)
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
function parseCondition(value) {
|
|
724
|
+
if (!isRecord(value) || typeof value.role !== "string") return null;
|
|
725
|
+
return { role: value.role, any_of: strings(value.any_of) };
|
|
726
|
+
}
|
|
727
|
+
function parseContractOption(value) {
|
|
728
|
+
if (typeof value.key !== "string" || typeof value.label !== "string") return [];
|
|
729
|
+
return [
|
|
730
|
+
{
|
|
731
|
+
key: value.key,
|
|
732
|
+
label: value.label,
|
|
733
|
+
is_non_answer: value.is_non_answer === true,
|
|
734
|
+
deprecated: value.deprecated === true
|
|
735
|
+
}
|
|
736
|
+
];
|
|
737
|
+
}
|
|
738
|
+
function isRecord(value) {
|
|
739
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
740
|
+
}
|
|
741
|
+
function records(value) {
|
|
742
|
+
return Array.isArray(value) ? value.filter(isRecord) : [];
|
|
743
|
+
}
|
|
744
|
+
function strings(value) {
|
|
745
|
+
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// ../tracking-core/src/resources/automatic-transaction.ts
|
|
749
|
+
var STORAGE_KEY = "_aranova_auto_txn_map";
|
|
750
|
+
var transactionIds = /* @__PURE__ */ new Map();
|
|
751
|
+
var legacyCounter = 0;
|
|
752
|
+
function scopeKey(sessionId, goalKey, path) {
|
|
753
|
+
return JSON.stringify([sessionId, goalKey, path]);
|
|
754
|
+
}
|
|
755
|
+
function randomId() {
|
|
756
|
+
const cryptoApi = globalThis.crypto;
|
|
757
|
+
if (typeof cryptoApi?.randomUUID === "function") return cryptoApi.randomUUID();
|
|
758
|
+
if (typeof cryptoApi?.getRandomValues === "function") {
|
|
759
|
+
const bytes = cryptoApi.getRandomValues(new Uint8Array(16));
|
|
760
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
761
|
+
}
|
|
762
|
+
legacyCounter = (legacyCounter + 1) % 4294967296;
|
|
763
|
+
const timestamp = Date.now().toString(16).padStart(12, "0");
|
|
764
|
+
const counter = legacyCounter.toString(16).padStart(8, "0");
|
|
765
|
+
const random = Math.floor(Math.random() * 281474976710655).toString(16).padStart(12, "0");
|
|
766
|
+
return `${timestamp}${counter}${random}`.slice(0, 32);
|
|
767
|
+
}
|
|
768
|
+
function isValidTransactionId(value) {
|
|
769
|
+
return typeof value === "string" && /^auto:(?:[0-9a-f]{32}|[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$/i.test(
|
|
770
|
+
value
|
|
771
|
+
) && value.length <= 64;
|
|
772
|
+
}
|
|
773
|
+
function readStoredMap(sessionId) {
|
|
774
|
+
if (typeof window === "undefined") return { sessionId, entries: {} };
|
|
775
|
+
try {
|
|
776
|
+
const raw = window.localStorage.getItem(STORAGE_KEY);
|
|
777
|
+
if (!raw) return { sessionId, entries: {} };
|
|
778
|
+
const parsed = JSON.parse(raw);
|
|
779
|
+
if (parsed.sessionId !== sessionId || !parsed.entries || typeof parsed.entries !== "object" || Array.isArray(parsed.entries)) {
|
|
780
|
+
return { sessionId, entries: {} };
|
|
781
|
+
}
|
|
782
|
+
return { sessionId, entries: parsed.entries };
|
|
783
|
+
} catch {
|
|
784
|
+
return { sessionId, entries: {} };
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
function writeStoredMap(stored) {
|
|
788
|
+
if (typeof window === "undefined") return;
|
|
789
|
+
try {
|
|
790
|
+
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(stored));
|
|
791
|
+
} catch {
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
function getAutomaticTransactionId(sessionId, goalKey, path) {
|
|
795
|
+
const key = scopeKey(sessionId, goalKey, path);
|
|
796
|
+
const existing = transactionIds.get(key);
|
|
797
|
+
if (existing) return existing;
|
|
798
|
+
const stored = readStoredMap(sessionId);
|
|
799
|
+
const storedId = stored.entries[key];
|
|
800
|
+
if (isValidTransactionId(storedId)) {
|
|
801
|
+
transactionIds.set(key, storedId);
|
|
802
|
+
return storedId;
|
|
803
|
+
}
|
|
804
|
+
const transactionId = `auto:${randomId()}`;
|
|
805
|
+
transactionIds.set(key, transactionId);
|
|
806
|
+
const latest = readStoredMap(sessionId);
|
|
807
|
+
const concurrentId = latest.entries[key];
|
|
808
|
+
if (isValidTransactionId(concurrentId)) {
|
|
809
|
+
transactionIds.set(key, concurrentId);
|
|
810
|
+
return concurrentId;
|
|
811
|
+
}
|
|
812
|
+
latest.entries[key] = transactionId;
|
|
813
|
+
writeStoredMap(latest);
|
|
814
|
+
return transactionId;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// ../tracking-core/src/resources/automatic-trigger.ts
|
|
818
|
+
function hasNumberField(metadata, key) {
|
|
819
|
+
return typeof metadata[key] === "number";
|
|
820
|
+
}
|
|
821
|
+
function hasStringField(metadata, key) {
|
|
822
|
+
return typeof metadata[key] === "string";
|
|
823
|
+
}
|
|
824
|
+
function automaticThresholdMet(goal, eventType, metadata) {
|
|
825
|
+
const trigger = goal.trigger;
|
|
826
|
+
if (!trigger || trigger.event_type !== eventType) return false;
|
|
827
|
+
switch (eventType) {
|
|
828
|
+
case "scroll_depth":
|
|
829
|
+
return hasNumberField(metadata, "depth_percent") && trigger.threshold_percent != null && metadata.depth_percent >= trigger.threshold_percent;
|
|
830
|
+
case "time_on_site":
|
|
831
|
+
return hasNumberField(metadata, "duration_ms") && trigger.threshold_seconds != null && metadata.duration_ms >= trigger.threshold_seconds * 1e3;
|
|
832
|
+
case "multi_page_session":
|
|
833
|
+
return hasNumberField(metadata, "page_count") && trigger.page_threshold != null && metadata.page_count >= trigger.page_threshold;
|
|
834
|
+
case "specific_page_visit":
|
|
835
|
+
return hasStringField(metadata, "page_name") && metadata.page_name === trigger.page_name;
|
|
836
|
+
case "page_view":
|
|
837
|
+
case "form_start":
|
|
838
|
+
case "phone_click":
|
|
839
|
+
return true;
|
|
840
|
+
default:
|
|
841
|
+
return false;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
295
844
|
|
|
296
845
|
// ../tracking-core/src/resources/intl/date.ts
|
|
297
846
|
function formatDateInTz(iso3, timeZone, opts, locale) {
|
|
@@ -340,7 +889,482 @@ function resolveTrackingConfigUrl(ref) {
|
|
|
340
889
|
const base = (configured || DEFAULT_CDN_BASE_URL).replace(/\/+$/, "");
|
|
341
890
|
return `${base}/${trackingConfigKey(ref)}`;
|
|
342
891
|
}
|
|
892
|
+
var CACHE_PREFIX = "_aranova_cfg_runtime_";
|
|
893
|
+
var AUTHORITY_TTL_MS = 6e4;
|
|
894
|
+
var MAX_QUEUE_LENGTH = 50;
|
|
895
|
+
var RETRY_BASE_MS = 5e3;
|
|
343
896
|
var RETRY_MAX_MS = 5 * 6e4;
|
|
897
|
+
var runtimes = /* @__PURE__ */ new Map();
|
|
898
|
+
var configuredIds = /* @__PURE__ */ new Set();
|
|
899
|
+
var scriptLoad = null;
|
|
900
|
+
var jsInitialized = false;
|
|
901
|
+
function cacheKey(url) {
|
|
902
|
+
return `${CACHE_PREFIX}${url}`;
|
|
903
|
+
}
|
|
904
|
+
function pushBounded(queue, item) {
|
|
905
|
+
queue.push(item);
|
|
906
|
+
if (queue.length > MAX_QUEUE_LENGTH) queue.splice(0, queue.length - MAX_QUEUE_LENGTH);
|
|
907
|
+
}
|
|
908
|
+
function readCache(url) {
|
|
909
|
+
if (typeof window === "undefined") return null;
|
|
910
|
+
try {
|
|
911
|
+
const raw = window.sessionStorage.getItem(cacheKey(url));
|
|
912
|
+
if (!raw) return null;
|
|
913
|
+
const parsed = JSON.parse(raw);
|
|
914
|
+
const config = parseConversionConfig(parsed.config);
|
|
915
|
+
if (!config) return null;
|
|
916
|
+
return {
|
|
917
|
+
etag: typeof parsed.etag === "string" ? parsed.etag : null,
|
|
918
|
+
config
|
|
919
|
+
};
|
|
920
|
+
} catch {
|
|
921
|
+
return null;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
function writeCache(url, entry) {
|
|
925
|
+
if (typeof window === "undefined") return;
|
|
926
|
+
try {
|
|
927
|
+
window.sessionStorage.setItem(cacheKey(url), JSON.stringify(entry));
|
|
928
|
+
} catch {
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
function isTombstone(config) {
|
|
932
|
+
return config.google_tracking_state === "disabled" || Object.keys(config.gtag_ids).length === 0;
|
|
933
|
+
}
|
|
934
|
+
function validateConfig(config, ref) {
|
|
935
|
+
return config.business_id === ref.businessId && config.environment === ref.environment && (config.google_tracking_state === "active" || config.google_tracking_state === "disabled");
|
|
936
|
+
}
|
|
937
|
+
function pageViewSnapshot() {
|
|
938
|
+
if (typeof window === "undefined" || typeof document === "undefined") return null;
|
|
939
|
+
return {
|
|
940
|
+
href: stripLinkParam(window.location.href),
|
|
941
|
+
title: document.title || null,
|
|
942
|
+
referrer: document.referrer || null
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
function ensureScript(gtagId) {
|
|
946
|
+
if (typeof window === "undefined" || typeof document === "undefined") return Promise.resolve();
|
|
947
|
+
applyDefaultConsentState();
|
|
948
|
+
loadGtagScript(gtagId);
|
|
949
|
+
if (scriptLoad) return scriptLoad;
|
|
950
|
+
scriptLoad = new Promise((resolve) => {
|
|
951
|
+
const script = document.querySelector(
|
|
952
|
+
'script[data-aranova-tracking="aranova-gtag-loader"]'
|
|
953
|
+
);
|
|
954
|
+
if (!script) {
|
|
955
|
+
resolve();
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
if (script.dataset.loaded === "true") {
|
|
959
|
+
resolve();
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
window.setTimeout(resolve, 0);
|
|
963
|
+
script.addEventListener(
|
|
964
|
+
"load",
|
|
965
|
+
() => {
|
|
966
|
+
script.dataset.loaded = "true";
|
|
967
|
+
resolve();
|
|
968
|
+
},
|
|
969
|
+
{ once: true }
|
|
970
|
+
);
|
|
971
|
+
script.addEventListener("error", () => resolve(), { once: true });
|
|
972
|
+
});
|
|
973
|
+
return scriptLoad;
|
|
974
|
+
}
|
|
975
|
+
var TrackingConfigRuntime = class {
|
|
976
|
+
constructor(ref, fetchImpl = globalThis.fetch) {
|
|
977
|
+
this.ref = ref;
|
|
978
|
+
this.current = null;
|
|
979
|
+
this.etag = null;
|
|
980
|
+
this.stateValue = "unconfirmed";
|
|
981
|
+
this.confirmedAt = 0;
|
|
982
|
+
this.authorityGeneration = 0;
|
|
983
|
+
this.inFlight = null;
|
|
984
|
+
this.flushInFlight = null;
|
|
985
|
+
this.flushRequested = false;
|
|
986
|
+
this.retryTimer = null;
|
|
987
|
+
this.started = false;
|
|
988
|
+
/** Consecutive failed authority attempts — drives the revalidate backoff. */
|
|
989
|
+
this.authorityFailures = 0;
|
|
990
|
+
/** Epoch ms before which `ensureAuthority` must not issue another request. */
|
|
991
|
+
this.nextAuthorityAttemptAt = 0;
|
|
992
|
+
this.conversionQueue = [];
|
|
993
|
+
this.automaticQueue = [];
|
|
994
|
+
this.pageQueue = [];
|
|
995
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
996
|
+
this.fetchImpl = fetchImpl.bind(globalThis);
|
|
997
|
+
this.url = resolveTrackingConfigUrl(ref);
|
|
998
|
+
const cached = readCache(this.url);
|
|
999
|
+
this.current = cached?.config ?? null;
|
|
1000
|
+
this.etag = cached?.etag ?? null;
|
|
1001
|
+
this.start();
|
|
1002
|
+
}
|
|
1003
|
+
/** The URL this runtime actually fetches (composed or explicit). */
|
|
1004
|
+
configUrl() {
|
|
1005
|
+
return this.url;
|
|
1006
|
+
}
|
|
1007
|
+
/**
|
|
1008
|
+
* Explicitly start authority resolution and Google-tag bootstrap.
|
|
1009
|
+
*
|
|
1010
|
+
* Idempotent so framework effects can call it after hydration without
|
|
1011
|
+
* depending on constructor timing.
|
|
1012
|
+
*/
|
|
1013
|
+
start() {
|
|
1014
|
+
if (this.started) {
|
|
1015
|
+
void this.flush();
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
this.started = true;
|
|
1019
|
+
void this.revalidate();
|
|
1020
|
+
if (typeof window !== "undefined") {
|
|
1021
|
+
window.addEventListener("visibilitychange", () => {
|
|
1022
|
+
if (document.visibilityState === "visible") void this.revalidate();
|
|
1023
|
+
});
|
|
1024
|
+
window.addEventListener("focus", () => void this.revalidate());
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
state() {
|
|
1028
|
+
return this.stateValue;
|
|
1029
|
+
}
|
|
1030
|
+
config() {
|
|
1031
|
+
return this.stateValue === "active" || this.stateValue === "tombstone" ? this.current : null;
|
|
1032
|
+
}
|
|
1033
|
+
__unsafeExpireAuthorityForTests() {
|
|
1034
|
+
this.confirmedAt = Number.NEGATIVE_INFINITY;
|
|
1035
|
+
this.nextAuthorityAttemptAt = 0;
|
|
1036
|
+
}
|
|
1037
|
+
/** Queue depths — asserted by tests to pin the bound. */
|
|
1038
|
+
__queueDepthsForTests() {
|
|
1039
|
+
return {
|
|
1040
|
+
conversions: this.conversionQueue.length,
|
|
1041
|
+
automatic: this.automaticQueue.length,
|
|
1042
|
+
pages: this.pageQueue.length
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
subscribe(listener) {
|
|
1046
|
+
this.listeners.add(listener);
|
|
1047
|
+
return () => this.listeners.delete(listener);
|
|
1048
|
+
}
|
|
1049
|
+
async ensureAuthority() {
|
|
1050
|
+
if (this.stateValue !== "unconfirmed" && Date.now() - this.confirmedAt < AUTHORITY_TTL_MS) {
|
|
1051
|
+
return true;
|
|
1052
|
+
}
|
|
1053
|
+
if (Date.now() < this.nextAuthorityAttemptAt) return false;
|
|
1054
|
+
await this.revalidateAuthority();
|
|
1055
|
+
return this.stateValue !== "unconfirmed" && Date.now() - this.confirmedAt < AUTHORITY_TTL_MS;
|
|
1056
|
+
}
|
|
1057
|
+
async revalidate() {
|
|
1058
|
+
this.nextAuthorityAttemptAt = 0;
|
|
1059
|
+
await this.revalidateAuthority();
|
|
1060
|
+
await this.flush();
|
|
1061
|
+
}
|
|
1062
|
+
async revalidateAuthority() {
|
|
1063
|
+
if (typeof window === "undefined" || !this.fetchImpl) return;
|
|
1064
|
+
if (this.inFlight) return this.inFlight;
|
|
1065
|
+
this.inFlight = this.revalidateNow().finally(() => {
|
|
1066
|
+
this.inFlight = null;
|
|
1067
|
+
});
|
|
1068
|
+
return this.inFlight;
|
|
1069
|
+
}
|
|
1070
|
+
queuePageView(snapshot = pageViewSnapshot()) {
|
|
1071
|
+
if (!snapshot) return;
|
|
1072
|
+
pushBounded(this.pageQueue, snapshot);
|
|
1073
|
+
void this.flush();
|
|
1074
|
+
}
|
|
1075
|
+
fireConversion(key, options) {
|
|
1076
|
+
pushBounded(this.conversionQueue, { key, ...options });
|
|
1077
|
+
void this.flush();
|
|
1078
|
+
}
|
|
1079
|
+
queueAutomaticEvent(eventType, metadata, transactionPath, transactionScope) {
|
|
1080
|
+
pushBounded(this.automaticQueue, {
|
|
1081
|
+
eventType,
|
|
1082
|
+
metadata,
|
|
1083
|
+
transactionPath,
|
|
1084
|
+
transactionScope
|
|
1085
|
+
});
|
|
1086
|
+
void this.flush();
|
|
1087
|
+
}
|
|
1088
|
+
listGoals() {
|
|
1089
|
+
return this.current?.goals ?? [];
|
|
1090
|
+
}
|
|
1091
|
+
/** Sibling hostnames for the linker — read from the cached object even while unconfirmed. */
|
|
1092
|
+
linkedHostnames() {
|
|
1093
|
+
return this.current?.linked_hostnames ?? [];
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Integration blocks, from the cached object even while unconfirmed: the booking fallback
|
|
1097
|
+
* link is safe to show stale. Same reference until the next adopt, for `useSyncExternalStore`.
|
|
1098
|
+
*/
|
|
1099
|
+
integrations() {
|
|
1100
|
+
return this.current?.integrations ?? null;
|
|
1101
|
+
}
|
|
1102
|
+
/** The lead-form contracts, from the cached object like `integrations()`. */
|
|
1103
|
+
leadForms() {
|
|
1104
|
+
return this.current?.lead_forms ?? null;
|
|
1105
|
+
}
|
|
1106
|
+
async revalidateNow() {
|
|
1107
|
+
try {
|
|
1108
|
+
const headers = {};
|
|
1109
|
+
if (this.etag) headers["If-None-Match"] = this.etag;
|
|
1110
|
+
const response = await this.fetchImpl(this.url, {
|
|
1111
|
+
method: "GET",
|
|
1112
|
+
headers,
|
|
1113
|
+
cache: "no-cache"
|
|
1114
|
+
});
|
|
1115
|
+
if (response.status === 304 && this.current && validateConfig(this.current, this.ref)) {
|
|
1116
|
+
this.confirm(this.current, this.etag);
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
if (!response.ok) {
|
|
1120
|
+
this.expireAuthority();
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
const next = parseConversionConfig(await response.json());
|
|
1124
|
+
if (!next || !validateConfig(next, this.ref)) {
|
|
1125
|
+
this.expireAuthority();
|
|
1126
|
+
return;
|
|
1127
|
+
}
|
|
1128
|
+
if (this.current && next.config_version < this.current.config_version) {
|
|
1129
|
+
this.expireAuthority();
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
this.confirm(next, response.headers.get("ETag"));
|
|
1133
|
+
} catch {
|
|
1134
|
+
this.expireAuthority();
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
expireAuthority() {
|
|
1138
|
+
this.authorityGeneration += 1;
|
|
1139
|
+
if (this.stateValue !== "unconfirmed") this.stateValue = "unconfirmed";
|
|
1140
|
+
this.authorityFailures += 1;
|
|
1141
|
+
const delay = Math.min(RETRY_MAX_MS, RETRY_BASE_MS * 2 ** (this.authorityFailures - 1));
|
|
1142
|
+
this.nextAuthorityAttemptAt = Date.now() + delay;
|
|
1143
|
+
}
|
|
1144
|
+
confirm(config, etag) {
|
|
1145
|
+
this.authorityGeneration += 1;
|
|
1146
|
+
this.current = config;
|
|
1147
|
+
this.etag = etag;
|
|
1148
|
+
this.confirmedAt = Date.now();
|
|
1149
|
+
this.authorityFailures = 0;
|
|
1150
|
+
this.nextAuthorityAttemptAt = 0;
|
|
1151
|
+
this.stateValue = isTombstone(config) ? "tombstone" : "active";
|
|
1152
|
+
writeCache(this.url, { etag, config });
|
|
1153
|
+
if (this.stateValue === "tombstone") {
|
|
1154
|
+
if (this.retryTimer !== null) {
|
|
1155
|
+
window.clearTimeout(this.retryTimer);
|
|
1156
|
+
this.retryTimer = null;
|
|
1157
|
+
}
|
|
1158
|
+
this.conversionQueue.length = 0;
|
|
1159
|
+
this.automaticQueue.length = 0;
|
|
1160
|
+
this.pageQueue.length = 0;
|
|
1161
|
+
}
|
|
1162
|
+
for (const listener of this.listeners) listener();
|
|
1163
|
+
}
|
|
1164
|
+
async flush() {
|
|
1165
|
+
if (this.flushInFlight) {
|
|
1166
|
+
this.flushRequested = true;
|
|
1167
|
+
return this.flushInFlight;
|
|
1168
|
+
}
|
|
1169
|
+
this.flushRequested = false;
|
|
1170
|
+
this.flushInFlight = this.flushNow().finally(() => {
|
|
1171
|
+
this.flushInFlight = null;
|
|
1172
|
+
if (this.flushRequested && this.stateValue === "active") void this.flush();
|
|
1173
|
+
});
|
|
1174
|
+
return this.flushInFlight;
|
|
1175
|
+
}
|
|
1176
|
+
scheduleRetry() {
|
|
1177
|
+
if (this.retryTimer !== null || typeof window === "undefined") return;
|
|
1178
|
+
this.retryTimer = window.setTimeout(() => {
|
|
1179
|
+
this.retryTimer = null;
|
|
1180
|
+
void this.flush();
|
|
1181
|
+
}, 1e3);
|
|
1182
|
+
}
|
|
1183
|
+
async flushNow() {
|
|
1184
|
+
if (!await this.ensureAuthority()) return;
|
|
1185
|
+
if (this.stateValue !== "active" || !this.current) return;
|
|
1186
|
+
const config = this.current;
|
|
1187
|
+
const generation = this.authorityGeneration;
|
|
1188
|
+
const ids = Object.values(config.gtag_ids).filter(
|
|
1189
|
+
(id) => typeof id === "string" && isValidGtagId(id)
|
|
1190
|
+
);
|
|
1191
|
+
if (ids.length === 0) return;
|
|
1192
|
+
await ensureScript(ids[0]);
|
|
1193
|
+
if (this.authorityGeneration !== generation || this.stateValue !== "active" || this.current !== config) {
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
const gtag = window.gtag;
|
|
1197
|
+
if (typeof gtag !== "function") return;
|
|
1198
|
+
try {
|
|
1199
|
+
if (!jsInitialized) {
|
|
1200
|
+
gtag("js", /* @__PURE__ */ new Date());
|
|
1201
|
+
jsInitialized = true;
|
|
1202
|
+
}
|
|
1203
|
+
for (const id of ids) {
|
|
1204
|
+
if (configuredIds.has(id)) continue;
|
|
1205
|
+
gtag("config", id, { send_page_view: false });
|
|
1206
|
+
configuredIds.add(id);
|
|
1207
|
+
}
|
|
1208
|
+
} catch {
|
|
1209
|
+
this.scheduleRetry();
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
while (this.pageQueue.length > 0) {
|
|
1213
|
+
const page = this.pageQueue[0];
|
|
1214
|
+
try {
|
|
1215
|
+
gtag("event", "page_view", {
|
|
1216
|
+
page_location: page.href,
|
|
1217
|
+
page_title: page.title ?? void 0,
|
|
1218
|
+
page_referrer: page.referrer ?? void 0
|
|
1219
|
+
});
|
|
1220
|
+
this.pageQueue.shift();
|
|
1221
|
+
} catch {
|
|
1222
|
+
this.scheduleRetry();
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
while (this.automaticQueue.length > 0) {
|
|
1227
|
+
const event = this.automaticQueue[0];
|
|
1228
|
+
for (const goal of config.goals) {
|
|
1229
|
+
if (goal.kind !== "event" || !goal.firing) continue;
|
|
1230
|
+
if (!automaticThresholdMet(goal, event.eventType, event.metadata)) continue;
|
|
1231
|
+
pushBounded(this.conversionQueue, {
|
|
1232
|
+
key: goal.key,
|
|
1233
|
+
transactionId: getAutomaticTransactionId(
|
|
1234
|
+
event.transactionScope,
|
|
1235
|
+
goal.key,
|
|
1236
|
+
event.transactionPath
|
|
1237
|
+
)
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
this.automaticQueue.shift();
|
|
1241
|
+
}
|
|
1242
|
+
while (this.conversionQueue.length > 0) {
|
|
1243
|
+
const item = this.conversionQueue[0];
|
|
1244
|
+
const goal = config.goals.find((g) => g.key === item.key);
|
|
1245
|
+
const firing = goal?.firing;
|
|
1246
|
+
if (!firing) {
|
|
1247
|
+
this.conversionQueue.shift();
|
|
1248
|
+
continue;
|
|
1249
|
+
}
|
|
1250
|
+
const currency = item.currency ?? firing.currency ?? null;
|
|
1251
|
+
const value = item.value ?? (firing.value_cents != null && currency ? fromMinor(firing.value_cents, currency) : null);
|
|
1252
|
+
const outcome = fireConversionWithConsent({
|
|
1253
|
+
sendTo: firing.send_to,
|
|
1254
|
+
value,
|
|
1255
|
+
currency,
|
|
1256
|
+
transactionId: item.transactionId ?? null
|
|
1257
|
+
});
|
|
1258
|
+
if (outcome === "retryable") {
|
|
1259
|
+
this.scheduleRetry();
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
1262
|
+
this.conversionQueue.shift();
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
};
|
|
1266
|
+
function getTrackingConfigRuntime(ref, fetchImpl) {
|
|
1267
|
+
const key = `${resolveTrackingConfigUrl(ref)}|${ref.businessId}|${ref.environment}`;
|
|
1268
|
+
const existing = runtimes.get(key);
|
|
1269
|
+
if (existing) return existing;
|
|
1270
|
+
const runtime = new TrackingConfigRuntime(ref, fetchImpl ?? globalThis.fetch);
|
|
1271
|
+
runtimes.set(key, runtime);
|
|
1272
|
+
return runtime;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
// ../tracking-core/src/lead-forms/submit.ts
|
|
1276
|
+
var KNOWN_ROLES = new Set(LEAD_FORM_ROLES);
|
|
1277
|
+
var ROLE_ORDER = new Map(LEAD_FORM_ROLES.map((role, index) => [role, index]));
|
|
1278
|
+
var ADD_ON = /^add_on:[a-z0-9_-]{1,48}$/;
|
|
1279
|
+
var CONTRACT_NAME = /^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?$/;
|
|
1280
|
+
function judgeLeadForm(kind, formId, fields, contracts, settings) {
|
|
1281
|
+
const generated = contracts?.contracts[kind];
|
|
1282
|
+
const live = liveContract(settings.trackingConfig, kind);
|
|
1283
|
+
const violations = check(live === void 0 ? generated : fromLive(live), fields);
|
|
1284
|
+
const liveHash = live === void 0 ? void 0 : live?.contract_hash ?? null;
|
|
1285
|
+
if (contracts && (liveHash !== void 0 && (generated?.hash ?? null) !== liveHash || contracts.registryVersion !== LEAD_FORM_REGISTRY_VERSION)) {
|
|
1286
|
+
violations.push({ role: null, rule: "contract_behind" });
|
|
1287
|
+
}
|
|
1288
|
+
if (violations.length > 0 && (settings.debug || settings.environment === "development")) {
|
|
1289
|
+
const message = `[AranovaTracking] lead form "${formId}" (${kind}) breaks its contract: ${violations.map((v) => `${v.rule}${v.role ? ` (${v.role})` : ""}`).join(", ")}`;
|
|
1290
|
+
console.error(message);
|
|
1291
|
+
if (settings.debug) throw new Error(message);
|
|
1292
|
+
}
|
|
1293
|
+
return {
|
|
1294
|
+
violations,
|
|
1295
|
+
hash: liveHash === void 0 ? generated?.hash ?? null : liveHash
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
function liveContract(ref, kind) {
|
|
1299
|
+
const leadForms = ref ? getTrackingConfigRuntime(ref).leadForms() : null;
|
|
1300
|
+
if (!leadForms) return void 0;
|
|
1301
|
+
return leadForms.contracts.find((c) => c.form_kind === kind) ?? null;
|
|
1302
|
+
}
|
|
1303
|
+
function fromLive(live) {
|
|
1304
|
+
if (!live) return void 0;
|
|
1305
|
+
return {
|
|
1306
|
+
requires: live.requires.map((r) => ({
|
|
1307
|
+
role: r.role,
|
|
1308
|
+
requiredWhen: r.required_when ? { role: r.required_when.role, anyOf: r.required_when.any_of } : null
|
|
1309
|
+
})),
|
|
1310
|
+
requiresAny: live.requires_any.map((g) => g.roles),
|
|
1311
|
+
// Deprecated keys still resolve: a cached form may send them (ADR-0024 §7).
|
|
1312
|
+
options: Object.fromEntries(live.options.map((o) => [o.role, o.options.map((x) => x.key)]))
|
|
1313
|
+
};
|
|
1314
|
+
}
|
|
1315
|
+
function check(contract, fields) {
|
|
1316
|
+
const answered = new Map(fields);
|
|
1317
|
+
const violations = [];
|
|
1318
|
+
for (const [role, value] of fields) {
|
|
1319
|
+
const primitive = primitiveOf(role);
|
|
1320
|
+
if (!primitive) {
|
|
1321
|
+
violations.push({ role: CONTRACT_NAME.test(role) ? role : null, rule: "unknown_role" });
|
|
1322
|
+
continue;
|
|
1323
|
+
}
|
|
1324
|
+
if (!safeParse2(leadFormPrimitiveSchemas[primitive], value).success) {
|
|
1325
|
+
violations.push({ role, rule: "invalid_value" });
|
|
1326
|
+
continue;
|
|
1327
|
+
}
|
|
1328
|
+
const allowed = contract?.options[role] ?? registryOptions(role);
|
|
1329
|
+
if (allowed?.length && optionKeys(value).some((key) => !allowed.includes(key))) {
|
|
1330
|
+
violations.push({ role, rule: "unknown_option" });
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
for (const { role, requiredWhen } of contract?.requires ?? []) {
|
|
1334
|
+
const owing = requiredWhen === null || optionKeys(answered.get(requiredWhen.role)).some((key) => requiredWhen.anyOf.includes(key));
|
|
1335
|
+
if (owing && !answered.has(role)) violations.push({ role, rule: "missing_required" });
|
|
1336
|
+
}
|
|
1337
|
+
for (const group of contract?.requiresAny ?? []) {
|
|
1338
|
+
if (!group.some((role) => answered.has(role))) {
|
|
1339
|
+
violations.push({ role: group.join("|"), rule: "missing_any_of" });
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
return violations;
|
|
1343
|
+
}
|
|
1344
|
+
function primitiveOf(role) {
|
|
1345
|
+
if (ADD_ON.test(role)) return "bool";
|
|
1346
|
+
return KNOWN_ROLES.has(role) ? LEAD_FORM_ROLE_SPECS[role].primitive : null;
|
|
1347
|
+
}
|
|
1348
|
+
function registryOptions(role) {
|
|
1349
|
+
const spec = KNOWN_ROLES.has(role) ? LEAD_FORM_ROLE_SPECS[role] : void 0;
|
|
1350
|
+
return spec && "options" in spec ? spec.options.map((o) => o.key) : void 0;
|
|
1351
|
+
}
|
|
1352
|
+
function optionKeys(value) {
|
|
1353
|
+
if (typeof value === "string") return [value];
|
|
1354
|
+
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
// ../tracking-core/src/resources/http/errors.ts
|
|
1358
|
+
var AranovaApiError = class extends Error {
|
|
1359
|
+
constructor(message, options) {
|
|
1360
|
+
super(message);
|
|
1361
|
+
this.name = "AranovaApiError";
|
|
1362
|
+
this.status = options.status;
|
|
1363
|
+
this.code = options.code;
|
|
1364
|
+
this.requestId = options.requestId;
|
|
1365
|
+
this.context = options.context;
|
|
1366
|
+
}
|
|
1367
|
+
};
|
|
344
1368
|
|
|
345
1369
|
// ../tracking-core/src/ingest.ts
|
|
346
1370
|
var API_KEY_HEADER = "X-Aranova-Api-Key";
|
|
@@ -376,11 +1400,11 @@ async function apiRequest(config, method, path, body, extraHeaders) {
|
|
|
376
1400
|
try {
|
|
377
1401
|
const parsed = await response.json();
|
|
378
1402
|
if (parsed && typeof parsed === "object") {
|
|
379
|
-
const
|
|
380
|
-
if (typeof
|
|
381
|
-
if (typeof
|
|
382
|
-
if (
|
|
383
|
-
context =
|
|
1403
|
+
const record4 = parsed;
|
|
1404
|
+
if (typeof record4.detail === "string") detail = record4.detail;
|
|
1405
|
+
if (typeof record4.code === "string") code = record4.code;
|
|
1406
|
+
if (record4.context && typeof record4.context === "object") {
|
|
1407
|
+
context = record4.context;
|
|
384
1408
|
}
|
|
385
1409
|
}
|
|
386
1410
|
} catch {
|
|
@@ -434,7 +1458,7 @@ var DROP_OFF_KEYS = {
|
|
|
434
1458
|
waitForIt: "wait-for-it",
|
|
435
1459
|
dropOff: "drop-off"
|
|
436
1460
|
};
|
|
437
|
-
function formSubmitPayload(input, formSubmit,
|
|
1461
|
+
function formSubmitPayload(input, formSubmit, runtime) {
|
|
438
1462
|
const field = (role, name, type, label, value) => ({ name, type, label, value, role });
|
|
439
1463
|
const text = (value) => value?.trim() || void 0;
|
|
440
1464
|
const { vehicle, dropOff } = input;
|
|
@@ -444,7 +1468,7 @@ function formSubmitPayload(input, formSubmit, contractHash) {
|
|
|
444
1468
|
// E.164 on the wire: it keys the customer and enhanced-conversion matching.
|
|
445
1469
|
field("phone", "phone", "tel", "Phone", toE164(input.phone) ?? input.phone),
|
|
446
1470
|
field("email", "email", "email", "Email", text(input.email)),
|
|
447
|
-
field("service", "service", "select", "Service", input.services),
|
|
1471
|
+
field("service", "service", "select", "Service", [...input.services]),
|
|
448
1472
|
field(
|
|
449
1473
|
"vehicle",
|
|
450
1474
|
"vehicle",
|
|
@@ -469,6 +1493,14 @@ function formSubmitPayload(input, formSubmit, contractHash) {
|
|
|
469
1493
|
const reported = new Set(entries.map((item) => item.name));
|
|
470
1494
|
const fields = entries.filter((item) => item.value !== void 0);
|
|
471
1495
|
const extra = (formSubmit.extraFields ?? []).filter((item) => !reported.has(item.name));
|
|
1496
|
+
const settings = typedClientSettings(formSubmit.tracking);
|
|
1497
|
+
const { violations, hash } = judgeLeadForm(
|
|
1498
|
+
"booking",
|
|
1499
|
+
formSubmit.formId,
|
|
1500
|
+
fields.map((item) => [item.role, item.value]),
|
|
1501
|
+
formSubmit.contracts,
|
|
1502
|
+
{ ...settings, trackingConfig: settings.trackingConfig ?? runtime?.ref }
|
|
1503
|
+
);
|
|
472
1504
|
return {
|
|
473
1505
|
form: {
|
|
474
1506
|
id: formSubmit.formId,
|
|
@@ -476,7 +1508,8 @@ function formSubmitPayload(input, formSubmit, contractHash) {
|
|
|
476
1508
|
fields: [...fields, ...extra],
|
|
477
1509
|
kind: "booking",
|
|
478
1510
|
contract_version: LEAD_FORM_REGISTRY_VERSION,
|
|
479
|
-
...
|
|
1511
|
+
...hash ? { contract_hash: hash } : {},
|
|
1512
|
+
...violations.length > 0 ? { contract_violations: violations.slice(0, MAX_CONTRACT_VIOLATIONS) } : {}
|
|
480
1513
|
},
|
|
481
1514
|
page: { path: typeof window === "undefined" ? "/" : window.location.pathname }
|
|
482
1515
|
};
|
|
@@ -575,10 +1608,9 @@ function createSalesBookingsClient(config, firing) {
|
|
|
575
1608
|
}
|
|
576
1609
|
if (formSubmit && !submittedForms.has(attemptKey)) {
|
|
577
1610
|
submittedForms.add(attemptKey);
|
|
578
|
-
const contract = runtime?.leadForms()?.contracts.find((c) => c.form_kind === "booking");
|
|
579
1611
|
formSubmit.tracking.trackEvent(
|
|
580
1612
|
"form_submit",
|
|
581
|
-
formSubmitPayload(input, formSubmit,
|
|
1613
|
+
formSubmitPayload(input, formSubmit, runtime)
|
|
582
1614
|
);
|
|
583
1615
|
}
|
|
584
1616
|
const body = {
|
|
@@ -594,7 +1626,7 @@ function createSalesBookingsClient(config, firing) {
|
|
|
594
1626
|
email: input.email?.trim() || null,
|
|
595
1627
|
vehicle: input.vehicle ?? null,
|
|
596
1628
|
drop_off: input.dropOff ?? null,
|
|
597
|
-
services: input.services,
|
|
1629
|
+
services: [...input.services],
|
|
598
1630
|
notes: input.notes?.trim() || null,
|
|
599
1631
|
marketing_sms_consent: input.marketingSmsConsent === true,
|
|
600
1632
|
page_path: typeof window === "undefined" ? null : window.location.pathname
|
|
@@ -681,7 +1713,7 @@ function fireRecordedConversions(firing, input, recorded, sale, currency) {
|
|
|
681
1713
|
}
|
|
682
1714
|
function createSalesClient(config) {
|
|
683
1715
|
if (config.firing) registerCapability("conversion_goals_manual");
|
|
684
|
-
async function
|
|
1716
|
+
async function record4(input) {
|
|
685
1717
|
const currency = input.currency ?? config.defaultCurrency;
|
|
686
1718
|
if (!currency) {
|
|
687
1719
|
throw new Error(
|
|
@@ -707,9 +1739,9 @@ function createSalesClient(config) {
|
|
|
707
1739
|
return sale;
|
|
708
1740
|
}
|
|
709
1741
|
return {
|
|
710
|
-
record:
|
|
1742
|
+
record: record4,
|
|
711
1743
|
// recordSale is the intent-revealing alias — same behavior, clearer call site.
|
|
712
|
-
recordSale:
|
|
1744
|
+
recordSale: record4,
|
|
713
1745
|
trackConversion(key, options) {
|
|
714
1746
|
if (config.firing && "fireConversion" in config.firing) {
|
|
715
1747
|
if (options?.userData && getConsentState() !== "denied") stashUserData(options.userData);
|
|
@@ -829,17 +1861,17 @@ function createSalesClient(config) {
|
|
|
829
1861
|
}
|
|
830
1862
|
|
|
831
1863
|
// ../tracking-core/src/resources/sales/schema.ts
|
|
832
|
-
import * as
|
|
1864
|
+
import * as z5 from "zod/mini";
|
|
833
1865
|
|
|
834
1866
|
// ../tracking-core/src/resources/sales/generated/zod.gen.ts
|
|
835
|
-
import * as
|
|
836
|
-
var zAutoLeapSaleFacts =
|
|
837
|
-
first_order:
|
|
838
|
-
fleet_customer:
|
|
839
|
-
invoice_code:
|
|
840
|
-
invoice_id:
|
|
1867
|
+
import * as z4 from "zod/mini";
|
|
1868
|
+
var zAutoLeapSaleFacts = z4.object({
|
|
1869
|
+
first_order: z4.boolean(),
|
|
1870
|
+
fleet_customer: z4.boolean(),
|
|
1871
|
+
invoice_code: z4.string(),
|
|
1872
|
+
invoice_id: z4.string()
|
|
841
1873
|
});
|
|
842
|
-
var zErrorCode =
|
|
1874
|
+
var zErrorCode = z4.enum([
|
|
843
1875
|
"missing_credentials",
|
|
844
1876
|
"invalid_api_key",
|
|
845
1877
|
"not_authenticated",
|
|
@@ -883,37 +1915,37 @@ var zErrorCode = z2.enum([
|
|
|
883
1915
|
"rate_limited",
|
|
884
1916
|
"internal_error"
|
|
885
1917
|
]);
|
|
886
|
-
var zSaleItemEntitySchema =
|
|
887
|
-
category:
|
|
888
|
-
external_item_id:
|
|
889
|
-
id:
|
|
890
|
-
name:
|
|
891
|
-
quantity:
|
|
892
|
-
unit_cost_cents:
|
|
893
|
-
unit_price_cents:
|
|
1918
|
+
var zSaleItemEntitySchema = z4.object({
|
|
1919
|
+
category: z4.nullable(z4.string()),
|
|
1920
|
+
external_item_id: z4.nullable(z4.string()),
|
|
1921
|
+
id: z4.uuid(),
|
|
1922
|
+
name: z4.nullable(z4.string()),
|
|
1923
|
+
quantity: z4.string().check(z4.regex(/^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$/)),
|
|
1924
|
+
unit_cost_cents: z4.nullable(z4.int()),
|
|
1925
|
+
unit_price_cents: z4.int()
|
|
894
1926
|
});
|
|
895
|
-
var zSaleItemInputSchema =
|
|
896
|
-
category:
|
|
897
|
-
external_item_id:
|
|
898
|
-
name:
|
|
899
|
-
quantity:
|
|
900
|
-
unit_cost_cents:
|
|
901
|
-
unit_price_cents:
|
|
1927
|
+
var zSaleItemInputSchema = z4.strictObject({
|
|
1928
|
+
category: z4.nullish(z4.string()),
|
|
1929
|
+
external_item_id: z4.nullish(z4.string()),
|
|
1930
|
+
name: z4.nullish(z4.string()),
|
|
1931
|
+
quantity: z4.string().check(z4.regex(/^\d+(\.\d{1,3})?$/)),
|
|
1932
|
+
unit_cost_cents: z4.nullish(z4.int().check(z4.gte(0))),
|
|
1933
|
+
unit_price_cents: z4.int().check(z4.gte(0))
|
|
902
1934
|
});
|
|
903
|
-
var zSaleServiceEntitySchema =
|
|
904
|
-
amount_cents:
|
|
905
|
-
id:
|
|
906
|
-
mapped:
|
|
907
|
-
service_id:
|
|
908
|
-
service_key:
|
|
909
|
-
service_label:
|
|
1935
|
+
var zSaleServiceEntitySchema = z4.object({
|
|
1936
|
+
amount_cents: z4.int(),
|
|
1937
|
+
id: z4.uuid(),
|
|
1938
|
+
mapped: z4.nullable(z4.boolean()),
|
|
1939
|
+
service_id: z4.uuid(),
|
|
1940
|
+
service_key: z4.string(),
|
|
1941
|
+
service_label: z4.string()
|
|
910
1942
|
});
|
|
911
|
-
var zSaleServiceInputSchema =
|
|
912
|
-
amount_cents:
|
|
913
|
-
service:
|
|
1943
|
+
var zSaleServiceInputSchema = z4.strictObject({
|
|
1944
|
+
amount_cents: z4.int().check(z4.gte(0)),
|
|
1945
|
+
service: z4.string()
|
|
914
1946
|
});
|
|
915
|
-
var zSaleSource =
|
|
916
|
-
var zSmsAutomationState =
|
|
1947
|
+
var zSaleSource = z4.enum(["api", "admin", "autoleap"]);
|
|
1948
|
+
var zSmsAutomationState = z4.enum([
|
|
917
1949
|
"needs_check",
|
|
918
1950
|
"failed",
|
|
919
1951
|
"undelivered",
|
|
@@ -925,7 +1957,7 @@ var zSmsAutomationState = z2.enum([
|
|
|
925
1957
|
"eligible",
|
|
926
1958
|
"not_applicable"
|
|
927
1959
|
]);
|
|
928
|
-
var zSmsWithheldReason =
|
|
1960
|
+
var zSmsWithheldReason = z4.enum([
|
|
929
1961
|
"automation_disabled",
|
|
930
1962
|
"sms_disabled",
|
|
931
1963
|
"no_phone",
|
|
@@ -951,77 +1983,80 @@ var zSmsWithheldReason = z2.enum([
|
|
|
951
1983
|
"confirmed_by_integration",
|
|
952
1984
|
"test_or_bot_session",
|
|
953
1985
|
"invalid_phone",
|
|
954
|
-
"recently_texted"
|
|
1986
|
+
"recently_texted",
|
|
1987
|
+
"do_not_contact",
|
|
1988
|
+
"do_not_text_tag",
|
|
1989
|
+
"missing_value"
|
|
955
1990
|
]);
|
|
956
|
-
var zSaleSmsStatusSchema =
|
|
957
|
-
can_send_now:
|
|
958
|
-
last_message_at:
|
|
959
|
-
reason_detail:
|
|
1991
|
+
var zSaleSmsStatusSchema = z4.object({
|
|
1992
|
+
can_send_now: z4._default(z4.boolean(), false),
|
|
1993
|
+
last_message_at: z4.nullable(z4.iso.datetime({ offset: true })),
|
|
1994
|
+
reason_detail: z4.nullable(z4.string()),
|
|
960
1995
|
state: zSmsAutomationState,
|
|
961
|
-
suppressed_by_other_sale:
|
|
962
|
-
withheld_reason:
|
|
1996
|
+
suppressed_by_other_sale: z4._default(z4.boolean(), false),
|
|
1997
|
+
withheld_reason: z4.nullable(zSmsWithheldReason)
|
|
963
1998
|
});
|
|
964
|
-
var zSupportedCurrency =
|
|
965
|
-
var zTrackingEnvironment =
|
|
966
|
-
var zSaleCreateSchema =
|
|
967
|
-
amount_total_cents:
|
|
1999
|
+
var zSupportedCurrency = z4.enum(["USD", "CAD"]);
|
|
2000
|
+
var zTrackingEnvironment = z4.enum(["production", "development"]);
|
|
2001
|
+
var zSaleCreateSchema = z4.strictObject({
|
|
2002
|
+
amount_total_cents: z4.nullish(z4.int().check(z4.gte(0))),
|
|
968
2003
|
currency: zSupportedCurrency,
|
|
969
|
-
customer_email:
|
|
970
|
-
customer_name:
|
|
971
|
-
customer_phone:
|
|
972
|
-
description:
|
|
973
|
-
environment:
|
|
974
|
-
external_id:
|
|
975
|
-
items:
|
|
976
|
-
metadata:
|
|
977
|
-
occurred_at:
|
|
978
|
-
service:
|
|
979
|
-
services:
|
|
980
|
-
sms_consent:
|
|
2004
|
+
customer_email: z4.nullish(z4.email().check(z4.maxLength(320))),
|
|
2005
|
+
customer_name: z4.nullish(z4.string().check(z4.maxLength(200))),
|
|
2006
|
+
customer_phone: z4.nullish(z4.string().check(z4.maxLength(64))),
|
|
2007
|
+
description: z4.nullish(z4.string()),
|
|
2008
|
+
environment: z4._default(z4.optional(zTrackingEnvironment), "production"),
|
|
2009
|
+
external_id: z4.nullish(z4.string()),
|
|
2010
|
+
items: z4.optional(z4.array(zSaleItemInputSchema)),
|
|
2011
|
+
metadata: z4.nullish(z4.record(z4.string(), z4.unknown())),
|
|
2012
|
+
occurred_at: z4.iso.datetime({ offset: true }),
|
|
2013
|
+
service: z4.nullish(z4.string()),
|
|
2014
|
+
services: z4.nullish(z4.array(zSaleServiceInputSchema)),
|
|
2015
|
+
sms_consent: z4.nullish(z4.boolean())
|
|
981
2016
|
});
|
|
982
|
-
var zValidationError =
|
|
983
|
-
ctx:
|
|
984
|
-
input:
|
|
985
|
-
loc:
|
|
986
|
-
msg:
|
|
987
|
-
type:
|
|
2017
|
+
var zValidationError = z4.object({
|
|
2018
|
+
ctx: z4.optional(z4.record(z4.string(), z4.unknown())),
|
|
2019
|
+
input: z4.optional(z4.unknown()),
|
|
2020
|
+
loc: z4.array(z4.union([z4.string(), z4.int()])),
|
|
2021
|
+
msg: z4.string(),
|
|
2022
|
+
type: z4.string()
|
|
988
2023
|
});
|
|
989
|
-
var zHttpValidationError =
|
|
990
|
-
detail:
|
|
2024
|
+
var zHttpValidationError = z4.object({
|
|
2025
|
+
detail: z4.optional(z4.array(zValidationError))
|
|
991
2026
|
});
|
|
992
|
-
var zValidationErrorItem =
|
|
993
|
-
loc:
|
|
994
|
-
msg:
|
|
995
|
-
type:
|
|
2027
|
+
var zValidationErrorItem = z4.object({
|
|
2028
|
+
loc: z4.array(z4.union([z4.string(), z4.int()])),
|
|
2029
|
+
msg: z4.string(),
|
|
2030
|
+
type: z4.string()
|
|
996
2031
|
});
|
|
997
|
-
var zApiErrorSchema =
|
|
2032
|
+
var zApiErrorSchema = z4.object({
|
|
998
2033
|
code: zErrorCode,
|
|
999
|
-
context:
|
|
1000
|
-
detail:
|
|
1001
|
-
errors:
|
|
1002
|
-
request_id:
|
|
2034
|
+
context: z4._default(z4.nullish(z4.record(z4.string(), z4.unknown())), null),
|
|
2035
|
+
detail: z4.string(),
|
|
2036
|
+
errors: z4._default(z4.nullish(z4.array(zValidationErrorItem)), null),
|
|
2037
|
+
request_id: z4._default(z4.nullish(z4.string()), null)
|
|
1003
2038
|
});
|
|
1004
|
-
var zWritebackEmailSource =
|
|
1005
|
-
var zWritebackEnrichmentStatus =
|
|
1006
|
-
var zWritebackSaleUploadCounts =
|
|
1007
|
-
failed:
|
|
1008
|
-
pending:
|
|
1009
|
-
skipped:
|
|
1010
|
-
submitted:
|
|
1011
|
-
total:
|
|
1012
|
-
uploaded:
|
|
2039
|
+
var zWritebackEmailSource = z4.enum(["NONE", "SALE", "CUSTOMER", "HARVESTED"]);
|
|
2040
|
+
var zWritebackEnrichmentStatus = z4.enum(["NONE", "MATCHED", "AMBIGUOUS"]);
|
|
2041
|
+
var zWritebackSaleUploadCounts = z4.object({
|
|
2042
|
+
failed: z4._default(z4.int(), 0),
|
|
2043
|
+
pending: z4._default(z4.int(), 0),
|
|
2044
|
+
skipped: z4._default(z4.int(), 0),
|
|
2045
|
+
submitted: z4._default(z4.int(), 0),
|
|
2046
|
+
total: z4._default(z4.int(), 0),
|
|
2047
|
+
uploaded: z4._default(z4.int(), 0)
|
|
1013
2048
|
});
|
|
1014
|
-
var zSaleWritebackStatusSchema =
|
|
1015
|
-
blocked_reason:
|
|
1016
|
-
can_dispatch:
|
|
1017
|
-
email_source:
|
|
1018
|
-
enrichment_status:
|
|
1019
|
-
gclid_attached:
|
|
1020
|
-
identifiers_sent:
|
|
1021
|
-
mapped_service_ids:
|
|
1022
|
-
matched_submit_count:
|
|
1023
|
-
needs_force:
|
|
1024
|
-
rollup:
|
|
2049
|
+
var zSaleWritebackStatusSchema = z4.object({
|
|
2050
|
+
blocked_reason: z4.nullable(z4.string()),
|
|
2051
|
+
can_dispatch: z4._default(z4.boolean(), false),
|
|
2052
|
+
email_source: z4.nullable(zWritebackEmailSource),
|
|
2053
|
+
enrichment_status: z4.nullable(zWritebackEnrichmentStatus),
|
|
2054
|
+
gclid_attached: z4._default(z4.boolean(), false),
|
|
2055
|
+
identifiers_sent: z4.nullable(z4.string()),
|
|
2056
|
+
mapped_service_ids: z4.array(z4.uuid()),
|
|
2057
|
+
matched_submit_count: z4.nullable(z4.int()),
|
|
2058
|
+
needs_force: z4._default(z4.boolean(), false),
|
|
2059
|
+
rollup: z4.enum([
|
|
1025
2060
|
"failed",
|
|
1026
2061
|
"skipped",
|
|
1027
2062
|
"pending",
|
|
@@ -1031,39 +2066,39 @@ var zSaleWritebackStatusSchema = z2.object({
|
|
|
1031
2066
|
"out_of_window",
|
|
1032
2067
|
"blocked"
|
|
1033
2068
|
]),
|
|
1034
|
-
stale:
|
|
1035
|
-
uncovered_service_ids:
|
|
2069
|
+
stale: z4._default(z4.boolean(), false),
|
|
2070
|
+
uncovered_service_ids: z4.array(z4.uuid()),
|
|
1036
2071
|
uploads: zWritebackSaleUploadCounts
|
|
1037
2072
|
});
|
|
1038
|
-
var zSaleEntitySchema =
|
|
1039
|
-
amount_total_cents:
|
|
1040
|
-
business_id:
|
|
1041
|
-
business_name:
|
|
1042
|
-
created_at:
|
|
1043
|
-
currency:
|
|
1044
|
-
customer_email:
|
|
1045
|
-
customer_name:
|
|
1046
|
-
customer_name_placeholder_confirmed:
|
|
1047
|
-
customer_name_placeholder_confirmed_at:
|
|
1048
|
-
customer_phone:
|
|
1049
|
-
description:
|
|
2073
|
+
var zSaleEntitySchema = z4.object({
|
|
2074
|
+
amount_total_cents: z4.int(),
|
|
2075
|
+
business_id: z4.uuid(),
|
|
2076
|
+
business_name: z4.nullable(z4.string()),
|
|
2077
|
+
created_at: z4.iso.datetime({ offset: true }),
|
|
2078
|
+
currency: z4.string(),
|
|
2079
|
+
customer_email: z4.nullable(z4.string()),
|
|
2080
|
+
customer_name: z4.nullable(z4.string()),
|
|
2081
|
+
customer_name_placeholder_confirmed: z4._default(z4.boolean(), false),
|
|
2082
|
+
customer_name_placeholder_confirmed_at: z4.nullable(z4.iso.datetime({ offset: true })),
|
|
2083
|
+
customer_phone: z4.nullable(z4.string()),
|
|
2084
|
+
description: z4.nullable(z4.string()),
|
|
1050
2085
|
environment: zTrackingEnvironment,
|
|
1051
|
-
external_id:
|
|
1052
|
-
id:
|
|
1053
|
-
items:
|
|
1054
|
-
metadata:
|
|
1055
|
-
occurred_at:
|
|
1056
|
-
service_id:
|
|
1057
|
-
service_key:
|
|
1058
|
-
service_label:
|
|
1059
|
-
services:
|
|
1060
|
-
sms_automation:
|
|
1061
|
-
sms_consent:
|
|
1062
|
-
sms_consent_granted_at:
|
|
2086
|
+
external_id: z4.nullable(z4.string()),
|
|
2087
|
+
id: z4.uuid(),
|
|
2088
|
+
items: z4.array(zSaleItemEntitySchema),
|
|
2089
|
+
metadata: z4.nullable(z4.record(z4.string(), z4.unknown())),
|
|
2090
|
+
occurred_at: z4.iso.datetime({ offset: true }),
|
|
2091
|
+
service_id: z4.nullable(z4.uuid()),
|
|
2092
|
+
service_key: z4.nullable(z4.string()),
|
|
2093
|
+
service_label: z4.nullable(z4.string()),
|
|
2094
|
+
services: z4.array(zSaleServiceEntitySchema),
|
|
2095
|
+
sms_automation: z4.nullable(zSaleSmsStatusSchema),
|
|
2096
|
+
sms_consent: z4._default(z4.boolean(), false),
|
|
2097
|
+
sms_consent_granted_at: z4.nullable(z4.iso.datetime({ offset: true })),
|
|
1063
2098
|
source: zSaleSource,
|
|
1064
|
-
source_facts:
|
|
1065
|
-
updated_at:
|
|
1066
|
-
writeback:
|
|
2099
|
+
source_facts: z4.nullable(zAutoLeapSaleFacts),
|
|
2100
|
+
updated_at: z4.iso.datetime({ offset: true }),
|
|
2101
|
+
writeback: z4.nullable(zSaleWritebackStatusSchema)
|
|
1067
2102
|
});
|
|
1068
2103
|
|
|
1069
2104
|
// ../tracking-core/src/resources/sales/schema.ts
|
|
@@ -1072,11 +2107,11 @@ var saleServiceSchema = zSaleServiceInputSchema;
|
|
|
1072
2107
|
var currencySchema = zSupportedCurrency;
|
|
1073
2108
|
var SUPPORTED_CURRENCIES = currencySchema.options;
|
|
1074
2109
|
var SALE_SOURCES = zSaleSource.options;
|
|
1075
|
-
var centsSchema =
|
|
1076
|
-
var metadataSchema =
|
|
1077
|
-
var customerNameSchema =
|
|
1078
|
-
var customerPhoneSchema =
|
|
1079
|
-
var customerEmailSchema =
|
|
2110
|
+
var centsSchema = z5.int().check(z5.gte(0));
|
|
2111
|
+
var metadataSchema = z5.record(z5.string(), z5.unknown());
|
|
2112
|
+
var customerNameSchema = z5.string().check(z5.maxLength(200));
|
|
2113
|
+
var customerPhoneSchema = z5.string().check(z5.maxLength(64));
|
|
2114
|
+
var customerEmailSchema = z5.email().check(z5.maxLength(320));
|
|
1080
2115
|
function addIssue(ctx, path, message) {
|
|
1081
2116
|
ctx.issues.push({ code: "custom", input: ctx.value, path, message });
|
|
1082
2117
|
}
|
|
@@ -1110,24 +2145,24 @@ function refineServiceXor(val, ctx, { requireAmount }) {
|
|
|
1110
2145
|
);
|
|
1111
2146
|
}
|
|
1112
2147
|
}
|
|
1113
|
-
var saleCreateSchema =
|
|
1114
|
-
var saleUpdateSchema =
|
|
1115
|
-
description:
|
|
1116
|
-
service:
|
|
1117
|
-
services:
|
|
1118
|
-
currency:
|
|
1119
|
-
amount_total_cents:
|
|
1120
|
-
occurred_at:
|
|
1121
|
-
items:
|
|
1122
|
-
metadata:
|
|
1123
|
-
customer_name:
|
|
2148
|
+
var saleCreateSchema = z5.extend(zSaleCreateSchema, { items: z5._default(z5.array(saleItemSchema), []) }).check((ctx) => refineServiceXor(ctx.value, ctx, { requireAmount: true }));
|
|
2149
|
+
var saleUpdateSchema = z5.strictObject({
|
|
2150
|
+
description: z5.nullish(z5.string()),
|
|
2151
|
+
service: z5.nullish(z5.string()),
|
|
2152
|
+
services: z5.nullish(z5.array(saleServiceSchema)),
|
|
2153
|
+
currency: z5.optional(currencySchema),
|
|
2154
|
+
amount_total_cents: z5.optional(centsSchema),
|
|
2155
|
+
occurred_at: z5.optional(z5.iso.datetime()),
|
|
2156
|
+
items: z5.optional(z5.array(saleItemSchema)),
|
|
2157
|
+
metadata: z5.nullish(metadataSchema),
|
|
2158
|
+
customer_name: z5.nullish(customerNameSchema),
|
|
1124
2159
|
// Re-attest when changing a filler-looking name; the server clears the
|
|
1125
2160
|
// prior attestation whenever `customer_name` changes.
|
|
1126
|
-
customer_name_placeholder_confirmed:
|
|
1127
|
-
customer_phone:
|
|
1128
|
-
customer_email:
|
|
2161
|
+
customer_name_placeholder_confirmed: z5.optional(z5.boolean()),
|
|
2162
|
+
customer_phone: z5.nullish(customerPhoneSchema),
|
|
2163
|
+
customer_email: z5.nullish(customerEmailSchema),
|
|
1129
2164
|
// NOT NULL server-side: omit to leave unchanged (explicit null is rejected).
|
|
1130
|
-
sms_consent:
|
|
2165
|
+
sms_consent: z5.optional(z5.boolean())
|
|
1131
2166
|
}).check((ctx) => refineServiceXor(ctx.value, ctx, { requireAmount: false }));
|
|
1132
2167
|
var TRACKING_RANGES = ["24h", "7d", "30d"];
|
|
1133
2168
|
var NAMED_RANGES = [
|