@aranova/tracking-react 0.27.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -60,7 +60,7 @@ function normalizeEmail(raw) {
60
60
  return EMAIL_SHAPE.test(cleaned) ? cleaned : null;
61
61
  }
62
62
  function stashUserData(data, country) {
63
- const email = normalizeEmail(data.email);
63
+ const email3 = normalizeEmail(data.email);
64
64
  let phoneNumber = null;
65
65
  if (typeof data.phone === "string" && data.phone.length > 0) {
66
66
  try {
@@ -70,7 +70,7 @@ function stashUserData(data, country) {
70
70
  }
71
71
  }
72
72
  stash = {
73
- email: email ?? stash.email,
73
+ email: email3 ?? stash.email,
74
74
  phoneNumber: phoneNumber ?? stash.phoneNumber
75
75
  };
76
76
  }
@@ -79,11 +79,11 @@ function clearStashedUserData() {
79
79
  }
80
80
  function applyUserDataForConversion(explicit, country) {
81
81
  if (typeof window === "undefined" || typeof window.gtag !== "function") return false;
82
- let email = stash.email;
82
+ let email3 = stash.email;
83
83
  let phoneNumber = stash.phoneNumber;
84
84
  if (explicit) {
85
85
  const normalizedEmail = normalizeEmail(explicit.email);
86
- if (normalizedEmail) email = normalizedEmail;
86
+ if (normalizedEmail) email3 = normalizedEmail;
87
87
  if (typeof explicit.phone === "string" && explicit.phone.length > 0) {
88
88
  try {
89
89
  phoneNumber = toE164(explicit.phone, country) ?? phoneNumber;
@@ -91,10 +91,10 @@ function applyUserDataForConversion(explicit, country) {
91
91
  }
92
92
  }
93
93
  }
94
- if (email === null && phoneNumber === null) return false;
94
+ if (email3 === null && phoneNumber === null) return false;
95
95
  try {
96
96
  window.gtag("set", "user_data", {
97
- ...email !== null ? { email } : {},
97
+ ...email3 !== null ? { email: email3 } : {},
98
98
  ...phoneNumber !== null ? { phone_number: phoneNumber } : {}
99
99
  });
100
100
  return true;
@@ -450,10 +450,10 @@ function readStoredRecord() {
450
450
  return null;
451
451
  }
452
452
  }
453
- function writeRecord(record) {
454
- memoryRecord = record;
453
+ function writeRecord(record3) {
454
+ memoryRecord = record3;
455
455
  try {
456
- window.localStorage.setItem(LANDING_STORAGE_KEY, JSON.stringify(record));
456
+ window.localStorage.setItem(LANDING_STORAGE_KEY, JSON.stringify(record3));
457
457
  } catch {
458
458
  }
459
459
  }
@@ -475,9 +475,9 @@ function getOrCaptureLandingParams(sessionId, url) {
475
475
  if (memoryRecord && memoryRecord.session_id === sessionId) {
476
476
  return memoryRecord.params;
477
477
  }
478
- const record = { session_id: sessionId, params: captureFromUrl(url) };
479
- writeRecord(record);
480
- return record.params;
478
+ const record3 = { session_id: sessionId, params: captureFromUrl(url) };
479
+ writeRecord(record3);
480
+ return record3.params;
481
481
  }
482
482
  function buildLandingPayloadFields(sessionId, override) {
483
483
  const params = override ?? (typeof window === "undefined" ? null : getOrCaptureLandingParams(sessionId));
@@ -854,9 +854,9 @@ function automaticThresholdMet(goal, eventType, metadata) {
854
854
  }
855
855
 
856
856
  // ../tracking-core/src/resources/intl/date.ts
857
- function formatDateInTz(iso, timeZone, opts, locale) {
858
- const date = new Date(iso);
859
- if (Number.isNaN(date.getTime())) return iso;
857
+ function formatDateInTz(iso3, timeZone, opts, locale) {
858
+ const date = new Date(iso3);
859
+ if (Number.isNaN(date.getTime())) return iso3;
860
860
  return new Intl.DateTimeFormat(locale, {
861
861
  year: "numeric",
862
862
  month: "short",
@@ -1268,29 +1268,6 @@ function getTrackingConfigRuntime(ref, fetchImpl) {
1268
1268
  return runtime;
1269
1269
  }
1270
1270
 
1271
- // ../tracking-core/src/session.ts
1272
- var SESSION_IDLE_MS = 30 * 60 * 1e3;
1273
-
1274
- // ../tracking-core/src/events/page-view.ts
1275
- import { z } from "zod";
1276
- var pageViewMetadataSchema = z.object({
1277
- page: z.object({
1278
- title: z.string().nullable(),
1279
- path: z.string(),
1280
- search: z.string(),
1281
- hash: z.string()
1282
- }).strict(),
1283
- referrer: z.string().nullable(),
1284
- // `.nullable().optional()` — absent (undefined) OR explicit null OR a
1285
- // real viewport object. Mirrors Pydantic's `_Viewport | None = None`
1286
- // on the backend side so the drift test stays clean.
1287
- viewport: z.object({
1288
- w: z.number(),
1289
- h: z.number()
1290
- }).strict().nullable().optional()
1291
- }).strict();
1292
- var pageViewConfigSchema = z.object({}).strict();
1293
-
1294
1271
  // ../tracking-core/src/ingest.ts
1295
1272
  var API_KEY_HEADER = "X-Aranova-Api-Key";
1296
1273
  var SDK_VERSION_HEADER = "X-Aranova-Sdk-Version";
@@ -1298,187 +1275,6 @@ var SDK_PACKAGE_HEADER = "X-Aranova-Sdk-Package";
1298
1275
  var SDK_SURFACE_HEADER = "X-Aranova-Sdk-Surface";
1299
1276
  var SDK_ENVIRONMENT_HEADER = "X-Aranova-Sdk-Environment";
1300
1277
 
1301
- // ../tracking-core/src/events/cta-click.ts
1302
- import { z as z2 } from "zod";
1303
- var ctaClickMetadataSchema = z2.object({
1304
- cta_name: z2.string(),
1305
- page: z2.object({
1306
- path: z2.string()
1307
- }).strict(),
1308
- section: z2.string().nullable().optional(),
1309
- destination_url: z2.string().nullable().optional(),
1310
- // Set by auto-capture (and available to manual callers): the link target
1311
- // and a short element descriptor (tag#id) for tying clicks to specific UI.
1312
- href: z2.string().nullable().optional(),
1313
- element: z2.string().nullable().optional()
1314
- }).strict();
1315
- var ctaClickConfigSchema = z2.object({
1316
- autoCapture: z2.object({
1317
- selector: z2.string().optional()
1318
- }).strict().optional()
1319
- }).strict();
1320
-
1321
- // ../tracking-core/src/events/sdk-heartbeat.ts
1322
- import { z as z3 } from "zod";
1323
- var sdkHeartbeatTriggersSchema = z3.object({
1324
- automatic: z3.array(z3.string()),
1325
- manual: z3.array(z3.string())
1326
- }).strict();
1327
- var sdkHeartbeatMetadataSchema = z3.object({
1328
- sdk_version: z3.string(),
1329
- package_name: z3.string().nullable(),
1330
- surface: z3.enum(["next", "react", "script"]),
1331
- triggers: sdkHeartbeatTriggersSchema,
1332
- trigger_config: z3.record(z3.string(), z3.record(z3.string(), z3.unknown())).nullable().optional(),
1333
- configured_gtag_ids: z3.record(z3.string(), z3.string()).nullable().optional(),
1334
- // Site whose config object the SDK resolves; null on a legacy business ref.
1335
- config_site_id: z3.string().uuid().nullable().optional()
1336
- }).strict();
1337
- var sdkHeartbeatConfigSchema = z3.object({}).strict();
1338
-
1339
- // ../tracking-core/src/events/form-start.ts
1340
- import { z as z4 } from "zod";
1341
- var formStartMetadataSchema = z4.object({
1342
- form: z4.object({
1343
- id: z4.string(),
1344
- action: z4.string().nullable()
1345
- }).strict(),
1346
- page: z4.object({
1347
- path: z4.string()
1348
- }).strict()
1349
- }).strict();
1350
- var formStartConfigSchema = z4.object({
1351
- selector: z4.string().optional()
1352
- }).strict();
1353
-
1354
- // ../tracking-core/src/events/form-submit.ts
1355
- import { z as z5 } from "zod";
1356
- var jsonValueSchema = z5.lazy(
1357
- () => z5.union([
1358
- z5.string(),
1359
- z5.number().finite(),
1360
- z5.boolean(),
1361
- z5.null(),
1362
- z5.array(jsonValueSchema),
1363
- z5.record(jsonValueSchema)
1364
- ])
1365
- );
1366
- var formSubmitMetadataSchema = z5.object({
1367
- form: z5.object({
1368
- id: z5.string(),
1369
- action: z5.string().nullable(),
1370
- fields: z5.array(
1371
- z5.object({
1372
- name: z5.string(),
1373
- type: z5.string(),
1374
- label: z5.string().nullable(),
1375
- value: jsonValueSchema
1376
- }).strict()
1377
- ).optional()
1378
- }).strict(),
1379
- page: z5.object({
1380
- path: z5.string()
1381
- }).strict()
1382
- }).strict();
1383
- var formSubmitConfigSchema = z5.object({}).strict();
1384
-
1385
- // ../tracking-core/src/events/multi-page-session.ts
1386
- import { z as z6 } from "zod";
1387
- var multiPageSessionMetadataSchema = z6.object({
1388
- page_count: z6.number().int().min(2),
1389
- page: z6.object({
1390
- path: z6.string()
1391
- }).strict()
1392
- }).strict();
1393
- var multiPageSessionConfigSchema = z6.object({
1394
- pageThreshold: z6.number().int().min(2)
1395
- }).strict();
1396
-
1397
- // ../tracking-core/src/events/page-exit.ts
1398
- import { z as z7 } from "zod";
1399
- var pageExitMetadataSchema = z7.object({
1400
- dwell_ms: z7.number().int().min(0),
1401
- // null = left without any scroll signal; floor is 0 so a valid 0% is never
1402
- // rejected (a single bad field 422s the whole keepalive beacon batch).
1403
- max_scroll_percent: z7.number().int().min(0).max(100).nullable(),
1404
- // The gating baseline: the fraction of the page visible at load with
1405
- // zero scrolling — or, for pages that grew after the post-paint snapshot
1406
- // (skeleton/streaming renders), the first-scroll position that
1407
- // established it. null = page had no scrollable range, or the segment
1408
- // ended before the snapshot. `.optional()` is load-bearing: SDK builds
1409
- // predating this field keep POSTing page_exit without the key —
1410
- // requiring it would 422 whole keepalive beacon batches.
1411
- scroll_baseline_percent: z7.number().int().min(0).max(100).nullable().optional(),
1412
- page: z7.object({
1413
- path: z7.string()
1414
- }).strict()
1415
- }).strict();
1416
- var pageExitConfigSchema = z7.object({}).strict();
1417
-
1418
- // ../tracking-core/src/events/phone-click.ts
1419
- import { z as z8 } from "zod";
1420
- var phoneClickMetadataSchema = z8.object({
1421
- phone_number: z8.string(),
1422
- page: z8.object({
1423
- path: z8.string()
1424
- }).strict(),
1425
- section: z8.string().nullable().optional()
1426
- }).strict();
1427
- var phoneClickConfigSchema = z8.object({
1428
- autoCapture: z8.object({
1429
- selector: z8.string().optional()
1430
- }).strict().optional()
1431
- }).strict();
1432
-
1433
- // ../tracking-core/src/events/scroll-depth.ts
1434
- import { z as z9 } from "zod";
1435
- var scrollDepthMetadataSchema = z9.object({
1436
- depth_percent: z9.number().int().min(1).max(100),
1437
- page: z9.object({
1438
- path: z9.string()
1439
- }).strict()
1440
- }).strict();
1441
- var scrollDepthConfigSchema = z9.object({
1442
- thresholds: z9.array(z9.number().int().min(1).max(100)).min(1)
1443
- }).strict();
1444
-
1445
- // ../tracking-core/src/events/specific-page-visit.ts
1446
- import { z as z10 } from "zod";
1447
- var PAGE_IDENTITY_MAX_LENGTH = 64;
1448
- var PAGE_IDENTITY_PATTERN = /^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/;
1449
- var pageIdentitySchema = z10.string().max(PAGE_IDENTITY_MAX_LENGTH).regex(PAGE_IDENTITY_PATTERN, {
1450
- message: "page identity must be lowercase snake_case, start with a letter, and contain at most 64 characters"
1451
- });
1452
- var specificPageNameSchema = pageIdentitySchema;
1453
- var specificPageVisitMetadataSchema = z10.object({
1454
- page_name: specificPageNameSchema,
1455
- page: z10.object({
1456
- path: z10.string()
1457
- }).strict()
1458
- }).strict();
1459
- var specificPageVisitConfigSchema = z10.object({
1460
- pages: z10.array(
1461
- z10.object({
1462
- name: specificPageNameSchema,
1463
- pathPattern: z10.custom((value) => value instanceof RegExp, {
1464
- message: "pathPattern must be a RegExp"
1465
- })
1466
- }).strict()
1467
- ).min(1)
1468
- }).strict();
1469
-
1470
- // ../tracking-core/src/events/time-on-site.ts
1471
- import { z as z11 } from "zod";
1472
- var timeOnSiteMetadataSchema = z11.object({
1473
- duration_ms: z11.number().int().nonnegative(),
1474
- page: z11.object({
1475
- path: z11.string()
1476
- }).strict()
1477
- }).strict();
1478
- var timeOnSiteConfigSchema = z11.object({
1479
- thresholdSeconds: z11.number().int().positive()
1480
- }).strict();
1481
-
1482
1278
  // ../tracking-core/src/events/semantics.ts
1483
1279
  var EVENT_SEMANTICS = {
1484
1280
  page_view: {
@@ -1552,82 +1348,6 @@ function getEventSemantics(eventName) {
1552
1348
  return eventName in EVENT_SEMANTICS ? EVENT_SEMANTICS[eventName] : null;
1553
1349
  }
1554
1350
 
1555
- // ../tracking-core/src/events/registry.ts
1556
- var EVENT_REGISTRY = {
1557
- // --- automatic triggers ---
1558
- page_view: {
1559
- kind: "automatic",
1560
- semantics: EVENT_SEMANTICS.page_view,
1561
- metadataSchema: pageViewMetadataSchema,
1562
- configSchema: pageViewConfigSchema
1563
- },
1564
- time_on_site: {
1565
- kind: "automatic",
1566
- semantics: EVENT_SEMANTICS.time_on_site,
1567
- metadataSchema: timeOnSiteMetadataSchema,
1568
- configSchema: timeOnSiteConfigSchema
1569
- },
1570
- specific_page_visit: {
1571
- kind: "automatic",
1572
- semantics: EVENT_SEMANTICS.specific_page_visit,
1573
- metadataSchema: specificPageVisitMetadataSchema,
1574
- configSchema: specificPageVisitConfigSchema
1575
- },
1576
- scroll_depth: {
1577
- kind: "automatic",
1578
- semantics: EVENT_SEMANTICS.scroll_depth,
1579
- metadataSchema: scrollDepthMetadataSchema,
1580
- configSchema: scrollDepthConfigSchema
1581
- },
1582
- multi_page_session: {
1583
- kind: "automatic",
1584
- semantics: EVENT_SEMANTICS.multi_page_session,
1585
- metadataSchema: multiPageSessionMetadataSchema,
1586
- configSchema: multiPageSessionConfigSchema
1587
- },
1588
- form_start: {
1589
- kind: "automatic",
1590
- semantics: EVENT_SEMANTICS.form_start,
1591
- metadataSchema: formStartMetadataSchema,
1592
- configSchema: formStartConfigSchema
1593
- },
1594
- // --- SDK-internal automatic (not consumer-configurable) ---
1595
- sdk_heartbeat: {
1596
- kind: "automatic",
1597
- semantics: EVENT_SEMANTICS.sdk_heartbeat,
1598
- metadataSchema: sdkHeartbeatMetadataSchema,
1599
- configSchema: sdkHeartbeatConfigSchema
1600
- },
1601
- page_exit: {
1602
- kind: "automatic",
1603
- semantics: EVENT_SEMANTICS.page_exit,
1604
- metadataSchema: pageExitMetadataSchema,
1605
- configSchema: pageExitConfigSchema
1606
- },
1607
- // --- manual triggers ---
1608
- form_submit: {
1609
- kind: "manual",
1610
- semantics: EVENT_SEMANTICS.form_submit,
1611
- metadataSchema: formSubmitMetadataSchema,
1612
- configSchema: formSubmitConfigSchema
1613
- },
1614
- phone_click: {
1615
- kind: "manual",
1616
- semantics: EVENT_SEMANTICS.phone_click,
1617
- metadataSchema: phoneClickMetadataSchema,
1618
- configSchema: phoneClickConfigSchema
1619
- },
1620
- cta_click: {
1621
- kind: "manual",
1622
- semantics: EVENT_SEMANTICS.cta_click,
1623
- metadataSchema: ctaClickMetadataSchema,
1624
- configSchema: ctaClickConfigSchema
1625
- }
1626
- };
1627
- var ALL_AUTOMATIC_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.kind === "automatic").map(([name]) => name);
1628
- var ALL_MANUAL_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.kind === "manual").map(([name]) => name);
1629
- var ALL_LEAD_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.semantics.outcomeRole === "lead").map(([name]) => name);
1630
-
1631
1351
  // ../tracking-core/src/resources/http/errors.ts
1632
1352
  var AranovaApiError = class extends Error {
1633
1353
  constructor(message, options) {
@@ -1665,9 +1385,9 @@ async function apiRequest(config, method, path, body, extraHeaders) {
1665
1385
  try {
1666
1386
  const parsed = await response.json();
1667
1387
  if (parsed && typeof parsed === "object") {
1668
- const record = parsed;
1669
- if (typeof record.detail === "string") detail = record.detail;
1670
- if (typeof record.code === "string") code = record.code;
1388
+ const record3 = parsed;
1389
+ if (typeof record3.detail === "string") detail = record3.detail;
1390
+ if (typeof record3.code === "string") code = record3.code;
1671
1391
  }
1672
1392
  } catch {
1673
1393
  }
@@ -1716,7 +1436,7 @@ function fireRecordedConversions(firing, input, recorded, sale, currency) {
1716
1436
  }
1717
1437
  function createSalesClient(config) {
1718
1438
  if (config.firing) registerCapability("conversion_goals_manual");
1719
- async function record(input) {
1439
+ async function record3(input) {
1720
1440
  const currency = input.currency ?? config.defaultCurrency;
1721
1441
  if (!currency) {
1722
1442
  throw new Error(
@@ -1742,9 +1462,9 @@ function createSalesClient(config) {
1742
1462
  return sale;
1743
1463
  }
1744
1464
  return {
1745
- record,
1465
+ record: record3,
1746
1466
  // recordSale is the intent-revealing alias — same behavior, clearer call site.
1747
- recordSale: record,
1467
+ recordSale: record3,
1748
1468
  trackConversion(key, options) {
1749
1469
  if (config.firing && "fireConversion" in config.firing) {
1750
1470
  if (options?.userData && getConsentState() !== "denied") stashUserData(options.userData);
@@ -1863,115 +1583,264 @@ function createSalesClient(config) {
1863
1583
  }
1864
1584
 
1865
1585
  // ../tracking-core/src/resources/sales/schema.ts
1866
- import { z as z12 } from "zod";
1867
- var SUPPORTED_CURRENCIES = ["USD", "CAD"];
1868
- var TRACKING_ENVIRONMENTS = ["production", "development"];
1869
- var currencySchema = z12.enum(SUPPORTED_CURRENCIES);
1870
- var centsSchema = z12.number().int().nonnegative();
1871
- var quantitySchema = z12.string().regex(/^\d+(\.\d{1,3})?$/);
1872
- var metadataSchema = z12.record(z12.unknown());
1873
- var saleItemSchema = z12.object({
1874
- external_item_id: z12.string().nullable().optional(),
1875
- name: z12.string().nullable().optional(),
1876
- category: z12.string().nullable().optional(),
1877
- quantity: quantitySchema,
1878
- unit_price_cents: centsSchema,
1879
- // Non-negativity validated on the wire — same contract as the other cents
1880
- // fields — and backstopped by the DB CHECK.
1881
- unit_cost_cents: centsSchema.nullable().optional()
1882
- }).strict();
1883
- var saleServiceSchema = z12.object({
1884
- service: z12.string(),
1885
- amount_cents: centsSchema
1886
- }).strict();
1887
- var customerNameSchema = z12.string().max(200);
1888
- var customerPhoneSchema = z12.string().max(64);
1889
- var customerEmailSchema = z12.string().max(320).email();
1586
+ import * as z2 from "zod/mini";
1587
+
1588
+ // ../tracking-core/src/resources/sales/generated/zod.gen.ts
1589
+ import * as z from "zod/mini";
1590
+ var zErrorCode = z.enum([
1591
+ "missing_credentials",
1592
+ "invalid_api_key",
1593
+ "not_authenticated",
1594
+ "wrong_key_type",
1595
+ "origin_missing",
1596
+ "origin_not_allowed",
1597
+ "capability_denied",
1598
+ "session_required",
1599
+ "operator_only",
1600
+ "cross_tenant",
1601
+ "business_id_required",
1602
+ "bad_request",
1603
+ "not_found",
1604
+ "conflict",
1605
+ "incompatible_payload",
1606
+ "repeat_confirmation_required",
1607
+ "idempotency_conflict",
1608
+ "validation_error",
1609
+ "unknown_service",
1610
+ "invalid_sale_properties",
1611
+ "invalid_cursor",
1612
+ "rate_limited",
1613
+ "internal_error"
1614
+ ]);
1615
+ var zSaleItemEntitySchema = z.object({
1616
+ category: z.nullable(z.string()),
1617
+ external_item_id: z.nullable(z.string()),
1618
+ id: z.uuid(),
1619
+ name: z.nullable(z.string()),
1620
+ quantity: z.string().check(z.regex(/^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$/)),
1621
+ unit_cost_cents: z.nullable(z.int()),
1622
+ unit_price_cents: z.int()
1623
+ });
1624
+ var zSaleItemInputSchema = z.strictObject({
1625
+ category: z.nullish(z.string()),
1626
+ external_item_id: z.nullish(z.string()),
1627
+ name: z.nullish(z.string()),
1628
+ quantity: z.string().check(z.regex(/^\d+(\.\d{1,3})?$/)),
1629
+ unit_cost_cents: z.nullish(z.int().check(z.gte(0))),
1630
+ unit_price_cents: z.int().check(z.gte(0))
1631
+ });
1632
+ var zSaleServiceEntitySchema = z.object({
1633
+ amount_cents: z.int(),
1634
+ id: z.uuid(),
1635
+ mapped: z.nullable(z.boolean()),
1636
+ service_id: z.uuid(),
1637
+ service_key: z.string(),
1638
+ service_label: z.string()
1639
+ });
1640
+ var zSaleServiceInputSchema = z.strictObject({
1641
+ amount_cents: z.int().check(z.gte(0)),
1642
+ service: z.string()
1643
+ });
1644
+ var zSmsAutomationState = z.enum([
1645
+ "needs_check",
1646
+ "failed",
1647
+ "undelivered",
1648
+ "blocked_opted_out",
1649
+ "withheld",
1650
+ "queued",
1651
+ "sent",
1652
+ "delivered",
1653
+ "eligible",
1654
+ "not_applicable"
1655
+ ]);
1656
+ var zSmsWithheldReason = z.enum([
1657
+ "automation_disabled",
1658
+ "sms_disabled",
1659
+ "no_phone",
1660
+ "no_consent",
1661
+ "no_customer_identity",
1662
+ "missing_customer_name",
1663
+ "placeholder_customer_name",
1664
+ "opted_out",
1665
+ "already_messaged",
1666
+ "sender_not_ready",
1667
+ "missing_review_url",
1668
+ "no_handler",
1669
+ "dispatch_already_recorded"
1670
+ ]);
1671
+ var zSaleSmsStatusSchema = z.object({
1672
+ can_send_now: z._default(z.boolean(), false),
1673
+ last_message_at: z.nullable(z.iso.datetime({ offset: true })),
1674
+ reason_detail: z.nullable(z.string()),
1675
+ state: zSmsAutomationState,
1676
+ suppressed_by_other_sale: z._default(z.boolean(), false),
1677
+ withheld_reason: z.nullable(zSmsWithheldReason)
1678
+ });
1679
+ var zSupportedCurrency = z.enum(["USD", "CAD"]);
1680
+ var zTrackingEnvironment = z.enum(["production", "development"]);
1681
+ var zSaleCreateSchema = z.strictObject({
1682
+ amount_total_cents: z.nullish(z.int().check(z.gte(0))),
1683
+ currency: zSupportedCurrency,
1684
+ customer_email: z.nullish(z.email().check(z.maxLength(320))),
1685
+ customer_name: z.nullish(z.string().check(z.maxLength(200))),
1686
+ customer_phone: z.nullish(z.string().check(z.maxLength(64))),
1687
+ description: z.nullish(z.string()),
1688
+ environment: z._default(z.optional(zTrackingEnvironment), "production"),
1689
+ external_id: z.nullish(z.string()),
1690
+ items: z.optional(z.array(zSaleItemInputSchema)),
1691
+ metadata: z.nullish(z.record(z.string(), z.unknown())),
1692
+ occurred_at: z.iso.datetime({ offset: true }),
1693
+ service: z.nullish(z.string()),
1694
+ services: z.nullish(z.array(zSaleServiceInputSchema)),
1695
+ sms_consent: z.nullish(z.boolean())
1696
+ });
1697
+ var zValidationError = z.object({
1698
+ ctx: z.optional(z.record(z.string(), z.unknown())),
1699
+ input: z.optional(z.unknown()),
1700
+ loc: z.array(z.union([z.string(), z.int()])),
1701
+ msg: z.string(),
1702
+ type: z.string()
1703
+ });
1704
+ var zHttpValidationError = z.object({
1705
+ detail: z.optional(z.array(zValidationError))
1706
+ });
1707
+ var zValidationErrorItem = z.object({
1708
+ loc: z.array(z.union([z.string(), z.int()])),
1709
+ msg: z.string(),
1710
+ type: z.string()
1711
+ });
1712
+ var zApiErrorSchema = z.object({
1713
+ code: zErrorCode,
1714
+ context: z._default(z.nullish(z.record(z.string(), z.unknown())), null),
1715
+ detail: z.string(),
1716
+ errors: z._default(z.nullish(z.array(zValidationErrorItem)), null),
1717
+ request_id: z._default(z.nullish(z.string()), null)
1718
+ });
1719
+ var zWritebackEmailSource = z.enum(["NONE", "SALE", "CUSTOMER", "HARVESTED"]);
1720
+ var zWritebackEnrichmentStatus = z.enum(["NONE", "MATCHED", "AMBIGUOUS"]);
1721
+ var zWritebackSaleUploadCounts = z.object({
1722
+ failed: z._default(z.int(), 0),
1723
+ pending: z._default(z.int(), 0),
1724
+ skipped: z._default(z.int(), 0),
1725
+ submitted: z._default(z.int(), 0),
1726
+ total: z._default(z.int(), 0),
1727
+ uploaded: z._default(z.int(), 0)
1728
+ });
1729
+ var zSaleWritebackStatusSchema = z.object({
1730
+ blocked_reason: z.nullable(z.string()),
1731
+ can_dispatch: z._default(z.boolean(), false),
1732
+ email_source: z.nullable(zWritebackEmailSource),
1733
+ enrichment_status: z.nullable(zWritebackEnrichmentStatus),
1734
+ gclid_attached: z._default(z.boolean(), false),
1735
+ identifiers_sent: z.nullable(z.string()),
1736
+ mapped_service_ids: z.array(z.uuid()),
1737
+ matched_submit_count: z.nullable(z.int()),
1738
+ needs_force: z._default(z.boolean(), false),
1739
+ rollup: z.enum([
1740
+ "failed",
1741
+ "skipped",
1742
+ "pending",
1743
+ "submitted",
1744
+ "uploaded",
1745
+ "not_uploaded",
1746
+ "out_of_window",
1747
+ "blocked"
1748
+ ]),
1749
+ stale: z._default(z.boolean(), false),
1750
+ uncovered_service_ids: z.array(z.uuid()),
1751
+ uploads: zWritebackSaleUploadCounts
1752
+ });
1753
+ var zSaleEntitySchema = z.object({
1754
+ amount_total_cents: z.int(),
1755
+ business_id: z.uuid(),
1756
+ business_name: z.nullable(z.string()),
1757
+ created_at: z.iso.datetime({ offset: true }),
1758
+ currency: z.string(),
1759
+ customer_email: z.nullable(z.string()),
1760
+ customer_name: z.nullable(z.string()),
1761
+ customer_name_placeholder_confirmed: z._default(z.boolean(), false),
1762
+ customer_name_placeholder_confirmed_at: z.nullable(z.iso.datetime({ offset: true })),
1763
+ customer_phone: z.nullable(z.string()),
1764
+ description: z.nullable(z.string()),
1765
+ environment: zTrackingEnvironment,
1766
+ external_id: z.nullable(z.string()),
1767
+ id: z.uuid(),
1768
+ items: z.array(zSaleItemEntitySchema),
1769
+ metadata: z.nullable(z.record(z.string(), z.unknown())),
1770
+ occurred_at: z.iso.datetime({ offset: true }),
1771
+ service_id: z.nullable(z.uuid()),
1772
+ service_key: z.nullable(z.string()),
1773
+ service_label: z.nullable(z.string()),
1774
+ services: z.array(zSaleServiceEntitySchema),
1775
+ sms_automation: z.nullable(zSaleSmsStatusSchema),
1776
+ sms_consent: z._default(z.boolean(), false),
1777
+ sms_consent_granted_at: z.nullable(z.iso.datetime({ offset: true })),
1778
+ updated_at: z.iso.datetime({ offset: true }),
1779
+ writeback: z.nullable(zSaleWritebackStatusSchema)
1780
+ });
1781
+
1782
+ // ../tracking-core/src/resources/sales/schema.ts
1783
+ var saleItemSchema = zSaleItemInputSchema;
1784
+ var saleServiceSchema = zSaleServiceInputSchema;
1785
+ var currencySchema = zSupportedCurrency;
1786
+ var SUPPORTED_CURRENCIES = currencySchema.options;
1787
+ var centsSchema = z2.int().check(z2.gte(0));
1788
+ var metadataSchema = z2.record(z2.string(), z2.unknown());
1789
+ var customerNameSchema = z2.string().check(z2.maxLength(200));
1790
+ var customerPhoneSchema = z2.string().check(z2.maxLength(64));
1791
+ var customerEmailSchema = z2.email().check(z2.maxLength(320));
1792
+ function addIssue(ctx, path, message) {
1793
+ ctx.issues.push({ code: "custom", input: ctx.value, path, message });
1794
+ }
1890
1795
  function refineServiceXor(val, ctx, { requireAmount }) {
1891
1796
  if (val.services != null) {
1892
1797
  if (val.service != null) {
1893
- ctx.addIssue({
1894
- code: z12.ZodIssueCode.custom,
1895
- message: "pass either `service` or `services`, not both",
1896
- path: ["services"]
1897
- });
1798
+ addIssue(ctx, ["services"], "pass either `service` or `services`, not both");
1898
1799
  }
1899
1800
  if (val.services.length === 0) {
1900
- ctx.addIssue({
1901
- code: z12.ZodIssueCode.custom,
1902
- message: "`services` must not be empty",
1903
- path: ["services"]
1904
- });
1801
+ addIssue(ctx, ["services"], "`services` must not be empty");
1905
1802
  }
1906
1803
  const keys = val.services.map((s) => s.service);
1907
1804
  if (new Set(keys).size !== keys.length) {
1908
- ctx.addIssue({
1909
- code: z12.ZodIssueCode.custom,
1910
- message: "`services` must not list the same service more than once",
1911
- path: ["services"]
1912
- });
1805
+ addIssue(ctx, ["services"], "`services` must not list the same service more than once");
1913
1806
  }
1914
1807
  if (val.amount_total_cents != null) {
1915
1808
  const sum = val.services.reduce((acc, s) => acc + s.amount_cents, 0);
1916
1809
  if (val.amount_total_cents !== sum) {
1917
- ctx.addIssue({
1918
- code: z12.ZodIssueCode.custom,
1919
- message: "amount_total_cents must equal the sum of the services amounts (omit it to derive it automatically)",
1920
- path: ["amount_total_cents"]
1921
- });
1810
+ addIssue(
1811
+ ctx,
1812
+ ["amount_total_cents"],
1813
+ "amount_total_cents must equal the sum of the services amounts (omit it to derive it automatically)"
1814
+ );
1922
1815
  }
1923
1816
  }
1924
1817
  } else if (requireAmount && val.amount_total_cents == null) {
1925
- ctx.addIssue({
1926
- code: z12.ZodIssueCode.custom,
1927
- message: "amount_total_cents is required unless `services` is provided",
1928
- path: ["amount_total_cents"]
1929
- });
1818
+ addIssue(
1819
+ ctx,
1820
+ ["amount_total_cents"],
1821
+ "amount_total_cents is required unless `services` is provided"
1822
+ );
1930
1823
  }
1931
1824
  }
1932
- var saleCreateSchema = z12.object({
1933
- external_id: z12.string().nullable().optional(),
1934
- description: z12.string().nullable().optional(),
1935
- service: z12.string().nullable().optional(),
1936
- services: z12.array(saleServiceSchema).nullable().optional(),
1937
- currency: currencySchema,
1938
- // Optional only because the plural `services` form derives it from the sum
1939
- // (see refineServiceXor); the singular/serviceless path still requires it.
1940
- amount_total_cents: centsSchema.nullable().optional(),
1941
- occurred_at: z12.string().datetime(),
1942
- environment: z12.enum(TRACKING_ENVIRONMENTS).default("production"),
1943
- items: z12.array(saleItemSchema).default([]),
1944
- metadata: metadataSchema.nullable().optional(),
1945
- customer_name: customerNameSchema.nullable().optional(),
1946
- customer_phone: customerPhoneSchema.nullable().optional(),
1947
- customer_email: customerEmailSchema.nullable().optional(),
1948
- // CASL consent attestation: the customer agreed to receive SMS. Recorded
1949
- // with a timestamp server-side; every SMS send path gates on it.
1950
- //
1951
- // Tri-state: omit it (or send null) to let the server apply the business's
1952
- // configured default-opt-in policy, honouring a returning customer's
1953
- // remembered preference. Send an explicit boolean to assert consent state
1954
- // yourself — `false` records a deliberate opt-out.
1955
- sms_consent: z12.boolean().nullable().optional()
1956
- }).strict().superRefine((val, ctx) => refineServiceXor(val, ctx, { requireAmount: true }));
1957
- var saleUpdateSchema = z12.object({
1958
- description: z12.string().nullable().optional(),
1959
- service: z12.string().nullable().optional(),
1960
- services: z12.array(saleServiceSchema).nullable().optional(),
1961
- currency: currencySchema.optional(),
1962
- amount_total_cents: centsSchema.optional(),
1963
- occurred_at: z12.string().datetime().optional(),
1964
- items: z12.array(saleItemSchema).optional(),
1965
- metadata: metadataSchema.nullable().optional(),
1966
- customer_name: customerNameSchema.nullable().optional(),
1825
+ var saleCreateSchema = z2.extend(zSaleCreateSchema, { items: z2._default(z2.array(saleItemSchema), []) }).check((ctx) => refineServiceXor(ctx.value, ctx, { requireAmount: true }));
1826
+ var saleUpdateSchema = z2.strictObject({
1827
+ description: z2.nullish(z2.string()),
1828
+ service: z2.nullish(z2.string()),
1829
+ services: z2.nullish(z2.array(saleServiceSchema)),
1830
+ currency: z2.optional(currencySchema),
1831
+ amount_total_cents: z2.optional(centsSchema),
1832
+ occurred_at: z2.optional(z2.iso.datetime()),
1833
+ items: z2.optional(z2.array(saleItemSchema)),
1834
+ metadata: z2.nullish(metadataSchema),
1835
+ customer_name: z2.nullish(customerNameSchema),
1967
1836
  // Re-attest when changing a filler-looking name; the server clears the
1968
1837
  // prior attestation whenever `customer_name` changes.
1969
- customer_name_placeholder_confirmed: z12.boolean().optional(),
1970
- customer_phone: customerPhoneSchema.nullable().optional(),
1971
- customer_email: customerEmailSchema.nullable().optional(),
1838
+ customer_name_placeholder_confirmed: z2.optional(z2.boolean()),
1839
+ customer_phone: z2.nullish(customerPhoneSchema),
1840
+ customer_email: z2.nullish(customerEmailSchema),
1972
1841
  // NOT NULL server-side: omit to leave unchanged (explicit null is rejected).
1973
- sms_consent: z12.boolean().optional()
1974
- }).strict().superRefine((val, ctx) => refineServiceXor(val, ctx, { requireAmount: false }));
1842
+ sms_consent: z2.optional(z2.boolean())
1843
+ }).check((ctx) => refineServiceXor(ctx.value, ctx, { requireAmount: false }));
1975
1844
  var TRACKING_RANGES = ["24h", "7d", "30d"];
1976
1845
  var NAMED_RANGES = [
1977
1846
  "today",
@@ -2023,6 +1892,7 @@ export {
2023
1892
  createTrackingClientContext,
2024
1893
  createTrackingEventCreatePayload,
2025
1894
  createTrackingSessionUpsertPayload,
1895
+ currencySchema,
2026
1896
  fetchServices,
2027
1897
  formatDateInTz,
2028
1898
  formatMoney,