@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/index.mjs CHANGED
@@ -457,10 +457,10 @@ function readStoredRecord() {
457
457
  return null;
458
458
  }
459
459
  }
460
- function writeRecord(record3) {
461
- memoryRecord = record3;
460
+ function writeRecord(record4) {
461
+ memoryRecord = record4;
462
462
  try {
463
- window.localStorage.setItem(LANDING_STORAGE_KEY, JSON.stringify(record3));
463
+ window.localStorage.setItem(LANDING_STORAGE_KEY, JSON.stringify(record4));
464
464
  } catch {
465
465
  }
466
466
  }
@@ -482,9 +482,9 @@ function getOrCaptureLandingParams(sessionId, url) {
482
482
  if (memoryRecord && memoryRecord.session_id === sessionId) {
483
483
  return memoryRecord.params;
484
484
  }
485
- const record3 = { session_id: sessionId, params: captureFromUrl(url) };
486
- writeRecord(record3);
487
- return record3.params;
485
+ const record4 = { session_id: sessionId, params: captureFromUrl(url) };
486
+ writeRecord(record4);
487
+ return record4.params;
488
488
  }
489
489
  function buildLandingPayloadFields(sessionId, override) {
490
490
  const params = override ?? (typeof window === "undefined" ? null : getOrCaptureLandingParams(sessionId));
@@ -1711,8 +1711,81 @@ var SDK_PACKAGE_HEADER = "X-Aranova-Sdk-Package";
1711
1711
  var SDK_SURFACE_HEADER = "X-Aranova-Sdk-Surface";
1712
1712
  var SDK_ENVIRONMENT_HEADER = "X-Aranova-Sdk-Environment";
1713
1713
 
1714
- // ../tracking-core/src/lead-forms/lead-forms.gen.ts
1714
+ // ../tracking-core/src/ingest-typed.ts
1715
+ import { parse, safeParse } from "zod/mini";
1716
+
1717
+ // ../tracking-core/src/events/form-submit.ts
1715
1718
  import * as z2 from "zod/mini";
1719
+ var jsonValueSchema = z2.lazy(
1720
+ () => z2.union([
1721
+ z2.string(),
1722
+ z2.number(),
1723
+ z2.boolean(),
1724
+ z2.null(),
1725
+ z2.array(jsonValueSchema),
1726
+ z2.record(z2.string(), jsonValueSchema)
1727
+ ])
1728
+ ).register(z2.globalRegistry, { id: "JsonSerializableValue" });
1729
+ var contractNameSchema = z2.string().check(z2.regex(/^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?$/));
1730
+ var contractName = contractNameSchema;
1731
+ var violationRole = z2.string().check(
1732
+ z2.maxLength(200),
1733
+ z2.regex(
1734
+ /^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?(\|[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?)*$/
1735
+ )
1736
+ );
1737
+ var MAX_CONTRACT_VIOLATIONS = 50;
1738
+ var contractViolationSchema = z2.strictObject({
1739
+ role: z2.nullable(violationRole),
1740
+ rule: z2.string().check(z2.regex(/^[a-z][a-z_]{0,47}$/))
1741
+ });
1742
+ var formSubmitMetadataSchema = z2.strictObject({
1743
+ form: z2.strictObject({
1744
+ id: z2.string(),
1745
+ action: z2.nullable(z2.string()),
1746
+ fields: z2.optional(
1747
+ z2.array(
1748
+ z2.strictObject({
1749
+ name: z2.string(),
1750
+ type: z2.string(),
1751
+ label: z2.nullable(z2.string()),
1752
+ value: jsonValueSchema,
1753
+ role: z2.optional(z2.nullable(contractName))
1754
+ })
1755
+ )
1756
+ ),
1757
+ kind: z2.optional(z2.nullable(contractName)),
1758
+ contract_version: z2.optional(z2.nullable(z2.int().check(z2.gte(1)))),
1759
+ contract_hash: z2.optional(z2.nullable(z2.string().check(z2.maxLength(64)))),
1760
+ extra: z2.optional(
1761
+ z2.nullable(
1762
+ z2.array(
1763
+ z2.strictObject({
1764
+ key: z2.string().check(z2.maxLength(64)),
1765
+ label: z2.string().check(z2.maxLength(200)),
1766
+ value: jsonValueSchema
1767
+ })
1768
+ ).check(z2.maxLength(20))
1769
+ )
1770
+ ),
1771
+ contract_violations: z2.optional(
1772
+ z2.nullable(z2.array(contractViolationSchema).check(z2.maxLength(MAX_CONTRACT_VIOLATIONS)))
1773
+ )
1774
+ }),
1775
+ page: z2.strictObject({
1776
+ path: z2.string()
1777
+ })
1778
+ });
1779
+ var formSubmitConfigSchema = z2.strictObject({});
1780
+
1781
+ // ../tracking-core/src/ingest-typed.ts
1782
+ var clientSettings = /* @__PURE__ */ new WeakMap();
1783
+ function typedClientSettings(client) {
1784
+ return clientSettings.get(client) ?? {};
1785
+ }
1786
+
1787
+ // ../tracking-core/src/lead-forms/lead-forms.gen.ts
1788
+ import * as z3 from "zod/mini";
1716
1789
  var LEAD_FORM_REGISTRY_VERSION = 2;
1717
1790
  var LEAD_FORM_KINDS = ["booking", "quote", "contact", "consult", "callback"];
1718
1791
  var LEAD_FORM_ROLES = [
@@ -1752,28 +1825,28 @@ var LEAD_FORM_PRIMITIVES = [
1752
1825
  "number"
1753
1826
  ];
1754
1827
  var leadFormPrimitiveSchemas = /* @__PURE__ */ (() => ({
1755
- string: z2.string().check(z2.maxLength(120)),
1756
- text: z2.string().check(z2.maxLength(2e3)),
1757
- enum: z2.string().check(z2.regex(/^[a-z0-9-]{1,48}$/)),
1758
- multi_enum: z2.array(z2.string().check(z2.regex(/^[a-z0-9-]{1,48}$/))).check(z2.maxLength(10)),
1759
- bool: z2.boolean(),
1760
- date: z2.string().check(z2.regex(/^\d{4}-\d{2}-\d{2}$/)),
1761
- time_window: z2.strictObject({
1762
- start: z2.string().check(z2.regex(/^([01]\d|2[0-3]):[0-5]\d$/)),
1763
- end: z2.nullable(z2.string().check(z2.regex(/^([01]\d|2[0-3]):[0-5]\d$/))),
1764
- label: z2.optional(z2.string().check(z2.maxLength(60)))
1828
+ string: z3.string().check(z3.maxLength(120)),
1829
+ text: z3.string().check(z3.maxLength(2e3)),
1830
+ enum: z3.string().check(z3.regex(/^[a-z0-9-]{1,48}$/)),
1831
+ multi_enum: z3.array(z3.string().check(z3.regex(/^[a-z0-9-]{1,48}$/))).check(z3.maxLength(10)),
1832
+ bool: z3.boolean(),
1833
+ date: z3.string().check(z3.regex(/^\d{4}-\d{2}-\d{2}$/)),
1834
+ time_window: z3.strictObject({
1835
+ start: z3.string().check(z3.regex(/^([01]\d|2[0-3]):[0-5]\d$/)),
1836
+ end: z3.nullable(z3.string().check(z3.regex(/^([01]\d|2[0-3]):[0-5]\d$/))),
1837
+ label: z3.optional(z3.string().check(z3.maxLength(60)))
1765
1838
  }),
1766
- phone: z2.string().check(z2.regex(/^\+[1-9]\d{6,14}$/)),
1767
- email: z2.string().check(z2.maxLength(320), z2.regex(/^[^\s@]+@[^\s@]+$/)),
1768
- address: z2.strictObject({
1769
- line1: z2.string().check(z2.maxLength(120)),
1770
- line2: z2.optional(z2.string().check(z2.maxLength(120))),
1771
- city: z2.optional(z2.string().check(z2.maxLength(120))),
1772
- region: z2.optional(z2.string().check(z2.maxLength(120))),
1773
- postal_code: z2.optional(z2.string().check(z2.maxLength(120))),
1774
- country: z2.optional(z2.string().check(z2.maxLength(120)))
1839
+ phone: z3.string().check(z3.regex(/^\+[1-9]\d{6,14}$/)),
1840
+ email: z3.string().check(z3.maxLength(320), z3.regex(/^[^\s@]+@[^\s@]+$/)),
1841
+ address: z3.strictObject({
1842
+ line1: z3.string().check(z3.maxLength(120)),
1843
+ line2: z3.optional(z3.string().check(z3.maxLength(120))),
1844
+ city: z3.optional(z3.string().check(z3.maxLength(120))),
1845
+ region: z3.optional(z3.string().check(z3.maxLength(120))),
1846
+ postal_code: z3.optional(z3.string().check(z3.maxLength(120))),
1847
+ country: z3.optional(z3.string().check(z3.maxLength(120)))
1775
1848
  }),
1776
- number: z2.number()
1849
+ number: z3.number()
1777
1850
  }))();
1778
1851
  var LEAD_FORM_ROLE_SPECS = {
1779
1852
  given_name: { primitive: "string", smsLabel: "", contactIdentity: true },
@@ -1823,6 +1896,101 @@ var LEAD_FORM_ROLE_SPECS = {
1823
1896
  attribution: { primitive: "enum", smsLabel: "", uninteresting: true }
1824
1897
  };
1825
1898
 
1899
+ // ../tracking-core/src/lead-forms/submit.ts
1900
+ import { safeParse as safeParse2 } from "zod/mini";
1901
+ var KNOWN_ROLES = new Set(LEAD_FORM_ROLES);
1902
+ var ROLE_ORDER = new Map(LEAD_FORM_ROLES.map((role, index) => [role, index]));
1903
+ var ADD_ON = /^add_on:[a-z0-9_-]{1,48}$/;
1904
+ var CONTRACT_NAME = /^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?$/;
1905
+ function judgeLeadForm(kind, formId, fields, contracts, settings) {
1906
+ const generated = contracts?.contracts[kind];
1907
+ const live = liveContract(settings.trackingConfig, kind);
1908
+ const violations = check(live === void 0 ? generated : fromLive(live), fields);
1909
+ const liveHash = live === void 0 ? void 0 : live?.contract_hash ?? null;
1910
+ if (contracts && (liveHash !== void 0 && (generated?.hash ?? null) !== liveHash || contracts.registryVersion !== LEAD_FORM_REGISTRY_VERSION)) {
1911
+ violations.push({ role: null, rule: "contract_behind" });
1912
+ }
1913
+ if (violations.length > 0 && (settings.debug || settings.environment === "development")) {
1914
+ const message = `[AranovaTracking] lead form "${formId}" (${kind}) breaks its contract: ${violations.map((v) => `${v.rule}${v.role ? ` (${v.role})` : ""}`).join(", ")}`;
1915
+ console.error(message);
1916
+ if (settings.debug) throw new Error(message);
1917
+ }
1918
+ return {
1919
+ violations,
1920
+ hash: liveHash === void 0 ? generated?.hash ?? null : liveHash
1921
+ };
1922
+ }
1923
+ function liveContract(ref, kind) {
1924
+ const leadForms = ref ? getTrackingConfigRuntime(ref).leadForms() : null;
1925
+ if (!leadForms) return void 0;
1926
+ return leadForms.contracts.find((c) => c.form_kind === kind) ?? null;
1927
+ }
1928
+ function fromLive(live) {
1929
+ if (!live) return void 0;
1930
+ return {
1931
+ requires: live.requires.map((r) => ({
1932
+ role: r.role,
1933
+ requiredWhen: r.required_when ? { role: r.required_when.role, anyOf: r.required_when.any_of } : null
1934
+ })),
1935
+ requiresAny: live.requires_any.map((g) => g.roles),
1936
+ // Deprecated keys still resolve: a cached form may send them (ADR-0024 §7).
1937
+ options: Object.fromEntries(live.options.map((o) => [o.role, o.options.map((x) => x.key)]))
1938
+ };
1939
+ }
1940
+ function check(contract, fields) {
1941
+ const answered = new Map(fields);
1942
+ const violations = [];
1943
+ for (const [role, value] of fields) {
1944
+ const primitive = primitiveOf(role);
1945
+ if (!primitive) {
1946
+ violations.push({ role: CONTRACT_NAME.test(role) ? role : null, rule: "unknown_role" });
1947
+ continue;
1948
+ }
1949
+ if (!safeParse2(leadFormPrimitiveSchemas[primitive], value).success) {
1950
+ violations.push({ role, rule: "invalid_value" });
1951
+ continue;
1952
+ }
1953
+ const allowed = contract?.options[role] ?? registryOptions(role);
1954
+ if (allowed?.length && optionKeys(value).some((key) => !allowed.includes(key))) {
1955
+ violations.push({ role, rule: "unknown_option" });
1956
+ }
1957
+ }
1958
+ for (const { role, requiredWhen } of contract?.requires ?? []) {
1959
+ const owing = requiredWhen === null || optionKeys(answered.get(requiredWhen.role)).some((key) => requiredWhen.anyOf.includes(key));
1960
+ if (owing && !answered.has(role)) violations.push({ role, rule: "missing_required" });
1961
+ }
1962
+ for (const group of contract?.requiresAny ?? []) {
1963
+ if (!group.some((role) => answered.has(role))) {
1964
+ violations.push({ role: group.join("|"), rule: "missing_any_of" });
1965
+ }
1966
+ }
1967
+ return violations;
1968
+ }
1969
+ function primitiveOf(role) {
1970
+ if (ADD_ON.test(role)) return "bool";
1971
+ return KNOWN_ROLES.has(role) ? LEAD_FORM_ROLE_SPECS[role].primitive : null;
1972
+ }
1973
+ function registryOptions(role) {
1974
+ const spec = KNOWN_ROLES.has(role) ? LEAD_FORM_ROLE_SPECS[role] : void 0;
1975
+ return spec && "options" in spec ? spec.options.map((o) => o.key) : void 0;
1976
+ }
1977
+ function optionKeys(value) {
1978
+ if (typeof value === "string") return [value];
1979
+ return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
1980
+ }
1981
+ function slotFields(dateTime) {
1982
+ const written = /^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2})(?::\d{2}(?:\.\d+)?)?$/.exec(dateTime);
1983
+ if (!written) {
1984
+ throw new TypeError(
1985
+ `slotFields needs the slot's wall time without an offset ("2026-10-13T09:30"), got "${dateTime}"`
1986
+ );
1987
+ }
1988
+ return { preferred_date: written[1], preferred_time: { start: written[2], end: null } };
1989
+ }
1990
+ function timeWindow(start, end, label) {
1991
+ return { start, end: end ?? null, ...label ? { label } : {} };
1992
+ }
1993
+
1826
1994
  // ../tracking-core/src/resources/http/errors.ts
1827
1995
  var AranovaApiError = class extends Error {
1828
1996
  constructor(message, options) {
@@ -1862,11 +2030,11 @@ async function apiRequest(config, method, path, body, extraHeaders) {
1862
2030
  try {
1863
2031
  const parsed = await response.json();
1864
2032
  if (parsed && typeof parsed === "object") {
1865
- const record3 = parsed;
1866
- if (typeof record3.detail === "string") detail = record3.detail;
1867
- if (typeof record3.code === "string") code = record3.code;
1868
- if (record3.context && typeof record3.context === "object") {
1869
- context = record3.context;
2033
+ const record4 = parsed;
2034
+ if (typeof record4.detail === "string") detail = record4.detail;
2035
+ if (typeof record4.code === "string") code = record4.code;
2036
+ if (record4.context && typeof record4.context === "object") {
2037
+ context = record4.context;
1870
2038
  }
1871
2039
  }
1872
2040
  } catch {
@@ -1920,7 +2088,7 @@ var DROP_OFF_KEYS = {
1920
2088
  waitForIt: "wait-for-it",
1921
2089
  dropOff: "drop-off"
1922
2090
  };
1923
- function formSubmitPayload(input, formSubmit, contractHash) {
2091
+ function formSubmitPayload(input, formSubmit, runtime) {
1924
2092
  const field = (role, name, type, label, value) => ({ name, type, label, value, role });
1925
2093
  const text = (value) => value?.trim() || void 0;
1926
2094
  const { vehicle, dropOff } = input;
@@ -1930,7 +2098,7 @@ function formSubmitPayload(input, formSubmit, contractHash) {
1930
2098
  // E.164 on the wire: it keys the customer and enhanced-conversion matching.
1931
2099
  field("phone", "phone", "tel", "Phone", toE164(input.phone) ?? input.phone),
1932
2100
  field("email", "email", "email", "Email", text(input.email)),
1933
- field("service", "service", "select", "Service", input.services),
2101
+ field("service", "service", "select", "Service", [...input.services]),
1934
2102
  field(
1935
2103
  "vehicle",
1936
2104
  "vehicle",
@@ -1955,6 +2123,14 @@ function formSubmitPayload(input, formSubmit, contractHash) {
1955
2123
  const reported = new Set(entries.map((item) => item.name));
1956
2124
  const fields = entries.filter((item) => item.value !== void 0);
1957
2125
  const extra = (formSubmit.extraFields ?? []).filter((item) => !reported.has(item.name));
2126
+ const settings = typedClientSettings(formSubmit.tracking);
2127
+ const { violations, hash } = judgeLeadForm(
2128
+ "booking",
2129
+ formSubmit.formId,
2130
+ fields.map((item) => [item.role, item.value]),
2131
+ formSubmit.contracts,
2132
+ { ...settings, trackingConfig: settings.trackingConfig ?? runtime?.ref }
2133
+ );
1958
2134
  return {
1959
2135
  form: {
1960
2136
  id: formSubmit.formId,
@@ -1962,7 +2138,8 @@ function formSubmitPayload(input, formSubmit, contractHash) {
1962
2138
  fields: [...fields, ...extra],
1963
2139
  kind: "booking",
1964
2140
  contract_version: LEAD_FORM_REGISTRY_VERSION,
1965
- ...contractHash ? { contract_hash: contractHash } : {}
2141
+ ...hash ? { contract_hash: hash } : {},
2142
+ ...violations.length > 0 ? { contract_violations: violations.slice(0, MAX_CONTRACT_VIOLATIONS) } : {}
1966
2143
  },
1967
2144
  page: { path: typeof window === "undefined" ? "/" : window.location.pathname }
1968
2145
  };
@@ -2061,10 +2238,9 @@ function createSalesBookingsClient(config, firing) {
2061
2238
  }
2062
2239
  if (formSubmit && !submittedForms.has(attemptKey)) {
2063
2240
  submittedForms.add(attemptKey);
2064
- const contract = runtime?.leadForms()?.contracts.find((c) => c.form_kind === "booking");
2065
2241
  formSubmit.tracking.trackEvent(
2066
2242
  "form_submit",
2067
- formSubmitPayload(input, formSubmit, contract?.contract_hash ?? null)
2243
+ formSubmitPayload(input, formSubmit, runtime)
2068
2244
  );
2069
2245
  }
2070
2246
  const body = {
@@ -2080,7 +2256,7 @@ function createSalesBookingsClient(config, firing) {
2080
2256
  email: input.email?.trim() || null,
2081
2257
  vehicle: input.vehicle ?? null,
2082
2258
  drop_off: input.dropOff ?? null,
2083
- services: input.services,
2259
+ services: [...input.services],
2084
2260
  notes: input.notes?.trim() || null,
2085
2261
  marketing_sms_consent: input.marketingSmsConsent === true,
2086
2262
  page_path: typeof window === "undefined" ? null : window.location.pathname
@@ -2167,7 +2343,7 @@ function fireRecordedConversions(firing, input, recorded, sale, currency) {
2167
2343
  }
2168
2344
  function createSalesClient(config) {
2169
2345
  if (config.firing) registerCapability("conversion_goals_manual");
2170
- async function record3(input) {
2346
+ async function record4(input) {
2171
2347
  const currency = input.currency ?? config.defaultCurrency;
2172
2348
  if (!currency) {
2173
2349
  throw new Error(
@@ -2193,9 +2369,9 @@ function createSalesClient(config) {
2193
2369
  return sale;
2194
2370
  }
2195
2371
  return {
2196
- record: record3,
2372
+ record: record4,
2197
2373
  // recordSale is the intent-revealing alias — same behavior, clearer call site.
2198
- recordSale: record3,
2374
+ recordSale: record4,
2199
2375
  trackConversion(key, options) {
2200
2376
  if (config.firing && "fireConversion" in config.firing) {
2201
2377
  if (options?.userData && getConsentState() !== "denied") stashUserData(options.userData);
@@ -2315,17 +2491,17 @@ function createSalesClient(config) {
2315
2491
  }
2316
2492
 
2317
2493
  // ../tracking-core/src/resources/sales/schema.ts
2318
- import * as z4 from "zod/mini";
2494
+ import * as z5 from "zod/mini";
2319
2495
 
2320
2496
  // ../tracking-core/src/resources/sales/generated/zod.gen.ts
2321
- import * as z3 from "zod/mini";
2322
- var zAutoLeapSaleFacts = z3.object({
2323
- first_order: z3.boolean(),
2324
- fleet_customer: z3.boolean(),
2325
- invoice_code: z3.string(),
2326
- invoice_id: z3.string()
2497
+ import * as z4 from "zod/mini";
2498
+ var zAutoLeapSaleFacts = z4.object({
2499
+ first_order: z4.boolean(),
2500
+ fleet_customer: z4.boolean(),
2501
+ invoice_code: z4.string(),
2502
+ invoice_id: z4.string()
2327
2503
  });
2328
- var zErrorCode = z3.enum([
2504
+ var zErrorCode = z4.enum([
2329
2505
  "missing_credentials",
2330
2506
  "invalid_api_key",
2331
2507
  "not_authenticated",
@@ -2369,37 +2545,37 @@ var zErrorCode = z3.enum([
2369
2545
  "rate_limited",
2370
2546
  "internal_error"
2371
2547
  ]);
2372
- var zSaleItemEntitySchema = z3.object({
2373
- category: z3.nullable(z3.string()),
2374
- external_item_id: z3.nullable(z3.string()),
2375
- id: z3.uuid(),
2376
- name: z3.nullable(z3.string()),
2377
- quantity: z3.string().check(z3.regex(/^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$/)),
2378
- unit_cost_cents: z3.nullable(z3.int()),
2379
- unit_price_cents: z3.int()
2548
+ var zSaleItemEntitySchema = z4.object({
2549
+ category: z4.nullable(z4.string()),
2550
+ external_item_id: z4.nullable(z4.string()),
2551
+ id: z4.uuid(),
2552
+ name: z4.nullable(z4.string()),
2553
+ quantity: z4.string().check(z4.regex(/^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$/)),
2554
+ unit_cost_cents: z4.nullable(z4.int()),
2555
+ unit_price_cents: z4.int()
2380
2556
  });
2381
- var zSaleItemInputSchema = z3.strictObject({
2382
- category: z3.nullish(z3.string()),
2383
- external_item_id: z3.nullish(z3.string()),
2384
- name: z3.nullish(z3.string()),
2385
- quantity: z3.string().check(z3.regex(/^\d+(\.\d{1,3})?$/)),
2386
- unit_cost_cents: z3.nullish(z3.int().check(z3.gte(0))),
2387
- unit_price_cents: z3.int().check(z3.gte(0))
2557
+ var zSaleItemInputSchema = z4.strictObject({
2558
+ category: z4.nullish(z4.string()),
2559
+ external_item_id: z4.nullish(z4.string()),
2560
+ name: z4.nullish(z4.string()),
2561
+ quantity: z4.string().check(z4.regex(/^\d+(\.\d{1,3})?$/)),
2562
+ unit_cost_cents: z4.nullish(z4.int().check(z4.gte(0))),
2563
+ unit_price_cents: z4.int().check(z4.gte(0))
2388
2564
  });
2389
- var zSaleServiceEntitySchema = z3.object({
2390
- amount_cents: z3.int(),
2391
- id: z3.uuid(),
2392
- mapped: z3.nullable(z3.boolean()),
2393
- service_id: z3.uuid(),
2394
- service_key: z3.string(),
2395
- service_label: z3.string()
2565
+ var zSaleServiceEntitySchema = z4.object({
2566
+ amount_cents: z4.int(),
2567
+ id: z4.uuid(),
2568
+ mapped: z4.nullable(z4.boolean()),
2569
+ service_id: z4.uuid(),
2570
+ service_key: z4.string(),
2571
+ service_label: z4.string()
2396
2572
  });
2397
- var zSaleServiceInputSchema = z3.strictObject({
2398
- amount_cents: z3.int().check(z3.gte(0)),
2399
- service: z3.string()
2573
+ var zSaleServiceInputSchema = z4.strictObject({
2574
+ amount_cents: z4.int().check(z4.gte(0)),
2575
+ service: z4.string()
2400
2576
  });
2401
- var zSaleSource = z3.enum(["api", "admin", "autoleap"]);
2402
- var zSmsAutomationState = z3.enum([
2577
+ var zSaleSource = z4.enum(["api", "admin", "autoleap"]);
2578
+ var zSmsAutomationState = z4.enum([
2403
2579
  "needs_check",
2404
2580
  "failed",
2405
2581
  "undelivered",
@@ -2411,7 +2587,7 @@ var zSmsAutomationState = z3.enum([
2411
2587
  "eligible",
2412
2588
  "not_applicable"
2413
2589
  ]);
2414
- var zSmsWithheldReason = z3.enum([
2590
+ var zSmsWithheldReason = z4.enum([
2415
2591
  "automation_disabled",
2416
2592
  "sms_disabled",
2417
2593
  "no_phone",
@@ -2437,77 +2613,80 @@ var zSmsWithheldReason = z3.enum([
2437
2613
  "confirmed_by_integration",
2438
2614
  "test_or_bot_session",
2439
2615
  "invalid_phone",
2440
- "recently_texted"
2616
+ "recently_texted",
2617
+ "do_not_contact",
2618
+ "do_not_text_tag",
2619
+ "missing_value"
2441
2620
  ]);
2442
- var zSaleSmsStatusSchema = z3.object({
2443
- can_send_now: z3._default(z3.boolean(), false),
2444
- last_message_at: z3.nullable(z3.iso.datetime({ offset: true })),
2445
- reason_detail: z3.nullable(z3.string()),
2621
+ var zSaleSmsStatusSchema = z4.object({
2622
+ can_send_now: z4._default(z4.boolean(), false),
2623
+ last_message_at: z4.nullable(z4.iso.datetime({ offset: true })),
2624
+ reason_detail: z4.nullable(z4.string()),
2446
2625
  state: zSmsAutomationState,
2447
- suppressed_by_other_sale: z3._default(z3.boolean(), false),
2448
- withheld_reason: z3.nullable(zSmsWithheldReason)
2626
+ suppressed_by_other_sale: z4._default(z4.boolean(), false),
2627
+ withheld_reason: z4.nullable(zSmsWithheldReason)
2449
2628
  });
2450
- var zSupportedCurrency = z3.enum(["USD", "CAD"]);
2451
- var zTrackingEnvironment = z3.enum(["production", "development"]);
2452
- var zSaleCreateSchema = z3.strictObject({
2453
- amount_total_cents: z3.nullish(z3.int().check(z3.gte(0))),
2629
+ var zSupportedCurrency = z4.enum(["USD", "CAD"]);
2630
+ var zTrackingEnvironment = z4.enum(["production", "development"]);
2631
+ var zSaleCreateSchema = z4.strictObject({
2632
+ amount_total_cents: z4.nullish(z4.int().check(z4.gte(0))),
2454
2633
  currency: zSupportedCurrency,
2455
- customer_email: z3.nullish(z3.email().check(z3.maxLength(320))),
2456
- customer_name: z3.nullish(z3.string().check(z3.maxLength(200))),
2457
- customer_phone: z3.nullish(z3.string().check(z3.maxLength(64))),
2458
- description: z3.nullish(z3.string()),
2459
- environment: z3._default(z3.optional(zTrackingEnvironment), "production"),
2460
- external_id: z3.nullish(z3.string()),
2461
- items: z3.optional(z3.array(zSaleItemInputSchema)),
2462
- metadata: z3.nullish(z3.record(z3.string(), z3.unknown())),
2463
- occurred_at: z3.iso.datetime({ offset: true }),
2464
- service: z3.nullish(z3.string()),
2465
- services: z3.nullish(z3.array(zSaleServiceInputSchema)),
2466
- sms_consent: z3.nullish(z3.boolean())
2634
+ customer_email: z4.nullish(z4.email().check(z4.maxLength(320))),
2635
+ customer_name: z4.nullish(z4.string().check(z4.maxLength(200))),
2636
+ customer_phone: z4.nullish(z4.string().check(z4.maxLength(64))),
2637
+ description: z4.nullish(z4.string()),
2638
+ environment: z4._default(z4.optional(zTrackingEnvironment), "production"),
2639
+ external_id: z4.nullish(z4.string()),
2640
+ items: z4.optional(z4.array(zSaleItemInputSchema)),
2641
+ metadata: z4.nullish(z4.record(z4.string(), z4.unknown())),
2642
+ occurred_at: z4.iso.datetime({ offset: true }),
2643
+ service: z4.nullish(z4.string()),
2644
+ services: z4.nullish(z4.array(zSaleServiceInputSchema)),
2645
+ sms_consent: z4.nullish(z4.boolean())
2467
2646
  });
2468
- var zValidationError = z3.object({
2469
- ctx: z3.optional(z3.record(z3.string(), z3.unknown())),
2470
- input: z3.optional(z3.unknown()),
2471
- loc: z3.array(z3.union([z3.string(), z3.int()])),
2472
- msg: z3.string(),
2473
- type: z3.string()
2647
+ var zValidationError = z4.object({
2648
+ ctx: z4.optional(z4.record(z4.string(), z4.unknown())),
2649
+ input: z4.optional(z4.unknown()),
2650
+ loc: z4.array(z4.union([z4.string(), z4.int()])),
2651
+ msg: z4.string(),
2652
+ type: z4.string()
2474
2653
  });
2475
- var zHttpValidationError = z3.object({
2476
- detail: z3.optional(z3.array(zValidationError))
2654
+ var zHttpValidationError = z4.object({
2655
+ detail: z4.optional(z4.array(zValidationError))
2477
2656
  });
2478
- var zValidationErrorItem = z3.object({
2479
- loc: z3.array(z3.union([z3.string(), z3.int()])),
2480
- msg: z3.string(),
2481
- type: z3.string()
2657
+ var zValidationErrorItem = z4.object({
2658
+ loc: z4.array(z4.union([z4.string(), z4.int()])),
2659
+ msg: z4.string(),
2660
+ type: z4.string()
2482
2661
  });
2483
- var zApiErrorSchema = z3.object({
2662
+ var zApiErrorSchema = z4.object({
2484
2663
  code: zErrorCode,
2485
- context: z3._default(z3.nullish(z3.record(z3.string(), z3.unknown())), null),
2486
- detail: z3.string(),
2487
- errors: z3._default(z3.nullish(z3.array(zValidationErrorItem)), null),
2488
- request_id: z3._default(z3.nullish(z3.string()), null)
2664
+ context: z4._default(z4.nullish(z4.record(z4.string(), z4.unknown())), null),
2665
+ detail: z4.string(),
2666
+ errors: z4._default(z4.nullish(z4.array(zValidationErrorItem)), null),
2667
+ request_id: z4._default(z4.nullish(z4.string()), null)
2489
2668
  });
2490
- var zWritebackEmailSource = z3.enum(["NONE", "SALE", "CUSTOMER", "HARVESTED"]);
2491
- var zWritebackEnrichmentStatus = z3.enum(["NONE", "MATCHED", "AMBIGUOUS"]);
2492
- var zWritebackSaleUploadCounts = z3.object({
2493
- failed: z3._default(z3.int(), 0),
2494
- pending: z3._default(z3.int(), 0),
2495
- skipped: z3._default(z3.int(), 0),
2496
- submitted: z3._default(z3.int(), 0),
2497
- total: z3._default(z3.int(), 0),
2498
- uploaded: z3._default(z3.int(), 0)
2669
+ var zWritebackEmailSource = z4.enum(["NONE", "SALE", "CUSTOMER", "HARVESTED"]);
2670
+ var zWritebackEnrichmentStatus = z4.enum(["NONE", "MATCHED", "AMBIGUOUS"]);
2671
+ var zWritebackSaleUploadCounts = z4.object({
2672
+ failed: z4._default(z4.int(), 0),
2673
+ pending: z4._default(z4.int(), 0),
2674
+ skipped: z4._default(z4.int(), 0),
2675
+ submitted: z4._default(z4.int(), 0),
2676
+ total: z4._default(z4.int(), 0),
2677
+ uploaded: z4._default(z4.int(), 0)
2499
2678
  });
2500
- var zSaleWritebackStatusSchema = z3.object({
2501
- blocked_reason: z3.nullable(z3.string()),
2502
- can_dispatch: z3._default(z3.boolean(), false),
2503
- email_source: z3.nullable(zWritebackEmailSource),
2504
- enrichment_status: z3.nullable(zWritebackEnrichmentStatus),
2505
- gclid_attached: z3._default(z3.boolean(), false),
2506
- identifiers_sent: z3.nullable(z3.string()),
2507
- mapped_service_ids: z3.array(z3.uuid()),
2508
- matched_submit_count: z3.nullable(z3.int()),
2509
- needs_force: z3._default(z3.boolean(), false),
2510
- rollup: z3.enum([
2679
+ var zSaleWritebackStatusSchema = z4.object({
2680
+ blocked_reason: z4.nullable(z4.string()),
2681
+ can_dispatch: z4._default(z4.boolean(), false),
2682
+ email_source: z4.nullable(zWritebackEmailSource),
2683
+ enrichment_status: z4.nullable(zWritebackEnrichmentStatus),
2684
+ gclid_attached: z4._default(z4.boolean(), false),
2685
+ identifiers_sent: z4.nullable(z4.string()),
2686
+ mapped_service_ids: z4.array(z4.uuid()),
2687
+ matched_submit_count: z4.nullable(z4.int()),
2688
+ needs_force: z4._default(z4.boolean(), false),
2689
+ rollup: z4.enum([
2511
2690
  "failed",
2512
2691
  "skipped",
2513
2692
  "pending",
@@ -2517,39 +2696,39 @@ var zSaleWritebackStatusSchema = z3.object({
2517
2696
  "out_of_window",
2518
2697
  "blocked"
2519
2698
  ]),
2520
- stale: z3._default(z3.boolean(), false),
2521
- uncovered_service_ids: z3.array(z3.uuid()),
2699
+ stale: z4._default(z4.boolean(), false),
2700
+ uncovered_service_ids: z4.array(z4.uuid()),
2522
2701
  uploads: zWritebackSaleUploadCounts
2523
2702
  });
2524
- var zSaleEntitySchema = z3.object({
2525
- amount_total_cents: z3.int(),
2526
- business_id: z3.uuid(),
2527
- business_name: z3.nullable(z3.string()),
2528
- created_at: z3.iso.datetime({ offset: true }),
2529
- currency: z3.string(),
2530
- customer_email: z3.nullable(z3.string()),
2531
- customer_name: z3.nullable(z3.string()),
2532
- customer_name_placeholder_confirmed: z3._default(z3.boolean(), false),
2533
- customer_name_placeholder_confirmed_at: z3.nullable(z3.iso.datetime({ offset: true })),
2534
- customer_phone: z3.nullable(z3.string()),
2535
- description: z3.nullable(z3.string()),
2703
+ var zSaleEntitySchema = z4.object({
2704
+ amount_total_cents: z4.int(),
2705
+ business_id: z4.uuid(),
2706
+ business_name: z4.nullable(z4.string()),
2707
+ created_at: z4.iso.datetime({ offset: true }),
2708
+ currency: z4.string(),
2709
+ customer_email: z4.nullable(z4.string()),
2710
+ customer_name: z4.nullable(z4.string()),
2711
+ customer_name_placeholder_confirmed: z4._default(z4.boolean(), false),
2712
+ customer_name_placeholder_confirmed_at: z4.nullable(z4.iso.datetime({ offset: true })),
2713
+ customer_phone: z4.nullable(z4.string()),
2714
+ description: z4.nullable(z4.string()),
2536
2715
  environment: zTrackingEnvironment,
2537
- external_id: z3.nullable(z3.string()),
2538
- id: z3.uuid(),
2539
- items: z3.array(zSaleItemEntitySchema),
2540
- metadata: z3.nullable(z3.record(z3.string(), z3.unknown())),
2541
- occurred_at: z3.iso.datetime({ offset: true }),
2542
- service_id: z3.nullable(z3.uuid()),
2543
- service_key: z3.nullable(z3.string()),
2544
- service_label: z3.nullable(z3.string()),
2545
- services: z3.array(zSaleServiceEntitySchema),
2546
- sms_automation: z3.nullable(zSaleSmsStatusSchema),
2547
- sms_consent: z3._default(z3.boolean(), false),
2548
- sms_consent_granted_at: z3.nullable(z3.iso.datetime({ offset: true })),
2716
+ external_id: z4.nullable(z4.string()),
2717
+ id: z4.uuid(),
2718
+ items: z4.array(zSaleItemEntitySchema),
2719
+ metadata: z4.nullable(z4.record(z4.string(), z4.unknown())),
2720
+ occurred_at: z4.iso.datetime({ offset: true }),
2721
+ service_id: z4.nullable(z4.uuid()),
2722
+ service_key: z4.nullable(z4.string()),
2723
+ service_label: z4.nullable(z4.string()),
2724
+ services: z4.array(zSaleServiceEntitySchema),
2725
+ sms_automation: z4.nullable(zSaleSmsStatusSchema),
2726
+ sms_consent: z4._default(z4.boolean(), false),
2727
+ sms_consent_granted_at: z4.nullable(z4.iso.datetime({ offset: true })),
2549
2728
  source: zSaleSource,
2550
- source_facts: z3.nullable(zAutoLeapSaleFacts),
2551
- updated_at: z3.iso.datetime({ offset: true }),
2552
- writeback: z3.nullable(zSaleWritebackStatusSchema)
2729
+ source_facts: z4.nullable(zAutoLeapSaleFacts),
2730
+ updated_at: z4.iso.datetime({ offset: true }),
2731
+ writeback: z4.nullable(zSaleWritebackStatusSchema)
2553
2732
  });
2554
2733
 
2555
2734
  // ../tracking-core/src/resources/sales/schema.ts
@@ -2558,11 +2737,11 @@ var saleServiceSchema = zSaleServiceInputSchema;
2558
2737
  var currencySchema = zSupportedCurrency;
2559
2738
  var SUPPORTED_CURRENCIES = currencySchema.options;
2560
2739
  var SALE_SOURCES = zSaleSource.options;
2561
- var centsSchema = z4.int().check(z4.gte(0));
2562
- var metadataSchema = z4.record(z4.string(), z4.unknown());
2563
- var customerNameSchema = z4.string().check(z4.maxLength(200));
2564
- var customerPhoneSchema = z4.string().check(z4.maxLength(64));
2565
- var customerEmailSchema = z4.email().check(z4.maxLength(320));
2740
+ var centsSchema = z5.int().check(z5.gte(0));
2741
+ var metadataSchema = z5.record(z5.string(), z5.unknown());
2742
+ var customerNameSchema = z5.string().check(z5.maxLength(200));
2743
+ var customerPhoneSchema = z5.string().check(z5.maxLength(64));
2744
+ var customerEmailSchema = z5.email().check(z5.maxLength(320));
2566
2745
  function addIssue(ctx, path, message) {
2567
2746
  ctx.issues.push({ code: "custom", input: ctx.value, path, message });
2568
2747
  }
@@ -2596,24 +2775,24 @@ function refineServiceXor(val, ctx, { requireAmount }) {
2596
2775
  );
2597
2776
  }
2598
2777
  }
2599
- var saleCreateSchema = z4.extend(zSaleCreateSchema, { items: z4._default(z4.array(saleItemSchema), []) }).check((ctx) => refineServiceXor(ctx.value, ctx, { requireAmount: true }));
2600
- var saleUpdateSchema = z4.strictObject({
2601
- description: z4.nullish(z4.string()),
2602
- service: z4.nullish(z4.string()),
2603
- services: z4.nullish(z4.array(saleServiceSchema)),
2604
- currency: z4.optional(currencySchema),
2605
- amount_total_cents: z4.optional(centsSchema),
2606
- occurred_at: z4.optional(z4.iso.datetime()),
2607
- items: z4.optional(z4.array(saleItemSchema)),
2608
- metadata: z4.nullish(metadataSchema),
2609
- customer_name: z4.nullish(customerNameSchema),
2778
+ var saleCreateSchema = z5.extend(zSaleCreateSchema, { items: z5._default(z5.array(saleItemSchema), []) }).check((ctx) => refineServiceXor(ctx.value, ctx, { requireAmount: true }));
2779
+ var saleUpdateSchema = z5.strictObject({
2780
+ description: z5.nullish(z5.string()),
2781
+ service: z5.nullish(z5.string()),
2782
+ services: z5.nullish(z5.array(saleServiceSchema)),
2783
+ currency: z5.optional(currencySchema),
2784
+ amount_total_cents: z5.optional(centsSchema),
2785
+ occurred_at: z5.optional(z5.iso.datetime()),
2786
+ items: z5.optional(z5.array(saleItemSchema)),
2787
+ metadata: z5.nullish(metadataSchema),
2788
+ customer_name: z5.nullish(customerNameSchema),
2610
2789
  // Re-attest when changing a filler-looking name; the server clears the
2611
2790
  // prior attestation whenever `customer_name` changes.
2612
- customer_name_placeholder_confirmed: z4.optional(z4.boolean()),
2613
- customer_phone: z4.nullish(customerPhoneSchema),
2614
- customer_email: z4.nullish(customerEmailSchema),
2791
+ customer_name_placeholder_confirmed: z5.optional(z5.boolean()),
2792
+ customer_phone: z5.nullish(customerPhoneSchema),
2793
+ customer_email: z5.nullish(customerEmailSchema),
2615
2794
  // NOT NULL server-side: omit to leave unchanged (explicit null is rejected).
2616
- sms_consent: z4.optional(z4.boolean())
2795
+ sms_consent: z5.optional(z5.boolean())
2617
2796
  }).check((ctx) => refineServiceXor(ctx.value, ctx, { requireAmount: false }));
2618
2797
  var TRACKING_RANGES = ["24h", "7d", "30d"];
2619
2798
  var NAMED_RANGES = [
@@ -2640,23 +2819,6 @@ function phoneField(name, raw, country, label = null) {
2640
2819
  return { name, type: "phone", label, value: toE164(raw, country) };
2641
2820
  }
2642
2821
 
2643
- // ../tracking-core/src/lead-forms/submit.ts
2644
- import { safeParse } from "zod/mini";
2645
- var KNOWN_ROLES = new Set(LEAD_FORM_ROLES);
2646
- var ROLE_ORDER = new Map(LEAD_FORM_ROLES.map((role, index) => [role, index]));
2647
- function slotFields(dateTime) {
2648
- const written = /^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2})(?::\d{2}(?:\.\d+)?)?$/.exec(dateTime);
2649
- if (!written) {
2650
- throw new TypeError(
2651
- `slotFields needs the slot's wall time without an offset ("2026-10-13T09:30"), got "${dateTime}"`
2652
- );
2653
- }
2654
- return { preferred_date: written[1], preferred_time: { start: written[2], end: null } };
2655
- }
2656
- function timeWindow(start, end, label) {
2657
- return { start, end: end ?? null, ...label ? { label } : {} };
2658
- }
2659
-
2660
2822
  // src/index.ts
2661
2823
  import {
2662
2824
  PhoneField,