@aranova/tracking-next 0.27.0 → 1.1.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.
Files changed (73) hide show
  1. package/dist/blog-server.d.mts +2 -1
  2. package/dist/blog-server.d.ts +2 -1
  3. package/dist/blog-server.js +121 -98
  4. package/dist/blog-server.js.map +1 -1
  5. package/dist/blog-server.mjs +86 -63
  6. package/dist/blog-server.mjs.map +1 -1
  7. package/dist/blog.d.mts +651 -1755
  8. package/dist/blog.d.ts +651 -1755
  9. package/dist/blog.js +121 -98
  10. package/dist/blog.js.map +1 -1
  11. package/dist/blog.mjs +86 -63
  12. package/dist/blog.mjs.map +1 -1
  13. package/dist/calendar-server.d.mts +2 -2
  14. package/dist/calendar-server.d.ts +2 -2
  15. package/dist/calendar-server.js +0 -26
  16. package/dist/calendar-server.js.map +1 -1
  17. package/dist/calendar-server.mjs +0 -26
  18. package/dist/calendar-server.mjs.map +1 -1
  19. package/dist/calendar.d.mts +3 -3
  20. package/dist/calendar.d.ts +3 -3
  21. package/dist/calendar.js +227 -126
  22. package/dist/calendar.js.map +1 -1
  23. package/dist/calendar.mjs +216 -125
  24. package/dist/calendar.mjs.map +1 -1
  25. package/dist/client.d.mts +11 -4
  26. package/dist/client.d.ts +11 -4
  27. package/dist/client.js +611 -347
  28. package/dist/client.js.map +1 -1
  29. package/dist/client.mjs +611 -347
  30. package/dist/client.mjs.map +1 -1
  31. package/dist/index.d.mts +9 -8
  32. package/dist/index.d.ts +9 -8
  33. package/dist/index.js +550 -487
  34. package/dist/index.js.map +1 -1
  35. package/dist/index.mjs +539 -487
  36. package/dist/index.mjs.map +1 -1
  37. package/dist/ingest-typed-MBuMe9Pn.d.ts +883 -0
  38. package/dist/ingest-typed-UA13xTfI.d.mts +883 -0
  39. package/dist/middleware.js +0 -467
  40. package/dist/middleware.js.map +1 -1
  41. package/dist/middleware.mjs +0 -467
  42. package/dist/middleware.mjs.map +1 -1
  43. package/dist/{phone-utils-BVzSNBf1.d.mts → phone-utils-C0ds6cqZ.d.mts} +24 -78
  44. package/dist/{phone-utils-BVzSNBf1.d.ts → phone-utils-C0ds6cqZ.d.ts} +24 -78
  45. package/dist/phone.d.mts +2 -2
  46. package/dist/phone.d.ts +2 -2
  47. package/dist/phone.js +0 -464
  48. package/dist/phone.js.map +1 -1
  49. package/dist/phone.mjs +0 -464
  50. package/dist/phone.mjs.map +1 -1
  51. package/dist/{sales-IGC2tq4J.d.ts → sales-DQC815f3.d.ts} +90 -329
  52. package/dist/{sales-DQGzXSgL.d.mts → sales-w1reW_Y3.d.mts} +90 -329
  53. package/dist/sales.d.mts +3 -3
  54. package/dist/sales.d.ts +3 -3
  55. package/dist/sales.js +270 -127
  56. package/dist/sales.js.map +1 -1
  57. package/dist/sales.mjs +259 -127
  58. package/dist/sales.mjs.map +1 -1
  59. package/dist/server.d.mts +2 -2
  60. package/dist/server.d.ts +2 -2
  61. package/dist/server.js +0 -467
  62. package/dist/server.js.map +1 -1
  63. package/dist/server.mjs +0 -467
  64. package/dist/server.mjs.map +1 -1
  65. package/dist/{tracking-config-runtime-D7prdTE1.d.mts → tracking-config-runtime-C6H7ofmo.d.mts} +6 -0
  66. package/dist/{tracking-config-runtime-D7prdTE1.d.ts → tracking-config-runtime-C6H7ofmo.d.ts} +6 -0
  67. package/dist/transport-CDmGOiCq.d.ts +253 -0
  68. package/dist/transport-I_cMSFQ6.d.mts +253 -0
  69. package/package.json +2 -2
  70. package/dist/ingest-typed-BxLFlZ7N.d.mts +0 -1371
  71. package/dist/ingest-typed-ByQVRMvP.d.ts +0 -1371
  72. package/dist/transport-C-_rFSR4.d.ts +0 -721
  73. package/dist/transport-yUF5Wize.d.mts +0 -721
package/dist/index.mjs CHANGED
@@ -47,7 +47,7 @@ function normalizeEmail(raw) {
47
47
  return EMAIL_SHAPE.test(cleaned) ? cleaned : null;
48
48
  }
