@aranova/tracking-react 1.16.1 → 1.18.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/client.mjs CHANGED
@@ -979,9 +979,18 @@ function parseBookingRules(value) {
979
979
  special_hours: parseWindowsMap(r.special_hours),
980
980
  vehicle_required: r.vehicle_required === true,
981
981
  vehicle_deferred: r.vehicle_deferred === true,
982
- drop_off_options: isStringList(r.drop_off_options) ? r.drop_off_options : []
982
+ drop_off_options: isStringList(r.drop_off_options) ? r.drop_off_options : [],
983
+ booked_counts: parseCounts(r.booked_counts)
983
984
  };
984
985
  }
986
+ function parseCounts(value) {
987
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
988
+ const counts = {};
989
+ for (const [date, count] of Object.entries(value)) {
990
+ if (typeof count === "number" && Number.isInteger(count) && count >= 0) counts[date] = count;
991
+ }
992
+ return counts;
993
+ }
985
994
  function parseBookingOption(value) {
986
995
  if (!value || typeof value !== "object") return [];
987
996
  const o = value;
@@ -1774,7 +1783,8 @@ function camelRules(rules) {
1774
1783
  specialHours: rules.special_hours,
1775
1784
  vehicleRequired: rules.vehicle_required,
1776
1785
  vehicleDeferred: rules.vehicle_deferred,
1777
- dropOffOptions: rules.drop_off_options
1786
+ dropOffOptions: rules.drop_off_options,
1787
+ bookedCounts: rules.booked_counts ?? {}
1778
1788
  };
1779
1789
  }
1780
1790
  var WEEKDAYS = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
@@ -1807,7 +1817,8 @@ function bookableSlots(rules, { timeZone, now = /* @__PURE__ */ new Date() }) {
1807
1817
  date,
1808
1818
  weekday,
1809
1819
  morning: [...windows.morning],
1810
- afternoon: [...windows.afternoon]
1820
+ afternoon: [...windows.afternoon],
1821
+ booked: rules.bookedCounts?.[date] ?? 0
1811
1822
  });
1812
1823
  }
1813
1824
  return days;
@@ -1967,6 +1978,13 @@ var EVENT_SEMANTICS = {
1967
1978
  outcomeRole: "engagement",
1968
1979
  clientVisibility: "detailed"
1969
1980
  },
1981
+ // Adds to the submit it names; counting it as a lead would double every lead.
1982
+ form_details: {
1983
+ label: "Form details added",
1984
+ category: "lead",
1985
+ outcomeRole: "engagement",
1986
+ clientVisibility: "detailed"
1987
+ },
1970
1988
  form_submit: {
1971
1989
  label: "Form submitted",
1972
1990
  category: "lead",
@@ -2583,7 +2601,7 @@ function createTrackingClient(config) {
2583
2601
  metadata: input.metadata ?? null,
2584
2602
  occurred_at: occurredAt
2585
2603
  });