49
49
  function stashUserData(data, country) {
50
- const email = normalizeEmail(data.email);
50
+ const email4 = normalizeEmail(data.email);
51
51
  let phoneNumber = null;
52
52
  if (typeof data.phone === "string" && data.phone.length > 0) {
53
53
  try {
@@ -57,7 +57,7 @@ function stashUserData(data, country) {
57
57
  }
58
58
  }
59
59
  stash = {
60
- email: email ?? stash.email,
60
+ email: email4 ?? stash.email,
61
61
  phoneNumber: phoneNumber ?? stash.phoneNumber
62
62
  };
63
63
  }
@@ -66,11 +66,11 @@ function clearStashedUserData() {
66
66
  }
67
67
  function applyUserDataForConversion(explicit, country) {
68
68
  if (typeof window === "undefined" || typeof window.gtag !== "function") return false;
69
- let email = stash.email;
69
+ let email4 = stash.email;
70
70
  let phoneNumber = stash.phoneNumber;
71
71
  if (explicit) {
72
72
  const normalizedEmail = normalizeEmail(explicit.email);
73
- if (normalizedEmail) email = normalizedEmail;
73
+ if (normalizedEmail) email4 = normalizedEmail;
74
74
  if (typeof explicit.phone === "string" && explicit.phone.length > 0) {
75
75
  try {
76
76
  phoneNumber = toE164(explicit.phone, country) ?? phoneNumber;
@@ -78,10 +78,10 @@ function applyUserDataForConversion(explicit, country) {
78
78
  }
79
79
  }
80
80
  }
81
- if (email === null && phoneNumber === null) return false;
81
+ if (email4 === null && phoneNumber === null) return false;
82
82
  try {
83
83
  window.gtag("set", "user_data", {
84
- ...email !== null ? { email } : {},
84
+ ...email4 !== null ? { email: email4 } : {},
85
85
  ...phoneNumber !== null ? { phone_number: phoneNumber } : {}
86
86
  });
87
87
  return true;
@@ -213,6 +213,7 @@ var TRACKING_CAPABILITIES = [
213
213
  "consent_controls",
214
214
  "conversion_goals_auto",
215
215
  "conversion_goals_manual",
216
+ "cross_site_linker",
216
217
  "cta_click_capture",
217
218
  "form_capture",
218
219
  "phone_click_capture",
@@ -239,6 +240,9 @@ function readDomMarkers() {
239
240
  return found;
240
241
  }
241
242
 
243
+ // ../tracking-core/src/cross-site-link.ts
244
+ import * as z from "zod/mini";
245
+
242
246
  // ../tracking-core/src/tracking.ts
243
247
  var TRACKING_COOKIE_MAX_AGE_SECONDS = 7776e3;
244
248
  var TRACKING_PARAM_KEYS = [
@@ -437,10 +441,10 @@ function readStoredRecord() {
437
441
  return null;
438
442
  }
439
443
  }
440
- function writeRecord(record) {
441
- memoryRecord = record;
444
+ function writeRecord(record5) {
445
+ memoryRecord = record5;
442
446
  try {
443
- window.localStorage.setItem(LANDING_STORAGE_KEY, JSON.stringify(record));
447
+ window.localStorage.setItem(LANDING_STORAGE_KEY, JSON.stringify(record5));
444
448
  } catch {
445
449
  }
446
450
  }
@@ -462,9 +466,9 @@ function getOrCaptureLandingParams(sessionId, url) {
462
466
  if (memoryRecord && memoryRecord.session_id === sessionId) {
463
467
  return memoryRecord.params;
464
468
  }
465
- const record = { session_id: sessionId, params: captureFromUrl(url) };
466
- writeRecord(record);
467
- return record.params;
469
+ const record5 = { session_id: sessionId, params: captureFromUrl(url) };
470
+ writeRecord(record5);
471
+ return record5.params;
468
472
  }
469
473
  function buildLandingPayloadFields(sessionId, override) {
470
474
  const params = override ?? (typeof window === "undefined" ? null : getOrCaptureLandingParams(sessionId));
@@ -483,6 +487,43 @@ function buildLandingPayloadFields(sessionId, override) {
483
487
  };
484
488
  }
485
489
 
490
+ // ../tracking-core/src/cross-site-link.ts
491
+ var LINK_PARAM = "_arv";
492
+ var LINK_TOKEN_TTL_MS = 5 * 60 * 1e3;
493
+ var FUTURE_SKEW_MS = 60 * 1e3;
494
+ var CARRIED_KEYS = {
495
+ g: "gclid",
496
+ w: "wbraid",
497
+ gb: "gbraid",
498
+ f: "fbclid",
499
+ y: "ylpcid"
500
+ };
501
+ var CARRIED_ENTRIES = Object.entries(CARRIED_KEYS);
502
+ var identifier = z.string().check(z.minLength(1), z.maxLength(128));
503
+ var optionalIdentifier = z.optional(identifier);
504
+ var linkTokenSchema = z.object({
505
+ v: identifier,
506
+ s: identifier,
507
+ // Epoch ms in base36.
508
+ t: z.string().check(z.regex(/^[0-9a-z]{1,12}$/)),
509
+ g: optionalIdentifier,
510
+ w: optionalIdentifier,
511
+ gb: optionalIdentifier,
512
+ f: optionalIdentifier,
513
+ fc: optionalIdentifier,
514
+ y: optionalIdentifier
515
+ });
516
+ function stripLinkParam(url) {
517
+ try {
518
+ const parsed = new URL(url, typeof window === "undefined" ? void 0 : window.location.href);
519
+ if (!parsed.searchParams.has(LINK_PARAM)) return url;
520
+ parsed.searchParams.delete(LINK_PARAM);
521
+ return parsed.href;
522
+ } catch {
523
+ return url;
524
+ }
525
+ }
526
+
486
527
  // ../tracking-core/src/payloads.ts
487
528
  function createTrackingClientContext(surface, input = {}) {
488
529
  return {
@@ -522,6 +563,7 @@ function createTrackingSessionUpsertPayload(trackingParams, input, context) {
522
563
  };
523
564
  }
524
565
  function createTrackingEventCreatePayload(trackingParams, input, context) {
566
+ const pageUrl = input.pageUrl ?? (typeof window === "undefined" ? null : window.location.href);
525
567
  return {
526
568
  session_id: input.sessionId,
527
569
  event_type: input.eventType,
@@ -532,7 +574,7 @@ function createTrackingEventCreatePayload(trackingParams, input, context) {
532
574
  fbclid: trackingParams.fbclid,
533
575
  fbc: getFbcCookie(),
534
576
  fbp: getFbpCookie(),
535
- page_url: input.pageUrl ?? (typeof window === "undefined" ? null : window.location.href),
577
+ page_url: pageUrl === null ? null : stripLinkParam(pageUrl),
536
578
  metadata: input.metadata ?? null,
537
579
  context
538
580
  };
@@ -644,7 +686,8 @@ function parseConversionConfig(raw) {
644
686
  gtag_ids: isStringMap(obj.gtag_ids) ? obj.gtag_ids : {},
645
687
  meta_pixel_ids: isStringMap(obj.meta_pixel_ids) ? obj.meta_pixel_ids : {},
646
688
  services,
647
- goals
689
+ goals,
690
+ linked_hostnames: Array.isArray(obj.linked_hostnames) ? obj.linked_hostnames.filter((h) => typeof h === "string" && h.length > 0) : []
648
691
  };
649
692
  }
650
693
  var CACHE_PREFIX = "_aranova_cfg_";
@@ -728,6 +771,7 @@ function resolveConversionConfig(options) {
728
771
  getFiring: (key) => goalsByKey.get(key)?.firing ?? null,
729
772
  getGoal: (key) => goalsByKey.get(key) ?? null,
730
773
  listGoals: () => [...goalsByKey.values()],
774
+ linkedHostnames: () => current?.linked_hostnames ?? [],
731
775
  current: () => current,
732
776
  isReady: () => current !== null,
733
777
  onResolve: (listener) => {
@@ -841,9 +885,9 @@ function automaticThresholdMet(goal, eventType, metadata) {
841
885
  }
842
886
 
843
887
  // ../tracking-core/src/resources/intl/date.ts
844
- function formatDateInTz(iso, timeZone, opts, locale) {
845
- const date = new Date(iso);
846
- if (Number.isNaN(date.getTime())) return iso;
888
+ function formatDateInTz(iso4, timeZone, opts, locale) {
889
+ const date = new Date(iso4);
890
+ if (Number.isNaN(date.getTime())) return iso4;
847
891
  return new Intl.DateTimeFormat(locale, {
848
892
  year: "numeric",
849
893
  month: "short",
@@ -935,7 +979,7 @@ function validateConfig(config, ref) {
935
979
  function pageViewSnapshot() {
936
980
  if (typeof window === "undefined" || typeof document === "undefined") return null;
937
981
  return {
938
- href: window.location.href,
982
+ href: stripLinkParam(window.location.href),
939
983
  title: document.title || null,
940
984
  referrer: document.referrer || null
941
985
  };
@@ -1086,6 +1130,10 @@ var TrackingConfigRuntime = class {
1086
1130
  listGoals() {
1087
1131
  return this.current?.goals ?? [];
1088
1132
  }
1133
+ /** Sibling hostnames for the linker — read from the cached object even while unconfirmed. */
1134
+ linkedHostnames() {
1135
+ return this.current?.linked_hostnames ?? [];
1136
+ }
1089
1137
  async revalidateNow() {
1090
1138
  try {
1091
1139
  const headers = {};
@@ -1255,29 +1303,6 @@ function getTrackingConfigRuntime(ref, fetchImpl) {
1255
1303
  return runtime;
1256
1304
  }
1257
1305
 
1258
- // ../tracking-core/src/session.ts
1259
- var SESSION_IDLE_MS = 30 * 60 * 1e3;
1260
-
1261
- // ../tracking-core/src/events/page-view.ts
1262
- import { z } from "zod";
1263
- var pageViewMetadataSchema = z.object({
1264
- page: z.object({
1265
- title: z.string().nullable(),
1266
- path: z.string(),
1267
- search: z.string(),
1268
- hash: z.string()
1269
- }).strict(),
1270
- referrer: z.string().nullable(),
1271
- // `.nullable().optional()` — absent (undefined) OR explicit null OR a
1272
- // real viewport object. Mirrors Pydantic's `_Viewport | None = None`
1273
- // on the backend side so the drift test stays clean.
1274
- viewport: z.object({
1275
- w: z.number(),
1276
- h: z.number()
1277
- }).strict().nullable().optional()
1278
- }).strict();
1279
- var pageViewConfigSchema = z.object({}).strict();
1280
-
1281
1306
  // ../tracking-core/src/ingest.ts
1282
1307
  var API_KEY_HEADER = "X-Aranova-Api-Key";
1283
1308
  var SDK_VERSION_HEADER = "X-Aranova-Sdk-Version";
@@ -1285,187 +1310,6 @@ var SDK_PACKAGE_HEADER = "X-Aranova-Sdk-Package";
1285
1310
  var SDK_SURFACE_HEADER = "X-Aranova-Sdk-Surface";
1286
1311
  var SDK_ENVIRONMENT_HEADER = "X-Aranova-Sdk-Environment";
1287
1312
 
1288
- // ../tracking-core/src/events/cta-click.ts
1289
- import { z as z2 } from "zod";
1290
- var ctaClickMetadataSchema = z2.object({
1291
- cta_name: z2.string(),
1292
- page: z2.object({
1293
- path: z2.string()
1294
- }).strict(),
1295
- section: z2.string().nullable().optional(),
1296
- destination_url: z2.string().nullable().optional(),
1297
- // Set by auto-capture (and available to manual callers): the link target
1298
- // and a short element descriptor (tag#id) for tying clicks to specific UI.
1299
- href: z2.string().nullable().optional(),
1300
- element: z2.string().nullable().optional()
1301
- }).strict();
1302
- var ctaClickConfigSchema = z2.object({
1303
- autoCapture: z2.object({
1304
- selector: z2.string().optional()
1305
- }).strict().optional()
1306
- }).strict();
1307
-
1308
- // ../tracking-core/src/events/sdk-heartbeat.ts
1309
- import { z as z3 } from "zod";
1310
- var sdkHeartbeatTriggersSchema = z3.object({
1311
- automatic: z3.array(z3.string()),
1312
- manual: z3.array(z3.string())
1313
- }).strict();
1314
- var sdkHeartbeatMetadataSchema = z3.object({
1315
- sdk_version: z3.string(),
1316
- package_name: z3.string().nullable(),
1317
- surface: z3.enum(["next", "react", "script"]),
1318
- triggers: sdkHeartbeatTriggersSchema,
1319
- trigger_config: z3.record(z3.string(), z3.record(z3.string(), z3.unknown())).nullable().optional(),
1320
- configured_gtag_ids: z3.record(z3.string(), z3.string()).nullable().optional(),
1321
- // Site whose config object the SDK resolves; null on a legacy business ref.
1322
- config_site_id: z3.string().uuid().nullable().optional()
1323
- }).strict();
1324
- var sdkHeartbeatConfigSchema = z3.object({}).strict();
1325
-
1326
- // ../tracking-core/src/events/form-start.ts
1327
- import { z as z4 } from "zod";
1328
- var formStartMetadataSchema = z4.object({
1329
- form: z4.object({
1330
- id: z4.string(),
1331
- action: z4.string().nullable()
1332
- }).strict(),
1333
- page: z4.object({
1334
- path: z4.string()
1335
- }).strict()
1336
- }).strict();
1337
- var formStartConfigSchema = z4.object({
1338
- selector: z4.string().optional()
1339
- }).strict();
1340
-
1341
- // ../tracking-core/src/events/form-submit.ts
1342
- import { z as z5 } from "zod";
1343
- var jsonValueSchema = z5.lazy(
1344
- () => z5.union([
1345
- z5.string(),
1346
- z5.number().finite(),
1347
- z5.boolean(),
1348
- z5.null(),
1349
- z5.array(jsonValueSchema),
1350
- z5.record(jsonValueSchema)
1351
- ])
1352
- );
1353
- var formSubmitMetadataSchema = z5.object({
1354
- form: z5.object({
1355
- id: z5.string(),
1356
- action: z5.string().nullable(),
1357
- fields: z5.array(
1358
- z5.object({
1359
- name: z5.string(),
1360
- type: z5.string(),
1361
- label: z5.string().nullable(),
1362
- value: jsonValueSchema
1363
- }).strict()
1364
- ).optional()
1365
- }).strict(),
1366
- page: z5.object({
1367
- path: z5.string()
1368
- }).strict()
1369
- }).strict();
1370
- var formSubmitConfigSchema = z5.object({}).strict();
1371
-
1372
- // ../tracking-core/src/events/multi-page-session.ts
1373
- import { z as z6 } from "zod";
1374
- var multiPageSessionMetadataSchema = z6.object({
1375
- page_count: z6.number().int().min(2),
1376
- page: z6.object({
1377
- path: z6.string()
1378
- }).strict()
1379
- }).strict();
1380
- var multiPageSessionConfigSchema = z6.object({
1381
- pageThreshold: z6.number().int().min(2)
1382
- }).strict();
1383
-
1384
- // ../tracking-core/src/events/page-exit.ts
1385
- import { z as z7 } from "zod";
1386
- var pageExitMetadataSchema = z7.object({
1387
- dwell_ms: z7.number().int().min(0),
1388
- // null = left without any scroll signal; floor is 0 so a valid 0% is never
1389
- // rejected (a single bad field 422s the whole keepalive beacon batch).
1390
- max_scroll_percent: z7.number().int().min(0).max(100).nullable(),
1391
- // The gating baseline: the fraction of the page visible at load with
1392
- // zero scrolling — or, for pages that grew after the post-paint snapshot
1393
- // (skeleton/streaming renders), the first-scroll position that
1394
- // established it. null = page had no scrollable range, or the segment
1395
- // ended before the snapshot. `.optional()` is load-bearing: SDK builds
1396
- // predating this field keep POSTing page_exit without the key —
1397
- // requiring it would 422 whole keepalive beacon batches.
1398
- scroll_baseline_percent: z7.number().int().min(0).max(100).nullable().optional(),
1399
- page: z7.object({
1400
- path: z7.string()
1401
- }).strict()
1402
- }).strict();
1403
- var pageExitConfigSchema = z7.object({}).strict();
1404
-
1405
- // ../tracking-core/src/events/phone-click.ts
1406
- import { z as z8 } from "zod";
1407
- var phoneClickMetadataSchema = z8.object({
1408
- phone_number: z8.string(),
1409
- page: z8.object({
1410
- path: z8.string()
1411
- }).strict(),
1412
- section: z8.string().nullable().optional()
1413
- }).strict();
1414
- var phoneClickConfigSchema = z8.object({
1415
- autoCapture: z8.object({
1416
- selector: z8.string().optional()
1417
- }).strict().optional()
1418
- }).strict();
1419
-
1420
- // ../tracking-core/src/events/scroll-depth.ts
1421
- import { z as z9 } from "zod";
1422
- var scrollDepthMetadataSchema = z9.object({
1423
- depth_percent: z9.number().int().min(1).max(100),
1424
- page: z9.object({
1425
- path: z9.string()
1426
- }).strict()
1427
- }).strict();
1428
- var scrollDepthConfigSchema = z9.object({
1429
- thresholds: z9.array(z9.number().int().min(1).max(100)).min(1)
1430
- }).strict();
1431
-
1432
- // ../tracking-core/src/events/specific-page-visit.ts
1433
- import { z as z10 } from "zod";
1434
- var PAGE_IDENTITY_MAX_LENGTH = 64;
1435
- var PAGE_IDENTITY_PATTERN = /^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/;
1436
- var pageIdentitySchema = z10.string().max(PAGE_IDENTITY_MAX_LENGTH).regex(PAGE_IDENTITY_PATTERN, {
1437
- message: "page identity must be lowercase snake_case, start with a letter, and contain at most 64 characters"
1438
- });
1439
- var specificPageNameSchema = pageIdentitySchema;
1440
- var specificPageVisitMetadataSchema = z10.object({
1441
- page_name: specificPageNameSchema,
1442
- page: z10.object({
1443
- path: z10.string()
1444
- }).strict()
1445
- }).strict();
1446
- var specificPageVisitConfigSchema = z10.object({
1447
- pages: z10.array(
1448
- z10.object({
1449
- name: specificPageNameSchema,
1450
- pathPattern: z10.custom((value) => value instanceof RegExp, {
1451
- message: "pathPattern must be a RegExp"
1452
- })
1453
- }).strict()
1454
- ).min(1)
1455
- }).strict();
1456
-
1457
- // ../tracking-core/src/events/time-on-site.ts
1458
- import { z as z11 } from "zod";
1459
- var timeOnSiteMetadataSchema = z11.object({
1460
- duration_ms: z11.number().int().nonnegative(),
1461
- page: z11.object({
1462
- path: z11.string()
1463
- }).strict()
1464
- }).strict();
1465
- var timeOnSiteConfigSchema = z11.object({
1466
- thresholdSeconds: z11.number().int().positive()
1467
- }).strict();
1468
-
1469
1313
  // ../tracking-core/src/events/semantics.ts
1470
1314
  var EVENT_SEMANTICS = {
1471
1315
  page_view: {
@@ -1533,88 +1377,24 @@ var EVENT_SEMANTICS = {
1533
1377
  category: "engagement",
1534
1378
  outcomeRole: "engagement",
1535
1379
  clientVisibility: "simple"
1380
+ },
1381
+ site_link_click: {
1382
+ label: "Left for sibling site",
1383
+ category: "page",
1384
+ outcomeRole: "navigation",
1385
+ clientVisibility: "detailed"
1386
+ },
1387
+ site_link_arrival: {
1388
+ label: "Arrived from sibling site",
1389
+ category: "page",
1390
+ outcomeRole: "navigation",
1391
+ clientVisibility: "simple"
1536
1392
  }
1537
1393
  };
1538
1394
  function getEventSemantics(eventName) {
1539
1395
  return eventName in EVENT_SEMANTICS ? EVENT_SEMANTICS[eventName] : null;
1540
1396
  }
1541
1397
 
1542
- // ../tracking-core/src/events/registry.ts
1543
- var EVENT_REGISTRY = {
1544
- // --- automatic triggers ---
1545
- page_view: {
1546
- kind: "automatic",
1547
- semantics: EVENT_SEMANTICS.page_view,
1548
- metadataSchema: pageViewMetadataSchema,
1549
- configSchema: pageViewConfigSchema
1550
- },
1551
- time_on_site: {
1552
- kind: "automatic",
1553
- semantics: EVENT_SEMANTICS.time_on_site,
1554
- metadataSchema: timeOnSiteMetadataSchema,
1555
- configSchema: timeOnSiteConfigSchema
1556
- },
1557
- specific_page_visit: {
1558
- kind: "automatic",
1559
- semantics: EVENT_SEMANTICS.specific_page_visit,
1560
- metadataSchema: specificPageVisitMetadataSchema,
1561
- configSchema: specificPageVisitConfigSchema
1562
- },
1563
- scroll_depth: {
1564
- kind: "automatic",
1565
- semantics: EVENT_SEMANTICS.scroll_depth,
1566
- metadataSchema: scrollDepthMetadataSchema,
1567
- configSchema: scrollDepthConfigSchema
1568
- },
1569
- multi_page_session: {
1570
- kind: "automatic",
1571
- semantics: EVENT_SEMANTICS.multi_page_session,
1572
- metadataSchema: multiPageSessionMetadataSchema,
1573
- configSchema: multiPageSessionConfigSchema
1574
- },
1575
- form_start: {
1576
- kind: "automatic",
1577
- semantics: EVENT_SEMANTICS.form_start,
1578
- metadataSchema: formStartMetadataSchema,
1579
- configSchema: formStartConfigSchema
1580
- },
1581
- // --- SDK-internal automatic (not consumer-configurable) ---
1582
- sdk_heartbeat: {
1583
- kind: "automatic",
1584
- semantics: EVENT_SEMANTICS.sdk_heartbeat,
1585
- metadataSchema: sdkHeartbeatMetadataSchema,
1586
- configSchema: sdkHeartbeatConfigSchema
1587
- },
1588
- page_exit: {
1589
- kind: "automatic",
1590
- semantics: EVENT_SEMANTICS.page_exit,
1591
- metadataSchema: pageExitMetadataSchema,
1592
- configSchema: pageExitConfigSchema
1593
- },
1594
- // --- manual triggers ---
1595
- form_submit: {
1596
- kind: "manual",
1597
- semantics: EVENT_SEMANTICS.form_submit,
1598
- metadataSchema: formSubmitMetadataSchema,
1599
- configSchema: formSubmitConfigSchema
1600
- },
1601
- phone_click: {
1602
- kind: "manual",
1603
- semantics: EVENT_SEMANTICS.phone_click,
1604
- metadataSchema: phoneClickMetadataSchema,
1605
- configSchema: phoneClickConfigSchema
1606
- },
1607
- cta_click: {
1608
- kind: "manual",
1609
- semantics: EVENT_SEMANTICS.cta_click,
1610
- metadataSchema: ctaClickMetadataSchema,
1611
- configSchema: ctaClickConfigSchema
1612
- }
1613
- };
1614
- var ALL_AUTOMATIC_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.kind === "automatic").map(([name]) => name);
1615
- var ALL_MANUAL_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.kind === "manual").map(([name]) => name);
1616
- var ALL_LEAD_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.semantics.outcomeRole === "lead").map(([name]) => name);
1617
-
1618
1398
  // ../tracking-core/src/resources/http/errors.ts
1619
1399
  var AranovaApiError = class extends Error {
1620
1400
  constructor(message, options) {
@@ -1652,9 +1432,9 @@ async function apiRequest(config, method, path, body, extraHeaders) {
1652
1432
  try {
1653
1433
  const parsed = await response.json();
1654
1434
  if (parsed && typeof parsed === "object") {
1655
- const record = parsed;
1656
- if (typeof record.detail === "string") detail = record.detail;
1657
- if (typeof record.code === "string") code = record.code;
1435
+ const record5 = parsed;
1436
+ if (typeof record5.detail === "string") detail = record5.detail;
1437
+ if (typeof record5.code === "string") code = record5.code;
1658
1438
  }
1659
1439
  } catch {
1660
1440
  }
@@ -1703,7 +1483,7 @@ function fireRecordedConversions(firing, input, recorded, sale, currency) {
1703
1483
  }
1704
1484
  function createSalesClient(config) {
1705
1485
  if (config.firing) registerCapability("conversion_goals_manual");
1706
- async function record(input) {
1486
+ async function record5(input) {
1707
1487
  const currency = input.currency ?? config.defaultCurrency;
1708
1488
  if (!currency) {
1709
1489
  throw new Error(
@@ -1729,9 +1509,9 @@ function createSalesClient(config) {
1729
1509
  return sale;
1730
1510
  }
1731
1511
  return {
1732
- record,
1512
+ record: record5,
1733
1513
  // recordSale is the intent-revealing alias — same behavior, clearer call site.
1734
- recordSale: record,
1514
+ recordSale: record5,
1735
1515
  trackConversion(key, options) {
1736
1516
  if (config.firing && "fireConversion" in config.firing) {
1737
1517
  if (options?.userData && getConsentState() !== "denied") stashUserData(options.userData);
@@ -1850,115 +1630,269 @@ function createSalesClient(config) {
1850
1630
  }
1851
1631
 
1852
1632
  // ../tracking-core/src/resources/sales/schema.ts
1853
- import { z as z12 } from "zod";
1854
- var SUPPORTED_CURRENCIES = ["USD", "CAD"];
1855
- var TRACKING_ENVIRONMENTS = ["production", "development"];
1856
- var currencySchema = z12.enum(SUPPORTED_CURRENCIES);
1857
- var centsSchema = z12.number().int().nonnegative();
1858
- var quantitySchema = z12.string().regex(/^\d+(\.\d{1,3})?$/);
1859
- var metadataSchema = z12.record(z12.unknown());
1860
- var saleItemSchema = z12.object({
1861
- external_item_id: z12.string().nullable().optional(),
1862
- name: z12.string().nullable().optional(),
1863
- category: z12.string().nullable().optional(),
1864
- quantity: quantitySchema,
1865
- unit_price_cents: centsSchema,
1866
- // Non-negativity validated on the wire — same contract as the other cents
1867
- // fields — and backstopped by the DB CHECK.
1868
- unit_cost_cents: centsSchema.nullable().optional()
1869
- }).strict();
1870
- var saleServiceSchema = z12.object({
1871
- service: z12.string(),
1872
- amount_cents: centsSchema
1873
- }).strict();
1874
- var customerNameSchema = z12.string().max(200);
1875
- var customerPhoneSchema = z12.string().max(64);
1876
- var customerEmailSchema = z12.string().max(320).email();
1633
+ import * as z3 from "zod/mini";
1634
+
1635
+ // ../tracking-core/src/resources/sales/generated/zod.gen.ts
1636
+ import * as z2 from "zod/mini";
1637
+ var zErrorCode = z2.enum([
1638
+ "missing_credentials",
1639
+ "invalid_api_key",
1640
+ "not_authenticated",
1641
+ "wrong_key_type",
1642
+ "origin_missing",
1643
+ "origin_not_allowed",
1644
+ "capability_denied",
1645
+ "session_required",
1646
+ "operator_only",
1647
+ "cross_tenant",
1648
+ "business_id_required",
1649
+ "bad_request",
1650
+ "not_found",
1651
+ "conflict",
1652
+ "incompatible_payload",
1653
+ "repeat_confirmation_required",
1654
+ "idempotency_conflict",
1655
+ "validation_error",
1656
+ "unknown_service",
1657
+ "invalid_sale_properties",
1658
+ "invalid_cursor",
1659
+ "rate_limited",
1660
+ "internal_error"
1661
+ ]);
1662
+ var zSaleItemEntitySchema = z2.object({
1663
+ category: z2.nullable(z2.string()),
1664
+ external_item_id: z2.nullable(z2.string()),
1665
+ id: z2.uuid(),
1666
+ name: z2.nullable(z2.string()),
1667
+ quantity: z2.string().check(z2.regex(/^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$/)),
1668
+ unit_cost_cents: z2.nullable(z2.int()),
1669
+ unit_price_cents: z2.int()
1670
+ });
1671
+ var zSaleItemInputSchema = z2.strictObject({
1672
+ category: z2.nullish(z2.string()),
1673
+ external_item_id: z2.nullish(z2.string()),
1674
+ name: z2.nullish(z2.string()),
1675
+ quantity: z2.string().check(z2.regex(/^\d+(\.\d{1,3})?$/)),
1676
+ unit_cost_cents: z2.nullish(z2.int().check(z2.gte(0))),
1677
+ unit_price_cents: z2.int().check(z2.gte(0))
1678
+ });
1679
+ var zSaleServiceEntitySchema = z2.object({
1680
+ amount_cents: z2.int(),
1681
+ id: z2.uuid(),
1682
+ mapped: z2.nullable(z2.boolean()),
1683
+ service_id: z2.uuid(),
1684
+ service_key: z2.string(),
1685
+ service_label: z2.string()
1686
+ });
1687
+ var zSaleServiceInputSchema = z2.strictObject({
1688
+ amount_cents: z2.int().check(z2.gte(0)),
1689
+ service: z2.string()
1690
+ });
1691
+ var zSmsAutomationState = z2.enum([
1692
+ "needs_check",
1693
+ "failed",
1694
+ "undelivered",
1695
+ "blocked_opted_out",
1696
+ "withheld",
1697
+ "queued",
1698
+ "sent",
1699
+ "delivered",
1700
+ "eligible",
1701
+ "not_applicable"
1702
+ ]);
1703
+ var zSmsWithheldReason = z2.enum([
1704
+ "automation_disabled",
1705
+ "sms_disabled",
1706
+ "no_phone",
1707
+ "no_consent",
1708
+ "no_customer_identity",
1709
+ "missing_customer_name",
1710
+ "placeholder_customer_name",
1711
+ "opted_out",
1712
+ "already_messaged",
1713
+ "sender_not_ready",
1714
+ "missing_review_url",
1715
+ "no_handler",
1716
+ "dispatch_already_recorded",
1717
+ "text_back_disabled",
1718
+ "number_not_active",
1719
+ "a2p_registration_required",
1720
+ "alert_recipient_cannot_receive_sms",
1721
+ "line_type_unresolved"
1722
+ ]);
1723
+ var zSaleSmsStatusSchema = z2.object({
1724
+ can_send_now: z2._default(z2.boolean(), false),
1725
+ last_message_at: z2.nullable(z2.iso.datetime({ offset: true })),
1726
+ reason_detail: z2.nullable(z2.string()),
1727
+ state: zSmsAutomationState,
1728
+ suppressed_by_other_sale: z2._default(z2.boolean(), false),
1729
+ withheld_reason: z2.nullable(zSmsWithheldReason)
1730
+ });
1731
+ var zSupportedCurrency = z2.enum(["USD", "CAD"]);
1732
+ var zTrackingEnvironment = z2.enum(["production", "development"]);
1733
+ var zSaleCreateSchema = z2.strictObject({
1734
+ amount_total_cents: z2.nullish(z2.int().check(z2.gte(0))),
1735
+ currency: zSupportedCurrency,
1736
+ customer_email: z2.nullish(z2.email().check(z2.maxLength(320))),
1737
+ customer_name: z2.nullish(z2.string().check(z2.maxLength(200))),
1738
+ customer_phone: z2.nullish(z2.string().check(z2.maxLength(64))),
1739
+ description: z2.nullish(z2.string()),
1740
+ environment: z2._default(z2.optional(zTrackingEnvironment), "production"),
1741
+ external_id: z2.nullish(z2.string()),
1742
+ items: z2.optional(z2.array(zSaleItemInputSchema)),
1743
+ metadata: z2.nullish(z2.record(z2.string(), z2.unknown())),
1744
+ occurred_at: z2.iso.datetime({ offset: true }),
1745
+ service: z2.nullish(z2.string()),
1746
+ services: z2.nullish(z2.array(zSaleServiceInputSchema)),
1747
+ sms_consent: z2.nullish(z2.boolean())
1748
+ });
1749
+ var zValidationError = z2.object({
1750
+ ctx: z2.optional(z2.record(z2.string(), z2.unknown())),
1751
+ input: z2.optional(z2.unknown()),
1752
+ loc: z2.array(z2.union([z2.string(), z2.int()])),
1753
+ msg: z2.string(),
1754
+ type: z2.string()
1755
+ });
1756
+ var zHttpValidationError = z2.object({
1757
+ detail: z2.optional(z2.array(zValidationError))
1758
+ });
1759
+ var zValidationErrorItem = z2.object({
1760
+ loc: z2.array(z2.union([z2.string(), z2.int()])),
1761
+ msg: z2.string(),
1762
+ type: z2.string()
1763
+ });
1764
+ var zApiErrorSchema = z2.object({
1765
+ code: zErrorCode,
1766
+ context: z2._default(z2.nullish(z2.record(z2.string(), z2.unknown())), null),
1767
+ detail: z2.string(),
1768
+ errors: z2._default(z2.nullish(z2.array(zValidationErrorItem)), null),
1769
+ request_id: z2._default(z2.nullish(z2.string()), null)
1770
+ });
1771
+ var zWritebackEmailSource = z2.enum(["NONE", "SALE", "CUSTOMER", "HARVESTED"]);
1772
+ var zWritebackEnrichmentStatus = z2.enum(["NONE", "MATCHED", "AMBIGUOUS"]);
1773
+ var zWritebackSaleUploadCounts = z2.object({
1774
+ failed: z2._default(z2.int(), 0),
1775
+ pending: z2._default(z2.int(), 0),
1776
+ skipped: z2._default(z2.int(), 0),
1777
+ submitted: z2._default(z2.int(), 0),
1778
+ total: z2._default(z2.int(), 0),
1779
+ uploaded: z2._default(z2.int(), 0)
1780
+ });
1781
+ var zSaleWritebackStatusSchema = z2.object({
1782
+ blocked_reason: z2.nullable(z2.string()),
1783
+ can_dispatch: z2._default(z2.boolean(), false),
1784
+ email_source: z2.nullable(zWritebackEmailSource),
1785
+ enrichment_status: z2.nullable(zWritebackEnrichmentStatus),
1786
+ gclid_attached: z2._default(z2.boolean(), false),
1787
+ identifiers_sent: z2.nullable(z2.string()),
1788
+ mapped_service_ids: z2.array(z2.uuid()),
1789
+ matched_submit_count: z2.nullable(z2.int()),
1790
+ needs_force: z2._default(z2.boolean(), false),
1791
+ rollup: z2.enum([
1792
+ "failed",
1793
+ "skipped",
1794
+ "pending",
1795
+ "submitted",
1796
+ "uploaded",
1797
+ "not_uploaded",
1798
+ "out_of_window",
1799
+ "blocked"
1800
+ ]),
1801
+ stale: z2._default(z2.boolean(), false),
1802
+ uncovered_service_ids: z2.array(z2.uuid()),
1803
+ uploads: zWritebackSaleUploadCounts
1804
+ });
1805
+ var zSaleEntitySchema = z2.object({
1806
+ amount_total_cents: z2.int(),
1807
+ business_id: z2.uuid(),
1808
+ business_name: z2.nullable(z2.string()),
1809
+ created_at: z2.iso.datetime({ offset: true }),
1810
+ currency: z2.string(),
1811
+ customer_email: z2.nullable(z2.string()),
1812
+ customer_name: z2.nullable(z2.string()),
1813
+ customer_name_placeholder_confirmed: z2._default(z2.boolean(), false),
1814
+ customer_name_placeholder_confirmed_at: z2.nullable(z2.iso.datetime({ offset: true })),
1815
+ customer_phone: z2.nullable(z2.string()),
1816
+ description: z2.nullable(z2.string()),
1817
+ environment: zTrackingEnvironment,
1818
+ external_id: z2.nullable(z2.string()),
1819
+ id: z2.uuid(),
1820
+ items: z2.array(zSaleItemEntitySchema),
1821
+ metadata: z2.nullable(z2.record(z2.string(), z2.unknown())),
1822
+ occurred_at: z2.iso.datetime({ offset: true }),
1823
+ service_id: z2.nullable(z2.uuid()),
1824
+ service_key: z2.nullable(z2.string()),
1825
+ service_label: z2.nullable(z2.string()),
1826
+ services: z2.array(zSaleServiceEntitySchema),
1827
+ sms_automation: z2.nullable(zSaleSmsStatusSchema),
1828
+ sms_consent: z2._default(z2.boolean(), false),
1829
+ sms_consent_granted_at: z2.nullable(z2.iso.datetime({ offset: true })),
1830
+ updated_at: z2.iso.datetime({ offset: true }),
1831
+ writeback: z2.nullable(zSaleWritebackStatusSchema)
1832
+ });
1833
+
1834
+ // ../tracking-core/src/resources/sales/schema.ts
1835
+ var saleItemSchema = zSaleItemInputSchema;
1836
+ var saleServiceSchema = zSaleServiceInputSchema;
1837
+ var currencySchema = zSupportedCurrency;
1838
+ var SUPPORTED_CURRENCIES = currencySchema.options;
1839
+ var centsSchema = z3.int().check(z3.gte(0));
1840
+ var metadataSchema = z3.record(z3.string(), z3.unknown());
1841
+ var customerNameSchema = z3.string().check(z3.maxLength(200));
1842
+ var customerPhoneSchema = z3.string().check(z3.maxLength(64));
1843
+ var customerEmailSchema = z3.email().check(z3.maxLength(320));
1844
+ function addIssue(ctx, path, message) {
1845
+ ctx.issues.push({ code: "custom", input: ctx.value, path, message });
1846
+ }
1877
1847
  function refineServiceXor(val, ctx, { requireAmount }) {
1878
1848
  if (val.services != null) {
1879
1849
  if (val.service != null) {
1880
- ctx.addIssue({
1881
- code: z12.ZodIssueCode.custom,
1882
- message: "pass either `service` or `services`, not both",
1883
- path: ["services"]
1884
- });
1850
+ addIssue(ctx, ["services"], "pass either `service` or `services`, not both");
1885
1851
  }
1886
1852
  if (val.services.length === 0) {
1887
- ctx.addIssue({
1888
- code: z12.ZodIssueCode.custom,
1889
- message: "`services` must not be empty",
1890
- path: ["services"]
1891
- });
1853
+ addIssue(ctx, ["services"], "`services` must not be empty");
1892
1854
  }
1893
1855
  const keys = val.services.map((s) => s.service);
1894
1856
  if (new Set(keys).size !== keys.length) {
1895
- ctx.addIssue({
1896
- code: z12.ZodIssueCode.custom,
1897
- message: "`services` must not list the same service more than once",
1898
- path: ["services"]
1899
- });
1857
+ addIssue(ctx, ["services"], "`services` must not list the same service more than once");
1900
1858
  }
1901
1859
  if (val.amount_total_cents != null) {
1902
1860
  const sum = val.services.reduce((acc, s) => acc + s.amount_cents, 0);
1903
1861
  if (val.amount_total_cents !== sum) {
1904
- ctx.addIssue({
1905
- code: z12.ZodIssueCode.custom,
1906
- message: "amount_total_cents must equal the sum of the services amounts (omit it to derive it automatically)",
1907
- path: ["amount_total_cents"]
1908
- });
1862
+ addIssue(
1863
+ ctx,
1864
+ ["amount_total_cents"],
1865
+ "amount_total_cents must equal the sum of the services amounts (omit it to derive it automatically)"
1866
+ );
1909
1867
  }
1910
1868
  }
1911
1869
  } else if (requireAmount && val.amount_total_cents == null) {
1912
- ctx.addIssue({
1913
- code: z12.ZodIssueCode.custom,
1914
- message: "amount_total_cents is required unless `services` is provided",
1915
- path: ["amount_total_cents"]
1916
- });
1870
+ addIssue(
1871
+ ctx,
1872
+ ["amount_total_cents"],
1873
+ "amount_total_cents is required unless `services` is provided"
1874
+ );
1917
1875
  }
1918
1876
  }
1919
- var saleCreateSchema = z12.object({
1920
- external_id: z12.string().nullable().optional(),
1921
- description: z12.string().nullable().optional(),
1922
- service: z12.string().nullable().optional(),
1923
- services: z12.array(saleServiceSchema).nullable().optional(),
1924
- currency: currencySchema,
1925
- // Optional only because the plural `services` form derives it from the sum
1926
- // (see refineServiceXor); the singular/serviceless path still requires it.
1927
- amount_total_cents: centsSchema.nullable().optional(),
1928
- occurred_at: z12.string().datetime(),
1929
- environment: z12.enum(TRACKING_ENVIRONMENTS).default("production"),
1930
- items: z12.array(saleItemSchema).default([]),
1931
- metadata: metadataSchema.nullable().optional(),
1932
- customer_name: customerNameSchema.nullable().optional(),
1933
- customer_phone: customerPhoneSchema.nullable().optional(),
1934
- customer_email: customerEmailSchema.nullable().optional(),
1935
- // CASL consent attestation: the customer agreed to receive SMS. Recorded
1936
- // with a timestamp server-side; every SMS send path gates on it.
1937
- //
1938
- // Tri-state: omit it (or send null) to let the server apply the business's
1939
- // configured default-opt-in policy, honouring a returning customer's
1940
- // remembered preference. Send an explicit boolean to assert consent state
1941
- // yourself — `false` records a deliberate opt-out.
1942
- sms_consent: z12.boolean().nullable().optional()
1943
- }).strict().superRefine((val, ctx) => refineServiceXor(val, ctx, { requireAmount: true }));
1944
- var saleUpdateSchema = z12.object({
1945
- description: z12.string().nullable().optional(),
1946
- service: z12.string().nullable().optional(),
1947
- services: z12.array(saleServiceSchema).nullable().optional(),
1948
- currency: currencySchema.optional(),
1949
- amount_total_cents: centsSchema.optional(),
1950
- occurred_at: z12.string().datetime().optional(),
1951
- items: z12.array(saleItemSchema).optional(),
1952
- metadata: metadataSchema.nullable().optional(),
1953
- customer_name: customerNameSchema.nullable().optional(),
1877
+ var saleCreateSchema = z3.extend(zSaleCreateSchema, { items: z3._default(z3.array(saleItemSchema), []) }).check((ctx) => refineServiceXor(ctx.value, ctx, { requireAmount: true }));
1878
+ var saleUpdateSchema = z3.strictObject({
1879
+ description: z3.nullish(z3.string()),
1880
+ service: z3.nullish(z3.string()),
1881
+ services: z3.nullish(z3.array(saleServiceSchema)),
1882
+ currency: z3.optional(currencySchema),
1883
+ amount_total_cents: z3.optional(centsSchema),
1884
+ occurred_at: z3.optional(z3.iso.datetime()),
1885
+ items: z3.optional(z3.array(saleItemSchema)),
1886
+ metadata: z3.nullish(metadataSchema),
1887
+ customer_name: z3.nullish(customerNameSchema),
1954
1888
  // Re-attest when changing a filler-looking name; the server clears the
1955
1889
  // prior attestation whenever `customer_name` changes.
1956
- customer_name_placeholder_confirmed: z12.boolean().optional(),
1957
- customer_phone: customerPhoneSchema.nullable().optional(),
1958
- customer_email: customerEmailSchema.nullable().optional(),
1890
+ customer_name_placeholder_confirmed: z3.optional(z3.boolean()),
1891
+ customer_phone: z3.nullish(customerPhoneSchema),
1892
+ customer_email: z3.nullish(customerEmailSchema),
1959
1893
  // NOT NULL server-side: omit to leave unchanged (explicit null is rejected).
1960
- sms_consent: z12.boolean().optional()
1961
- }).strict().superRefine((val, ctx) => refineServiceXor(val, ctx, { requireAmount: false }));
1894
+ sms_consent: z3.optional(z3.boolean())
1895
+ }).check((ctx) => refineServiceXor(ctx.value, ctx, { requireAmount: false }));
1962
1896
  var TRACKING_RANGES = ["24h", "7d", "30d"];
1963
1897
  var NAMED_RANGES = [
1964
1898
  "today",
@@ -2039,8 +1973,8 @@ function instantFromWallClock(timeZone, year, month, day, hour = 0, minute = 0)
2039
1973
  const corrected = naive - offsetMinutesAt(firstGuess, timeZone) * 6e4;
2040
1974
  return new Date(corrected);
2041
1975
  }
2042
- function localDateKey(iso, timeZone) {
2043
- const p = partsInTz(new Date(iso), timeZone);
1976
+ function localDateKey(iso4, timeZone) {
1977
+ const p = partsInTz(new Date(iso4), timeZone);
2044
1978
  const pad = (n) => String(n).padStart(2, "0");
2045
1979
  return `${p.year}-${pad(p.month)}-${pad(p.day)}`;
2046
1980
  }
@@ -2095,7 +2029,167 @@ function isCalendarError(error, code) {
2095
2029
  }
2096
2030
 
2097
2031
  // ../tracking-core/src/resources/calendar/schema.ts
2098
- import { z as z13 } from "zod";
2032
+ import * as z5 from "zod/mini";
2033
+
2034
+ // ../tracking-core/src/resources/calendar/generated/zod.gen.ts
2035
+ import * as z4 from "zod/mini";
2036
+ var zBookingAttendee = z4.strictObject({
2037
+ display_name: z4.nullish(z4.string().check(z4.maxLength(200))),
2038
+ email: z4.email().check(z4.maxLength(320)),
2039
+ optional: z4._default(z4.optional(z4.boolean()), false)
2040
+ });
2041
+ var zBookingCancelSchema = z4.strictObject({
2042
+ notify_attendees: z4._default(z4.optional(z4.boolean()), true),
2043
+ reason: z4.nullish(z4.string().check(z4.maxLength(500)))
2044
+ });
2045
+ var zBookingCustomerInput = z4.strictObject({
2046
+ email: z4.email().check(z4.maxLength(320)),
2047
+ name: z4.nullish(z4.string().check(z4.maxLength(200))),
2048
+ phone: z4.nullish(z4.string().check(z4.maxLength(64))),
2049
+ sms_consent: z4._default(z4.optional(z4.boolean()), false)
2050
+ });
2051
+ var zBookingCustomerOutput = z4.strictObject({
2052
+ email: z4.email().check(z4.maxLength(320)),
2053
+ name: z4.nullable(z4.string().check(z4.maxLength(200))),
2054
+ phone: z4.nullable(z4.string().check(z4.maxLength(64))),
2055
+ sms_consent: z4._default(z4.boolean(), false)
2056
+ });
2057
+ var zBookingRescheduleSchema = z4.strictObject({
2058
+ duration_minutes: z4.nullish(z4.int().check(z4.gt(0), z4.lte(1440))),
2059
+ end_at: z4.nullish(z4.iso.datetime({ offset: true })),
2060
+ notify_attendees: z4._default(z4.optional(z4.boolean()), true),
2061
+ reason: z4.nullish(z4.string().check(z4.maxLength(500))),
2062
+ start_at: z4.iso.datetime({ offset: true }),
2063
+ time_zone: z4.string().check(z4.minLength(1), z4.maxLength(64), z4.regex(/^[A-Za-z0-9_+\-\/]+$/))
2064
+ });
2065
+ var zBookingResponse = z4.strictObject({
2066
+ appointment_type: z4.nullable(z4.string()),
2067
+ calendar_key: z4.string(),
2068
+ customer: zBookingCustomerOutput,
2069
+ end_at: z4.iso.datetime({ offset: true }),
2070
+ google_html_link: z4.nullable(z4.string()),
2071
+ google_sync_state: z4.string(),
2072
+ id: z4.string(),
2073
+ manage_token: z4.nullable(z4.string()),
2074
+ meet_url: z4.nullable(z4.string()),
2075
+ start_at: z4.iso.datetime({ offset: true }),
2076
+ status: z4.string(),
2077
+ time_zone: z4.string(),
2078
+ title: z4.string()
2079
+ });
2080
+ var zBookingSource = z4.enum(["website", "phone", "walk_in", "import", "operator"]);
2081
+ var zBookingMetadata = z4.strictObject({
2082
+ custom: z4.nullish(
2083
+ z4.record(z4.string(), z4.nullable(z4.union([z4.string(), z4.int(), z4.number(), z4.boolean()])))
2084
+ ),
2085
+ fbclid: z4.nullish(z4.string().check(z4.maxLength(256))),
2086
+ gclid: z4.nullish(z4.string().check(z4.maxLength(256))),
2087
+ landing_page: z4.nullish(z4.string().check(z4.maxLength(2048))),
2088
+ notes: z4.nullish(z4.string().check(z4.maxLength(2e3))),
2089
+ referrer: z4.nullish(z4.string().check(z4.maxLength(2048))),
2090
+ schema_version: z4._default(z4.optional(z4.int()), 1),
2091
+ service: z4.nullish(z4.string().check(z4.maxLength(64))),
2092
+ session_id: z4.nullish(z4.string().check(z4.maxLength(64))),
2093
+ source: z4.nullish(zBookingSource),
2094
+ utm_campaign: z4.nullish(z4.string().check(z4.maxLength(128))),
2095
+ utm_content: z4.nullish(z4.string().check(z4.maxLength(128))),
2096
+ utm_medium: z4.nullish(z4.string().check(z4.maxLength(128))),
2097
+ utm_source: z4.nullish(z4.string().check(z4.maxLength(128))),
2098
+ utm_term: z4.nullish(z4.string().check(z4.maxLength(128))),
2099
+ visitor_id: z4.nullish(z4.string().check(z4.maxLength(64)))
2100
+ });
2101
+ var zCustomLocation = z4.strictObject({
2102
+ kind: z4.literal("custom"),
2103
+ text: z4.string().check(z4.maxLength(1024))
2104
+ });
2105
+ var zErrorCode2 = z4.enum([
2106
+ "missing_credentials",
2107
+ "invalid_api_key",
2108
+ "not_authenticated",
2109
+ "wrong_key_type",
2110
+ "origin_missing",
2111
+ "origin_not_allowed",
2112
+ "capability_denied",
2113
+ "session_required",
2114
+ "operator_only",
2115
+ "cross_tenant",
2116
+ "business_id_required",
2117
+ "bad_request",
2118
+ "not_found",
2119
+ "conflict",
2120
+ "incompatible_payload",
2121
+ "repeat_confirmation_required",
2122
+ "idempotency_conflict",
2123
+ "validation_error",
2124
+ "unknown_service",
2125
+ "invalid_sale_properties",
2126
+ "invalid_cursor",
2127
+ "rate_limited",
2128
+ "internal_error"
2129
+ ]);
2130
+ var zMeetLocation = z4.strictObject({
2131
+ kind: z4.literal("google_meet")
2132
+ });
2133
+ var zPhoneLocation = z4.strictObject({
2134
+ kind: z4.literal("phone"),
2135
+ phone: z4.string().check(z4.maxLength(64))
2136
+ });
2137
+ var zPhysicalLocation = z4.strictObject({
2138
+ address: z4.string().check(z4.maxLength(1024)),
2139
+ kind: z4.literal("physical")
2140
+ });
2141
+ var zReminderMethod = z4.enum(["email", "popup"]);
2142
+ var zBookingReminder = z4.strictObject({
2143
+ method: zReminderMethod,
2144
+ minutes_before: z4.int().check(z4.gte(0), z4.lte(40320))
2145
+ });
2146
+ var zBookingReminders = z4.strictObject({
2147
+ overrides: z4.optional(z4.array(zBookingReminder).check(z4.maxLength(5))),
2148
+ use_calendar_defaults: z4._default(z4.optional(z4.boolean()), true)
2149
+ });
2150
+ var zBookingCreateSchema = z4.strictObject({
2151
+ appointment_type: z4.nullish(z4.string().check(z4.maxLength(64))),
2152
+ attendees: z4.optional(z4.array(zBookingAttendee).check(z4.maxLength(20))),
2153
+ buffer_after_minutes: z4._default(z4.optional(z4.int().check(z4.gte(0), z4.lte(1440))), 0),
2154
+ buffer_before_minutes: z4._default(z4.optional(z4.int().check(z4.gte(0), z4.lte(1440))), 0),
2155
+ calendar_key: z4.string().check(z4.minLength(1), z4.maxLength(64)),
2156
+ customer: zBookingCustomerInput,
2157
+ description: z4.nullish(z4.string().check(z4.maxLength(8e3))),
2158
+ duration_minutes: z4.nullish(z4.int().check(z4.gt(0), z4.lte(1440))),
2159
+ end_at: z4.nullish(z4.iso.datetime({ offset: true })),
2160
+ idempotency_key: z4.nullish(z4.string().check(z4.maxLength(128))),
2161
+ location: z4.nullish(z4.union([zMeetLocation, zPhysicalLocation, zPhoneLocation, zCustomLocation])),
2162
+ metadata: z4.nullish(zBookingMetadata),
2163
+ reminders: z4.nullish(zBookingReminders),
2164
+ send_invites: z4._default(z4.optional(z4.boolean()), true),
2165
+ start_at: z4.iso.datetime({ offset: true }),
2166
+ time_zone: z4.string().check(z4.minLength(1), z4.maxLength(64), z4.regex(/^[A-Za-z0-9_+\-\/]+$/)),
2167
+ title: z4.nullish(z4.string().check(z4.maxLength(300)))
2168
+ });
2169
+ var zValidationError2 = z4.object({
2170
+ ctx: z4.optional(z4.record(z4.string(), z4.unknown())),
2171
+ input: z4.optional(z4.unknown()),
2172
+ loc: z4.array(z4.union([z4.string(), z4.int()])),
2173
+ msg: z4.string(),
2174
+ type: z4.string()
2175
+ });
2176
+ var zHttpValidationError2 = z4.object({
2177
+ detail: z4.optional(z4.array(zValidationError2))
2178
+ });
2179
+ var zValidationErrorItem2 = z4.object({
2180
+ loc: z4.array(z4.union([z4.string(), z4.int()])),
2181
+ msg: z4.string(),
2182
+ type: z4.string()
2183
+ });
2184
+ var zApiErrorSchema2 = z4.object({
2185
+ code: zErrorCode2,
2186
+ context: z4._default(z4.nullish(z4.record(z4.string(), z4.unknown())), null),
2187
+ detail: z4.string(),
2188
+ errors: z4._default(z4.nullish(z4.array(zValidationErrorItem2)), null),
2189
+ request_id: z4._default(z4.nullish(z4.string()), null)
2190
+ });
2191
+
2192
+ // ../tracking-core/src/resources/calendar/schema.ts
2099
2193
  var CALENDAR_METADATA_SCHEMA_VERSION = 1;
2100
2194
  var MAX_ATTENDEES = 20;
2101
2195
  var MAX_REMINDER_OVERRIDES = 5;
@@ -2121,7 +2215,6 @@ var CALENDAR_ERROR_CODES = [
2121
2215
  "rate_limited",
2122
2216
  "google_error"
2123
2217
  ];
2124
- var isoInstant = z13.string().datetime({ offset: true });
2125
2218
  function isKnownTimeZone(timeZone) {
2126
2219
  try {
2127
2220
  new Intl.DateTimeFormat(void 0, { timeZone });
@@ -2130,107 +2223,65 @@ function isKnownTimeZone(timeZone) {
2130
2223
  return false;
2131
2224
  }
2132
2225
  }
2133
- var ianaTz = z13.string().min(1).max(64).regex(/^[A-Za-z0-9_+\-/]+$/).refine(isKnownTimeZone, { message: "unknown IANA time zone" });
2134
- var bookingAttendeeSchema = z13.object({
2135
- email: z13.string().max(320).email(),
2136
- display_name: z13.string().max(200).nullable().optional(),
2137
- optional: z13.boolean().default(false)
2138
- }).strict();
2139
- var bookingReminderSchema = z13.object({
2140
- method: z13.enum(["email", "popup"]),
2141
- minutes_before: z13.number().int().min(0).max(MAX_REMINDER_MINUTES)
2142
- }).strict();
2143
- var bookingRemindersSchema = z13.object({
2144
- use_calendar_defaults: z13.boolean().default(true),
2145
- overrides: z13.array(bookingReminderSchema).max(MAX_REMINDER_OVERRIDES).default([])
2146
- }).strict();
2147
- var bookingLocationSchema = z13.union([
2148
- z13.object({ kind: z13.literal("google_meet") }).strict(),
2149
- z13.object({ kind: z13.literal("physical"), address: z13.string().max(1024) }).strict(),
2150
- z13.object({ kind: z13.literal("phone"), phone: z13.string().max(64) }).strict(),
2151
- z13.object({ kind: z13.literal("custom"), text: z13.string().max(1024) }).strict()
2226
+ var ianaTz = z5.string().check(
2227
+ z5.minLength(1),
2228
+ z5.maxLength(64),
2229
+ z5.regex(/^[A-Za-z0-9_+\-/]+$/),
2230
+ z5.refine(isKnownTimeZone, { error: "unknown IANA time zone" })
2231
+ );
2232
+ var bookingAttendeeSchema = zBookingAttendee;
2233
+ var bookingReminderSchema = zBookingReminder;
2234
+ var bookingCustomerSchema = zBookingCustomerInput;
2235
+ var bookingMetadataSchema = z5.extend(zBookingMetadata, {
2236
+ custom: z5.nullish(
2237
+ z5.record(z5.string(), z5.union([z5.string(), z5.int(), z5.number(), z5.boolean(), z5.null()]))
2238
+ )
2239
+ });
2240
+ var bookingLocationSchema = z5.union([
2241
+ zMeetLocation,
2242
+ zPhysicalLocation,
2243
+ zPhoneLocation,
2244
+ zCustomLocation
2245
+ ]);
2246
+ var bookingLocationNullableSchema = z5.union([
2247
+ ...bookingLocationSchema.def.options,
2248
+ z5.null()
2152
2249
  ]);
2153
- var bookingLocationNullableSchema = z13.union([...bookingLocationSchema.options, z13.null()]);
2154
- var bookingCustomerSchema = z13.object({
2155
- // Required: Google needs an address to send the invite that confirms the
2156
- // booking, and that invite is the whole confirmation mechanism.
2157
- email: z13.string().max(320).email(),
2158
- name: z13.string().max(200).nullable().optional(),
2159
- phone: z13.string().max(64).nullable().optional(),
2160
- sms_consent: z13.boolean().default(false)
2161
- }).strict();
2162
- var jsonScalar = z13.union([z13.string(), z13.number(), z13.boolean(), z13.null()]);
2163
- var bookingMetadataSchema = z13.object({
2164
- schema_version: z13.number().int().default(CALENDAR_METADATA_SCHEMA_VERSION),
2165
- source: z13.enum(BOOKING_SOURCES).nullable().optional(),
2166
- service: z13.string().max(64).nullable().optional(),
2167
- visitor_id: z13.string().max(64).nullable().optional(),
2168
- session_id: z13.string().max(64).nullable().optional(),
2169
- gclid: z13.string().max(256).nullable().optional(),
2170
- fbclid: z13.string().max(256).nullable().optional(),
2171
- utm_source: z13.string().max(128).nullable().optional(),
2172
- utm_medium: z13.string().max(128).nullable().optional(),
2173
- utm_campaign: z13.string().max(128).nullable().optional(),
2174
- utm_term: z13.string().max(128).nullable().optional(),
2175
- utm_content: z13.string().max(128).nullable().optional(),
2176
- landing_page: z13.string().max(2048).nullable().optional(),
2177
- referrer: z13.string().max(2048).nullable().optional(),
2178
- notes: z13.string().max(2e3).nullable().optional(),
2179
- custom: z13.record(jsonScalar).nullable().optional()
2180
- }).strict();
2250
+ function addIssue2(ctx, path, message) {
2251
+ ctx.issues.push({ code: "custom", input: ctx.value, path, message });
2252
+ }
2181
2253
  function refineEndXor(value, ctx) {
2182
2254
  const hasEnd = value.end_at !== void 0 && value.end_at !== null;
2183
2255
  const hasDuration = value.duration_minutes !== void 0 && value.duration_minutes !== null;
2184
2256
  if (hasEnd === hasDuration) {
2185
- ctx.addIssue({
2186
- code: z13.ZodIssueCode.custom,
2187
- message: "provide exactly one of end_at or duration_minutes",
2188
- path: ["end_at"]
2189
- });
2257
+ addIssue2(ctx, ["end_at"], "provide exactly one of end_at or duration_minutes");
2190
2258
  return;
2191
2259
  }
2192
2260
  if (hasEnd && new Date(value.end_at) <= new Date(value.start_at)) {
2193
- ctx.addIssue({
2194
- code: z13.ZodIssueCode.custom,
2195
- message: "end_at must be after start_at",
2196
- path: ["end_at"]
2197
- });
2261
+ addIssue2(ctx, ["end_at"], "end_at must be after start_at");
2198
2262
  }
2199
2263
  }
2200
- var bookingCreateSchema = z13.object({
2201
- calendar_key: z13.string().min(1).max(64),
2202
- // Free-form: appointment types are the client site's own vocabulary, not
2203
- // configuration the dashboard holds.
2204
- appointment_type: z13.string().max(64).nullable().optional(),
2205
- start_at: isoInstant,
2206
- end_at: isoInstant.nullable().optional(),
2207
- duration_minutes: z13.number().int().positive().max(MAX_BOOKING_MINUTES).nullable().optional(),
2208
- /** The booker's zone — distinct from the business's and the calendar's. */
2209
- time_zone: ianaTz,
2210
- title: z13.string().max(300).nullable().optional(),
2211
- description: z13.string().max(8e3).nullable().optional(),
2212
- location: bookingLocationNullableSchema.optional(),
2213
- customer: bookingCustomerSchema,
2214
- attendees: z13.array(bookingAttendeeSchema).max(MAX_ATTENDEES).default([]),
2215
- send_invites: z13.boolean().default(true),
2216
- reminders: bookingRemindersSchema.nullable().optional(),
2217
- metadata: bookingMetadataSchema.nullable().optional(),
2218
- idempotency_key: z13.string().max(128).nullable().optional(),
2219
- buffer_before_minutes: z13.number().int().min(0).max(MAX_BOOKING_MINUTES).default(0),
2220
- buffer_after_minutes: z13.number().int().min(0).max(MAX_BOOKING_MINUTES).default(0)
2221
- }).strict().superRefine(refineEndXor);
2222
- var bookingRescheduleSchema = z13.object({
2223
- start_at: isoInstant,
2224
- end_at: isoInstant.nullable().optional(),
2225
- duration_minutes: z13.number().int().positive().max(MAX_BOOKING_MINUTES).nullable().optional(),
2264
+ var bookingRemindersSchema = z5.extend(zBookingReminders, {
2265
+ overrides: z5._default(
2266
+ z5.array(bookingReminderSchema).check(z5.maxLength(MAX_REMINDER_OVERRIDES)),
2267
+ []
2268
+ )
2269
+ });
2270
+ var bookingCreateSchema = z5.extend(zBookingCreateSchema, {
2226
2271
  time_zone: ianaTz,
2227
- notify_attendees: z13.boolean().default(true),
2228
- reason: z13.string().max(500).nullable().optional()
2229
- }).strict().superRefine(refineEndXor);
2230
- var bookingCancelSchema = z13.object({
2231
- reason: z13.string().max(500).nullable().optional(),
2232
- notify_attendees: z13.boolean().default(true)
2233
- }).strict();
2272
+ // The generated field is `z.union([...variants]).nullish()`, which nests one
2273
+ // `anyOf` inside another; Pydantic's `BookingLocation | None` flattens to a
2274
+ // single list and the drift snapshot compares structure. Override with the
2275
+ // flattened union.
2276
+ location: z5.optional(bookingLocationNullableSchema),
2277
+ attendees: z5._default(z5.array(bookingAttendeeSchema).check(z5.maxLength(MAX_ATTENDEES)), []),
2278
+ // These reference the un-composed generated schemas; generation can't nest
2279
+ // our compositions into its own output.
2280
+ reminders: z5.nullish(bookingRemindersSchema),
2281
+ metadata: z5.nullish(bookingMetadataSchema)
2282
+ }).check((ctx) => refineEndXor(ctx.value, ctx));
2283
+ var bookingRescheduleSchema = z5.extend(zBookingRescheduleSchema, { time_zone: ianaTz }).check((ctx) => refineEndXor(ctx.value, ctx));
2284
+ var bookingCancelSchema = zBookingCancelSchema;
2234
2285
 
2235
2286
  // ../tracking-core/src/resources/calendar/slots.ts
2236
2287
  function parseHhMm(value) {
@@ -2461,6 +2512,7 @@ export {
2461
2512
  createTrackingClientContext,
2462
2513
  createTrackingEventCreatePayload,
2463
2514
  createTrackingSessionUpsertPayload,
2515
+ currencySchema,
2464
2516
  durationMinutes,
2465
2517
  endOfDayInTz,
2466
2518
  fetchServices,