2586
- if (queue.length >= maxQueueSize || getEventSemantics(input.eventType)?.outcomeRole === "lead") {
2604
+ if (queue.length >= maxQueueSize || input.eventType === "form_details" || getEventSemantics(input.eventType)?.outcomeRole === "lead") {
2587
2605
  void flush();
2588
2606
  } else {
2589
2607
  scheduleFlush();
@@ -2687,110 +2705,133 @@ var formStartConfigSchema = z5.strictObject({
2687
2705
  selector: z5.optional(z5.string())
2688
2706
  });
2689
2707
 
2690
- // ../tracking-core/src/events/form-step.ts
2708
+ // ../tracking-core/src/events/form-details.ts
2709
+ import * as z7 from "zod/mini";
2710
+
2711
+ // ../tracking-core/src/events/form-submit.ts
2691
2712
  import * as z6 from "zod/mini";
2692
- var formStepMetadataSchema = z6.strictObject({
2713
+ var jsonValueSchema = z6.lazy(
2714
+ () => z6.union([
2715
+ z6.string(),
2716
+ z6.number(),
2717
+ z6.boolean(),
2718
+ z6.null(),
2719
+ z6.array(jsonValueSchema),
2720
+ z6.record(z6.string(), jsonValueSchema)
2721
+ ])
2722
+ ).register(z6.globalRegistry, { id: "JsonSerializableValue" });
2723
+ var contractNameSchema = z6.string().check(z6.regex(/^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?$/));
2724
+ var violationRole = z6.string().check(
2725
+ z6.maxLength(200),
2726
+ z6.regex(
2727
+ /^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?(\|[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?)*$/
2728
+ )
2729
+ );
2730
+ var MAX_CONTRACT_VIOLATIONS = 50;
2731
+ var contractViolationSchema = z6.strictObject({
2732
+ role: z6.nullable(violationRole),
2733
+ rule: z6.string().check(z6.regex(/^[a-z][a-z_]{0,47}$/))
2734
+ });
2735
+ var formFieldSchema = z6.strictObject({
2736
+ name: z6.string(),
2737
+ type: z6.string(),
2738
+ label: z6.nullable(z6.string()),
2739
+ value: jsonValueSchema,
2740
+ role: z6.optional(z6.nullable(contractNameSchema))
2741
+ });
2742
+ var formExtraSchema = z6.optional(
2743
+ z6.nullable(
2744
+ z6.array(
2745
+ z6.strictObject({
2746
+ key: z6.string().check(z6.maxLength(64)),
2747
+ label: z6.string().check(z6.maxLength(200)),
2748
+ value: jsonValueSchema
2749
+ })
2750
+ ).check(z6.maxLength(20))
2751
+ )
2752
+ );
2753
+ var contractVersionSchema = z6.optional(z6.nullable(z6.int().check(z6.gte(1))));
2754
+ var contractHashSchema = z6.optional(z6.nullable(z6.string().check(z6.maxLength(64))));
2755
+ var formContractViolationsSchema = z6.optional(
2756
+ z6.nullable(z6.array(contractViolationSchema).check(z6.maxLength(MAX_CONTRACT_VIOLATIONS)))
2757
+ );
2758
+ var formSubmitMetadataSchema = z6.strictObject({
2693
2759
  form: z6.strictObject({
2694
2760
  id: z6.string(),
2695
- action: z6.nullable(z6.string())
2761
+ action: z6.nullable(z6.string()),
2762
+ fields: z6.optional(z6.array(formFieldSchema)),
2763
+ kind: z6.optional(z6.nullable(contractNameSchema)),
2764
+ contract_version: contractVersionSchema,
2765
+ contract_hash: contractHashSchema,
2766
+ extra: formExtraSchema,
2767
+ contract_violations: formContractViolationsSchema,
2768
+ // Minted per submit; a later `form_details` names it to add answers to this lead.
2769
+ submission_id: z6.optional(z6.nullable(z6.uuidv4()))
2696
2770
  }),
2697
- step: z6.strictObject({
2698
- id: z6.string().check(z6.minLength(1), z6.maxLength(64), z6.regex(/^[A-Za-z0-9_-]+$/)),
2699
- // 1-based position in the flow the visitor is on right now.
2700
- index: z6.int().check(z6.gte(1), z6.lte(50)),
2701
- // Null when the number of steps depends on earlier answers.
2702
- total: z6.nullable(z6.int().check(z6.gte(1), z6.lte(50)))
2703
- }),
2704
- direction: z6.enum(["forward", "back"]),
2705
2771
  page: z6.strictObject({
2706
2772
  path: z6.string()
2707
2773
  })
2708
2774
  });
2709
- var formStepConfigSchema = z6.strictObject({});
2775
+ var formSubmitConfigSchema = z6.strictObject({});
2710
2776
 
2711
- // ../tracking-core/src/events/form-submit.ts
2712
- import * as z7 from "zod/mini";
2713
- var jsonValueSchema = z7.lazy(
2714
- () => z7.union([
2715
- z7.string(),
2716
- z7.number(),
2717
- z7.boolean(),
2718
- z7.null(),
2719
- z7.array(jsonValueSchema),
2720
- z7.record(z7.string(), jsonValueSchema)
2721
- ])
2722
- ).register(z7.globalRegistry, { id: "JsonSerializableValue" });
2723
- var contractNameSchema = z7.string().check(z7.regex(/^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?$/));
2724
- var contractName = contractNameSchema;
2725
- var violationRole = z7.string().check(
2726
- z7.maxLength(200),
2727
- z7.regex(
2728
- /^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?(\|[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?)*$/
2729
- )
2730
- );
2731
- var MAX_CONTRACT_VIOLATIONS = 50;
2732
- var contractViolationSchema = z7.strictObject({
2733
- role: z7.nullable(violationRole),
2734
- rule: z7.string().check(z7.regex(/^[a-z][a-z_]{0,47}$/))
2735
- });
2736
- var formSubmitMetadataSchema = z7.strictObject({
2777
+ // ../tracking-core/src/events/form-details.ts
2778
+ var formDetailsMetadataSchema = z7.strictObject({
2737
2779
  form: z7.strictObject({
2738
2780
  id: z7.string(),
2739
- action: z7.nullable(z7.string()),
2740
- fields: z7.optional(
2741
- z7.array(
2742
- z7.strictObject({
2743
- name: z7.string(),
2744
- type: z7.string(),
2745
- label: z7.nullable(z7.string()),
2746
- value: jsonValueSchema,
2747
- role: z7.optional(z7.nullable(contractName))
2748
- })
2749
- )
2750
- ),
2751
- kind: z7.optional(z7.nullable(contractName)),
2752
- contract_version: z7.optional(z7.nullable(z7.int().check(z7.gte(1)))),
2753
- contract_hash: z7.optional(z7.nullable(z7.string().check(z7.maxLength(64)))),
2754
- extra: z7.optional(
2755
- z7.nullable(
2756
- z7.array(
2757
- z7.strictObject({
2758
- key: z7.string().check(z7.maxLength(64)),
2759
- label: z7.string().check(z7.maxLength(200)),
2760
- value: jsonValueSchema
2761
- })
2762
- ).check(z7.maxLength(20))
2763
- )
2764
- ),
2765
- contract_violations: z7.optional(
2766
- z7.nullable(z7.array(contractViolationSchema).check(z7.maxLength(MAX_CONTRACT_VIOLATIONS)))
2767
- )
2781
+ submission_id: z7.uuidv4(),
2782
+ kind: z7.optional(z7.nullable(contractNameSchema)),
2783
+ fields: z7.array(formFieldSchema),
2784
+ contract_version: contractVersionSchema,
2785
+ contract_hash: contractHashSchema,
2786
+ extra: formExtraSchema,
2787
+ contract_violations: formContractViolationsSchema
2768
2788
  }),
2769
2789
  page: z7.strictObject({
2770
2790
  path: z7.string()
2771
2791
  })
2772
2792
  });
2773
- var formSubmitConfigSchema = z7.strictObject({});
2793
+ var formDetailsConfigSchema = z7.strictObject({});
2774
2794
 
2775
- // ../tracking-core/src/events/multi-page-session.ts
2795
+ // ../tracking-core/src/events/form-step.ts
2776
2796
  import * as z8 from "zod/mini";
2777
- var multiPageSessionMetadataSchema = z8.strictObject({
2778
- page_count: z8.int().check(z8.gte(2)),
2797
+ var formStepMetadataSchema = z8.strictObject({
2798
+ form: z8.strictObject({
2799
+ id: z8.string(),
2800
+ action: z8.nullable(z8.string())
2801
+ }),
2802
+ step: z8.strictObject({
2803
+ id: z8.string().check(z8.minLength(1), z8.maxLength(64), z8.regex(/^[A-Za-z0-9_-]+$/)),
2804
+ // 1-based position in the flow the visitor is on right now.
2805
+ index: z8.int().check(z8.gte(1), z8.lte(50)),
2806
+ // Null when the number of steps depends on earlier answers.
2807
+ total: z8.nullable(z8.int().check(z8.gte(1), z8.lte(50)))
2808
+ }),
2809
+ direction: z8.enum(["forward", "back"]),
2779
2810
  page: z8.strictObject({
2780
2811
  path: z8.string()
2781
2812
  })
2782
2813
  });
2783
- var multiPageSessionConfigSchema = z8.strictObject({
2784
- pageThreshold: z8.int().check(z8.gte(2))
2814
+ var formStepConfigSchema = z8.strictObject({});
2815
+
2816
+ // ../tracking-core/src/events/multi-page-session.ts
2817
+ import * as z9 from "zod/mini";
2818
+ var multiPageSessionMetadataSchema = z9.strictObject({
2819
+ page_count: z9.int().check(z9.gte(2)),
2820
+ page: z9.strictObject({
2821
+ path: z9.string()
2822
+ })
2823
+ });
2824
+ var multiPageSessionConfigSchema = z9.strictObject({
2825
+ pageThreshold: z9.int().check(z9.gte(2))
2785
2826
  });
2786
2827
 
2787
2828
  // ../tracking-core/src/events/page-exit.ts
2788
- import * as z9 from "zod/mini";
2789
- var pageExitMetadataSchema = z9.strictObject({
2790
- dwell_ms: z9.int().check(z9.gte(0)),
2829
+ import * as z10 from "zod/mini";
2830
+ var pageExitMetadataSchema = z10.strictObject({
2831
+ dwell_ms: z10.int().check(z10.gte(0)),
2791
2832
  // null = left without any scroll signal; floor is 0 so a valid 0% is never
2792
2833
  // rejected (a single bad field 422s the whole keepalive beacon batch).
2793
- max_scroll_percent: z9.nullable(z9.int().check(z9.gte(0), z9.lte(100))),
2834
+ max_scroll_percent: z10.nullable(z10.int().check(z10.gte(0), z10.lte(100))),
2794
2835
  // The gating baseline: the fraction of the page visible at load with
2795
2836
  // zero scrolling — or, for pages that grew after the post-paint snapshot
2796
2837
  // (skeleton/streaming renders), the first-scroll position that
@@ -2798,104 +2839,104 @@ var pageExitMetadataSchema = z9.strictObject({
2798
2839
  // ended before the snapshot. Optionality is load-bearing: SDK builds
2799
2840
  // predating this field keep POSTing page_exit without the key —
2800
2841
  // requiring it would 422 whole keepalive beacon batches.
2801
- scroll_baseline_percent: z9.optional(z9.nullable(z9.int().check(z9.gte(0), z9.lte(100)))),
2802
- page: z9.strictObject({
2803
- path: z9.string()
2842
+ scroll_baseline_percent: z10.optional(z10.nullable(z10.int().check(z10.gte(0), z10.lte(100)))),
2843
+ page: z10.strictObject({
2844
+ path: z10.string()
2804
2845
  })
2805
2846
  });
2806
- var pageExitConfigSchema = z9.strictObject({});
2847
+ var pageExitConfigSchema = z10.strictObject({});
2807
2848
 
2808
2849
  // ../tracking-core/src/events/phone-click.ts
2809
- import * as z10 from "zod/mini";
2810
- var phoneClickMetadataSchema = z10.strictObject({
2811
- phone_number: z10.string(),
2812
- page: z10.strictObject({
2813
- path: z10.string()
2850
+ import * as z11 from "zod/mini";
2851
+ var phoneClickMetadataSchema = z11.strictObject({
2852
+ phone_number: z11.string(),
2853
+ page: z11.strictObject({
2854
+ path: z11.string()
2814
2855
  }),
2815
- section: z10.optional(z10.nullable(z10.string()))
2856
+ section: z11.optional(z11.nullable(z11.string()))
2816
2857
  });
2817
- var phoneClickConfigSchema = z10.strictObject({
2818
- autoCapture: z10.optional(
2819
- z10.strictObject({
2820
- selector: z10.optional(z10.string())
2858
+ var phoneClickConfigSchema = z11.strictObject({
2859
+ autoCapture: z11.optional(
2860
+ z11.strictObject({
2861
+ selector: z11.optional(z11.string())
2821
2862
  })
2822
2863
  )
2823
2864
  });
2824
2865
 
2825
2866
  // ../tracking-core/src/events/scroll-depth.ts
2826
- import * as z11 from "zod/mini";
2827
- var scrollDepthMetadataSchema = z11.strictObject({
2828
- depth_percent: z11.int().check(z11.gte(1), z11.lte(100)),
2829
- page: z11.strictObject({
2830
- path: z11.string()
2867
+ import * as z12 from "zod/mini";
2868
+ var scrollDepthMetadataSchema = z12.strictObject({
2869
+ depth_percent: z12.int().check(z12.gte(1), z12.lte(100)),
2870
+ page: z12.strictObject({
2871
+ path: z12.string()
2831
2872
  })
2832
2873
  });
2833
- var scrollDepthConfigSchema = z11.strictObject({
2834
- thresholds: z11.array(z11.int().check(z11.gte(1), z11.lte(100))).check(z11.minLength(1))
2874
+ var scrollDepthConfigSchema = z12.strictObject({
2875
+ thresholds: z12.array(z12.int().check(z12.gte(1), z12.lte(100))).check(z12.minLength(1))
2835
2876
  });
2836
2877
 
2837
2878
  // ../tracking-core/src/events/specific-page-visit.ts
2838
- import * as z12 from "zod/mini";
2879
+ import * as z13 from "zod/mini";
2839
2880
  var PAGE_IDENTITY_MAX_LENGTH = 64;
2840
2881
  var PAGE_IDENTITY_PATTERN = /^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/;
2841
- var pageIdentitySchema = z12.string().check(
2842
- z12.maxLength(PAGE_IDENTITY_MAX_LENGTH),
2843
- z12.regex(PAGE_IDENTITY_PATTERN, {
2882
+ var pageIdentitySchema = z13.string().check(
2883
+ z13.maxLength(PAGE_IDENTITY_MAX_LENGTH),
2884
+ z13.regex(PAGE_IDENTITY_PATTERN, {
2844
2885
  message: "page identity must be lowercase snake_case, start with a letter, and contain at most 64 characters"
2845
2886
  })
2846
2887
  );
2847
2888
  var specificPageNameSchema = pageIdentitySchema;
2848
- var specificPageVisitMetadataSchema = z12.strictObject({
2889
+ var specificPageVisitMetadataSchema = z13.strictObject({
2849
2890
  page_name: specificPageNameSchema,
2850
- page: z12.strictObject({
2851
- path: z12.string()
2891
+ page: z13.strictObject({
2892
+ path: z13.string()
2852
2893
  })
2853
2894
  });
2854
- var specificPageVisitConfigSchema = z12.strictObject({
2855
- pages: z12.array(
2856
- z12.strictObject({
2895
+ var specificPageVisitConfigSchema = z13.strictObject({
2896
+ pages: z13.array(
2897
+ z13.strictObject({
2857
2898
  name: specificPageNameSchema,
2858
- pathPattern: z12.custom((value) => value instanceof RegExp, {
2899
+ pathPattern: z13.custom((value) => value instanceof RegExp, {
2859
2900
  message: "pathPattern must be a RegExp"
2860
2901
  })
2861
2902
  })
2862
- ).check(z12.minLength(1))
2903
+ ).check(z13.minLength(1))
2863
2904
  });
2864
2905
 
2865
2906
  // ../tracking-core/src/events/site-link.ts
2866
- import * as z13 from "zod/mini";
2867
- var siteLinkClickMetadataSchema = z13.strictObject({
2868
- destination_host: z13.string(),
2869
- destination_url: z13.string(),
2870
- page: z13.strictObject({
2871
- path: z13.string()
2907
+ import * as z14 from "zod/mini";
2908
+ var siteLinkClickMetadataSchema = z14.strictObject({
2909
+ destination_host: z14.string(),
2910
+ destination_url: z14.string(),
2911
+ page: z14.strictObject({
2912
+ path: z14.string()
2872
2913
  })
2873
2914
  });
2874
- var siteLinkClickConfigSchema = z13.strictObject({});
2875
- var siteLinkArrivalMetadataSchema = z13.strictObject({
2876
- outcome: z13.enum(["linked", "stale", "invalid"]),
2877
- origin_session_id: z13.optional(z13.nullable(z13.string())),
2878
- origin_visitor_id: z13.optional(z13.nullable(z13.string())),
2915
+ var siteLinkClickConfigSchema = z14.strictObject({});
2916
+ var siteLinkArrivalMetadataSchema = z14.strictObject({
2917
+ outcome: z14.enum(["linked", "stale", "invalid"]),
2918
+ origin_session_id: z14.optional(z14.nullable(z14.string())),
2919
+ origin_visitor_id: z14.optional(z14.nullable(z14.string())),
2879
2920
  // Milliseconds between the origin click and this page load.
2880
- transit_ms: z13.optional(z13.nullable(z13.number())),
2921
+ transit_ms: z14.optional(z14.nullable(z14.number())),
2881
2922
  // True when this browser had no visitor id and took the origin's.
2882
- adopted_visitor: z13.boolean(),
2883
- page: z13.strictObject({
2884
- path: z13.string()
2923
+ adopted_visitor: z14.boolean(),
2924
+ page: z14.strictObject({
2925
+ path: z14.string()
2885
2926
  })
2886
2927
  });
2887
- var siteLinkArrivalConfigSchema = z13.strictObject({});
2928
+ var siteLinkArrivalConfigSchema = z14.strictObject({});
2888
2929
 
2889
2930
  // ../tracking-core/src/events/time-on-site.ts
2890
- import * as z14 from "zod/mini";
2891
- var timeOnSiteMetadataSchema = z14.strictObject({
2892
- duration_ms: z14.int().check(z14.nonnegative()),
2893
- page: z14.strictObject({
2894
- path: z14.string()
2931
+ import * as z15 from "zod/mini";
2932
+ var timeOnSiteMetadataSchema = z15.strictObject({
2933
+ duration_ms: z15.int().check(z15.nonnegative()),
2934
+ page: z15.strictObject({
2935
+ path: z15.string()
2895
2936
  })
2896
2937
  });
2897
- var timeOnSiteConfigSchema = z14.strictObject({
2898
- thresholdSeconds: z14.int().check(z14.positive())
2938
+ var timeOnSiteConfigSchema = z15.strictObject({
2939
+ thresholdSeconds: z15.int().check(z15.positive())
2899
2940
  });
2900
2941
 
2901
2942
  // ../tracking-core/src/events/registry.ts
@@ -2977,6 +3018,12 @@ var EVENT_REGISTRY = {
2977
3018
  metadataSchema: formStepMetadataSchema,
2978
3019
  configSchema: formStepConfigSchema
2979
3020
  },
3021
+ form_details: {
3022
+ kind: "manual",
3023
+ semantics: EVENT_SEMANTICS.form_details,
3024
+ metadataSchema: formDetailsMetadataSchema,
3025
+ configSchema: formDetailsConfigSchema
3026
+ },
2980
3027
  phone_click: {
2981
3028
  kind: "manual",
2982
3029
  semantics: EVENT_SEMANTICS.phone_click,
@@ -3015,6 +3062,7 @@ function salvageFormSubmit(metadata) {
3015
3062
  ...valid("contract_version", form.contract_version),
3016
3063
  ...valid("contract_hash", form.contract_hash),
3017
3064
  ...valid("extra", form.extra),
3065
+ ...valid("submission_id", form.submission_id),
3018
3066
  contract_violations: [...reported, INVALID_SHAPE].slice(-MAX_CONTRACT_VIOLATIONS)
3019
3067
  },
3020
3068
  page: { path: typeof page.path === "string" ? page.path : currentPath2() }
@@ -3295,7 +3343,7 @@ function attachScrollDepth(client, config) {
3295
3343
  }
3296
3344
  const thresholds = new Set(config.thresholds);
3297
3345
  let firedForPath = /* @__PURE__ */ new Set();
3298
- let currentPath3 = window.location.pathname;
3346
+ let currentPath4 = window.location.pathname;
3299
3347
  let rafId = null;
3300
3348
  const gate = createBaselineGate();
3301
3349
  function checkThresholds() {
@@ -3311,7 +3359,7 @@ function attachScrollDepth(client, config) {
3311
3359
  eventType: "scroll_depth",
3312
3360
  metadata: {
3313
3361
  depth_percent: threshold,
3314
- page: { path: currentPath3 }
3362
+ page: { path: currentPath4 }
3315
3363
  },
3316
3364
  pageUrl: window.location.href,
3317
3365
  occurredAt: null
@@ -3328,8 +3376,8 @@ function attachScrollDepth(client, config) {
3328
3376
  }
3329
3377
  function resetIfPathChanged() {
3330
3378
  const newPath = window.location.pathname;
3331
- if (newPath === currentPath3) return;
3332
- currentPath3 = newPath;
3379
+ if (newPath === currentPath4) return;
3380
+ currentPath4 = newPath;
3333
3381
  firedForPath = /* @__PURE__ */ new Set();
3334
3382
  gate.rebaseline();
3335
3383
  }
@@ -3392,13 +3440,13 @@ function attachMultiPageSession(client, config) {
3392
3440
  return storage.getItem(FIRED_KEY) === "1";
3393
3441
  }
3394
3442
  function check2() {
3395
- const currentPath3 = window.location.pathname;
3396
- if (currentPath3 === lastCheckedPath) return;
3397
- lastCheckedPath = currentPath3;
3443
+ const currentPath4 = window.location.pathname;
3444
+ if (currentPath4 === lastCheckedPath) return;
3445
+ lastCheckedPath = currentPath4;
3398
3446
  resetIfSessionChanged();
3399
3447
  if (hasFired()) return;
3400
3448
  const paths = getDistinctPaths();
3401
- paths.add(currentPath3);
3449
+ paths.add(currentPath4);
3402
3450
  saveDistinctPaths(paths);
3403
3451
  if (paths.size >= pageThreshold) {
3404
3452
  storage.setItem(FIRED_KEY, "1");
@@ -3443,7 +3491,7 @@ function attachFormStart(client, config) {
3443
3491
  }
3444
3492
  const selector = config.selector ?? "form";
3445
3493
  let firedForms = /* @__PURE__ */ new Set();
3446
- let currentPath3 = window.location.pathname;
3494
+ let currentPath4 = window.location.pathname;
3447
3495
  let pendingTap = null;
3448
3496
  function getFormKey(form) {
3449
3497
  if (form.id) return `id:${form.id}`;
@@ -3494,8 +3542,8 @@ function attachFormStart(client, config) {
3494
3542
  }
3495
3543
  function resetIfPathChanged() {
3496
3544
  const newPath = window.location.pathname;
3497
- if (newPath === currentPath3) return;
3498
- currentPath3 = newPath;
3545
+ if (newPath === currentPath4) return;
3546
+ currentPath4 = newPath;
3499
3547
  firedForms = /* @__PURE__ */ new Set();
3500
3548
  }
3501
3549
  const originalPushState = history.pushState.bind(history);
@@ -3536,7 +3584,7 @@ function attachPageExit(client) {
3536
3584
  return () => {
3537
3585
  };
3538
3586
  }
3539
- let currentPath3 = window.location.pathname;
3587
+ let currentPath4 = window.location.pathname;
3540
3588
  let activeSince = document.visibilityState === "visible" ? Date.now() : null;
3541
3589
  let accumulatedMs = 0;
3542
3590
  let maxScrollPercent = null;
@@ -3586,9 +3634,9 @@ function attachPageExit(client) {
3586
3634
  }
3587
3635
  function onNavigate() {
3588
3636
  const newPath = window.location.pathname;
3589
- if (newPath === currentPath3) return;
3590
- emitSegment(currentPath3, false);
3591
- currentPath3 = newPath;
3637
+ if (newPath === currentPath4) return;
3638
+ emitSegment(currentPath4, false);
3639
+ currentPath4 = newPath;
3592
3640
  maxScrollPercent = null;
3593
3641
  gate.rebaseline();
3594
3642
  accumulatedMs = 0;
@@ -3596,13 +3644,13 @@ function attachPageExit(client) {
3596
3644
  }
3597
3645
  function onVisibilityChange() {
3598
3646
  if (document.visibilityState === "hidden") {
3599
- emitSegment(currentPath3, true);
3647
+ emitSegment(currentPath4, true);
3600
3648
  } else {
3601
3649
  activeSince = Date.now();
3602
3650
  }
3603
3651
  }
3604
3652
  function onPageHide() {
3605
- emitSegment(currentPath3, true);
3653
+ emitSegment(currentPath4, true);
3606
3654
  }
3607
3655
  const unsubscribeNav = onHistoryChange(onNavigate);
3608
3656
  window.addEventListener("scroll", onScroll, { passive: true });
@@ -3782,7 +3830,7 @@ function attachPhoneClickCapture(client, config) {
3782
3830
  }
3783
3831
 
3784
3832
  // ../tracking-core/src/lead-forms/lead-forms.gen.ts
3785
- import * as z15 from "zod/mini";
3833
+ import * as z16 from "zod/mini";
3786
3834
  var LEAD_FORM_REGISTRY_VERSION = 2;
3787
3835
  var LEAD_FORM_ROLES = [
3788
3836
  "given_name",
@@ -3808,28 +3856,28 @@ var LEAD_FORM_ROLES = [
3808
3856
  "attribution"
3809
3857
  ];
3810
3858
  var leadFormPrimitiveSchemas = /* @__PURE__ */ (() => ({
3811
- string: z15.string().check(z15.maxLength(120)),
3812
- text: z15.string().check(z15.maxLength(2e3)),
3813
- enum: z15.string().check(z15.regex(/^[a-z0-9-]{1,48}$/)),
3814
- multi_enum: z15.array(z15.string().check(z15.regex(/^[a-z0-9-]{1,48}$/))).check(z15.maxLength(10)),
3815
- bool: z15.boolean(),
3816
- date: z15.string().check(z15.regex(/^\d{4}-\d{2}-\d{2}$/)),
3817
- time_window: z15.strictObject({
3818
- start: z15.string().check(z15.regex(/^([01]\d|2[0-3]):[0-5]\d$/)),
3819
- end: z15.nullable(z15.string().check(z15.regex(/^([01]\d|2[0-3]):[0-5]\d$/))),
3820
- label: z15.optional(z15.string().check(z15.maxLength(60)))
3859
+ string: z16.string().check(z16.maxLength(120)),
3860
+ text: z16.string().check(z16.maxLength(2e3)),
3861
+ enum: z16.string().check(z16.regex(/^[a-z0-9-]{1,48}$/)),
3862
+ multi_enum: z16.array(z16.string().check(z16.regex(/^[a-z0-9-]{1,48}$/))).check(z16.maxLength(10)),
3863
+ bool: z16.boolean(),
3864
+ date: z16.string().check(z16.regex(/^\d{4}-\d{2}-\d{2}$/)),
3865
+ time_window: z16.strictObject({
3866
+ start: z16.string().check(z16.regex(/^([01]\d|2[0-3]):[0-5]\d$/)),
3867
+ end: z16.nullable(z16.string().check(z16.regex(/^([01]\d|2[0-3]):[0-5]\d$/))),
3868
+ label: z16.optional(z16.string().check(z16.maxLength(60)))
3821
3869
  }),
3822
- phone: z15.string().check(z15.regex(/^\+[1-9]\d{6,14}$/)),
3823
- email: z15.string().check(z15.maxLength(320), z15.regex(/^[^\s@]+@[^\s@]+$/)),
3824
- address: z15.strictObject({
3825
- line1: z15.string().check(z15.maxLength(120)),
3826
- line2: z15.optional(z15.string().check(z15.maxLength(120))),
3827
- city: z15.optional(z15.string().check(z15.maxLength(120))),
3828
- region: z15.optional(z15.string().check(z15.maxLength(120))),
3829
- postal_code: z15.optional(z15.string().check(z15.maxLength(120))),
3830
- country: z15.optional(z15.string().check(z15.maxLength(120)))
3870
+ phone: z16.string().check(z16.regex(/^\+[1-9]\d{6,14}$/)),
3871
+ email: z16.string().check(z16.maxLength(320), z16.regex(/^[^\s@]+@[^\s@]+$/)),
3872
+ address: z16.strictObject({
3873
+ line1: z16.string().check(z16.maxLength(120)),
3874
+ line2: z16.optional(z16.string().check(z16.maxLength(120))),
3875
+ city: z16.optional(z16.string().check(z16.maxLength(120))),
3876
+ region: z16.optional(z16.string().check(z16.maxLength(120))),
3877
+ postal_code: z16.optional(z16.string().check(z16.maxLength(120))),
3878
+ country: z16.optional(z16.string().check(z16.maxLength(120)))
3831
3879
  }),
3832
- number: z15.number()
3880
+ number: z16.number()
3833
3881
  }))();
3834
3882
  var LEAD_FORM_ROLE_SPECS = {
3835
3883
  given_name: { primitive: "string", smsLabel: "", contactIdentity: true },
@@ -3911,34 +3959,70 @@ function createLeadFormSubmit(tracking, contracts, options = {}) {
3911
3959
  contracts,
3912
3960
  settings
3913
3961
  );
3962
+ const submission = { submissionId: uuidV4(), formId: input.formId, kind: input.kind };
3914
3963
  const metadata = {
3915
3964
  form: {
3916
3965
  id: input.formId,
3917
3966
  action: input.action ?? null,
3918
- fields: fields.map(([role, value]) => ({
3919
- name: role,
3920
- type: INPUT_TYPES[primitiveOf(role) ?? "string"],
3921
- label: labelOf(role),
3922
- value,
3923
- role
3924
- })),
3967
+ fields: fields.map(fieldEntry),
3925
3968
  kind: input.kind,
3926
3969
  contract_version: LEAD_FORM_REGISTRY_VERSION,
3927
3970
  ...hash ? { contract_hash: hash } : {},
3928
3971
  ...input.extra?.length ? { extra: input.extra } : {},
3929
- ...violations.length > 0 ? { contract_violations: violations.slice(0, MAX_CONTRACT_VIOLATIONS) } : {}
3972
+ ...violations.length > 0 ? { contract_violations: violations.slice(0, MAX_CONTRACT_VIOLATIONS) } : {},
3973
+ submission_id: submission.submissionId
3930
3974
  },
3931
- page: { path: typeof window === "undefined" ? "/" : window.location.pathname }
3975
+ page: { path: currentPath3() }
3932
3976
  };
3933
3977
  tracking.trackEvent("form_submit", metadata);
3934
- return metadata;
3978
+ return { ...metadata, submission };
3979
+ },
3980
+ addDetails(submission, input) {
3981
+ const fields = presentFields(input.fields);
3982
+ const extra = (input.extra ?? []).filter((item) => !isBlank(item.value));
3983
+ if (fields.length === 0 && extra.length === 0) return { sent: false, reason: "no_fields" };
3984
+ const { violations, hash } = judgeLeadForm(
3985
+ submission.kind,
3986
+ submission.formId,
3987
+ fields,
3988
+ contracts,
3989
+ settings,
3990
+ { partial: true }
3991
+ );
3992
+ const metadata = {
3993
+ form: {
3994
+ id: submission.formId,
3995
+ submission_id: submission.submissionId,
3996
+ kind: submission.kind,
3997
+ fields: fields.map(fieldEntry),
3998
+ contract_version: LEAD_FORM_REGISTRY_VERSION,
3999
+ ...hash ? { contract_hash: hash } : {},
4000
+ ...extra.length > 0 ? { extra } : {},
4001
+ ...violations.length > 0 ? { contract_violations: violations.slice(0, MAX_CONTRACT_VIOLATIONS) } : {}
4002
+ },
4003
+ page: { path: currentPath3() }
4004
+ };
4005
+ tracking.trackEvent("form_details", metadata);
4006
+ return { sent: true };
3935
4007
  }
3936
4008
  };
3937
4009
  }
3938
- function judgeLeadForm(kind, formId, fields, contracts, settings) {
4010
+ function fieldEntry([role, value]) {
4011
+ return {
4012
+ name: role,
4013
+ type: INPUT_TYPES[primitiveOf(role) ?? "string"],
4014
+ label: labelOf(role),
4015
+ value,
4016
+ role
4017
+ };
4018
+ }
4019
+ function currentPath3() {
4020
+ return typeof window === "undefined" ? "/" : window.location.pathname;
4021
+ }
4022
+ function judgeLeadForm(kind, formId, fields, contracts, settings, { partial = false } = {}) {
3939
4023
  const generated = contracts?.contracts[kind];
3940
4024
  const live = liveContract(settings.trackingConfig, kind);
3941
- const violations = check(live === void 0 ? generated : fromLive(live), fields);
4025
+ const violations = check(live === void 0 ? generated : fromLive(live), fields, partial);
3942
4026
  const liveHash = live === void 0 ? void 0 : live?.contract_hash ?? null;
3943
4027
  if (contracts && (liveHash !== void 0 && (generated?.hash ?? null) !== liveHash || contracts.registryVersion !== LEAD_FORM_REGISTRY_VERSION)) {
3944
4028
  violations.push({ role: null, rule: "contract_behind" });
@@ -3984,7 +4068,7 @@ function normalize(role, value) {
3984
4068
  function isBlank(value) {
3985
4069
  return value === void 0 || value === null || typeof value === "string" && value.trim() === "" || Array.isArray(value) && value.length === 0;
3986
4070
  }
3987
- function check(contract, fields) {
4071
+ function check(contract, fields, partial) {
3988
4072
  const answered = new Map(fields);
3989
4073
  const violations = [];
3990
4074
  for (const [role, value] of fields) {
@@ -4002,6 +4086,7 @@ function check(contract, fields) {
4002
4086
  violations.push({ role, rule: "unknown_option" });
4003
4087
  }
4004
4088
  }
4089
+ if (partial) return violations;
4005
4090
  for (const { role, requiredWhen } of contract?.requires ?? []) {
4006
4091
  const owing = requiredWhen === null || optionKeys(answered.get(requiredWhen.role)).some((key) => requiredWhen.anyOf.includes(key));
4007
4092
  if (owing && !answered.has(role)) violations.push({ role, rule: "missing_required" });
@@ -4364,7 +4449,7 @@ function GoogleAdsTracking(props) {
4364
4449
  import { createContext as createContext2, useContext as useContext2, useEffect as useEffect5, useMemo as useMemo4 } from "react";
4365
4450
 
4366
4451
  // package.json
4367
- var version = "1.16.1";
4452
+ var version = "1.18.0";
4368
4453
 
4369
4454
  // ../tracking-core/src/phone-react.tsx
4370
4455
  import {