@aranova/tracking-react 1.17.0 → 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
@@ -1978,6 +1978,13 @@ var EVENT_SEMANTICS = {
1978
1978
  outcomeRole: "engagement",
1979
1979
  clientVisibility: "detailed"
1980
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
+ },
1981
1988
  form_submit: {
1982
1989
  label: "Form submitted",
1983
1990
  category: "lead",
@@ -2594,7 +2601,7 @@ function createTrackingClient(config) {
2594
2601
  metadata: input.metadata ?? null,
2595
2602
  occurred_at: occurredAt
2596
2603
  });
2597
- if (queue.length >= maxQueueSize || getEventSemantics(input.eventType)?.outcomeRole === "lead") {
2604
+ if (queue.length >= maxQueueSize || input.eventType === "form_details" || getEventSemantics(input.eventType)?.outcomeRole === "lead") {
2598
2605
  void flush();
2599
2606
  } else {
2600
2607
  scheduleFlush();
@@ -2698,110 +2705,133 @@ var formStartConfigSchema = z5.strictObject({
2698
2705
  selector: z5.optional(z5.string())
2699
2706
  });
2700
2707
 
2701
- // ../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
2702
2712
  import * as z6 from "zod/mini";
2703
- 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({
2704
2759
  form: z6.strictObject({
2705
2760
  id: z6.string(),
2706
- 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()))
2707
2770
  }),
2708
- step: z6.strictObject({
2709
- id: z6.string().check(z6.minLength(1), z6.maxLength(64), z6.regex(/^[A-Za-z0-9_-]+$/)),
2710
- // 1-based position in the flow the visitor is on right now.
2711
- index: z6.int().check(z6.gte(1), z6.lte(50)),
2712
- // Null when the number of steps depends on earlier answers.
2713
- total: z6.nullable(z6.int().check(z6.gte(1), z6.lte(50)))
2714
- }),
2715
- direction: z6.enum(["forward", "back"]),
2716
2771
  page: z6.strictObject({
2717
2772
  path: z6.string()
2718
2773
  })
2719
2774
  });
2720
- var formStepConfigSchema = z6.strictObject({});
2775
+ var formSubmitConfigSchema = z6.strictObject({});
2721
2776
 
2722
- // ../tracking-core/src/events/form-submit.ts
2723
- import * as z7 from "zod/mini";
2724
- var jsonValueSchema = z7.lazy(
2725
- () => z7.union([
2726
- z7.string(),
2727
- z7.number(),
2728
- z7.boolean(),
2729
- z7.null(),
2730
- z7.array(jsonValueSchema),
2731
- z7.record(z7.string(), jsonValueSchema)
2732
- ])
2733
- ).register(z7.globalRegistry, { id: "JsonSerializableValue" });
2734
- var contractNameSchema = z7.string().check(z7.regex(/^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?$/));
2735
- var contractName = contractNameSchema;
2736
- var violationRole = z7.string().check(
2737
- z7.maxLength(200),
2738
- z7.regex(
2739
- /^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?(\|[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?)*$/
2740
- )
2741
- );
2742
- var MAX_CONTRACT_VIOLATIONS = 50;
2743
- var contractViolationSchema = z7.strictObject({
2744
- role: z7.nullable(violationRole),
2745
- rule: z7.string().check(z7.regex(/^[a-z][a-z_]{0,47}$/))
2746
- });
2747
- var formSubmitMetadataSchema = z7.strictObject({
2777
+ // ../tracking-core/src/events/form-details.ts
2778
+ var formDetailsMetadataSchema = z7.strictObject({
2748
2779
  form: z7.strictObject({
2749
2780
  id: z7.string(),
2750
- action: z7.nullable(z7.string()),
2751
- fields: z7.optional(
2752
- z7.array(
2753
- z7.strictObject({
2754
- name: z7.string(),
2755
- type: z7.string(),
2756
- label: z7.nullable(z7.string()),
2757
- value: jsonValueSchema,
2758
- role: z7.optional(z7.nullable(contractName))
2759
- })
2760
- )
2761
- ),
2762
- kind: z7.optional(z7.nullable(contractName)),
2763
- contract_version: z7.optional(z7.nullable(z7.int().check(z7.gte(1)))),
2764
- contract_hash: z7.optional(z7.nullable(z7.string().check(z7.maxLength(64)))),
2765
- extra: z7.optional(
2766
- z7.nullable(
2767
- z7.array(
2768
- z7.strictObject({
2769
- key: z7.string().check(z7.maxLength(64)),
2770
- label: z7.string().check(z7.maxLength(200)),
2771
- value: jsonValueSchema
2772
- })
2773
- ).check(z7.maxLength(20))
2774
- )
2775
- ),
2776
- contract_violations: z7.optional(
2777
- z7.nullable(z7.array(contractViolationSchema).check(z7.maxLength(MAX_CONTRACT_VIOLATIONS)))
2778
- )
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
2779
2788
  }),
2780
2789
  page: z7.strictObject({
2781
2790
  path: z7.string()
2782
2791
  })
2783
2792
  });
2784
- var formSubmitConfigSchema = z7.strictObject({});
2793
+ var formDetailsConfigSchema = z7.strictObject({});
2785
2794
 
2786
- // ../tracking-core/src/events/multi-page-session.ts
2795
+ // ../tracking-core/src/events/form-step.ts
2787
2796
  import * as z8 from "zod/mini";
2788
- var multiPageSessionMetadataSchema = z8.strictObject({
2789
- 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"]),
2790
2810
  page: z8.strictObject({
2791
2811
  path: z8.string()
2792
2812
  })
2793
2813
  });
2794
- var multiPageSessionConfigSchema = z8.strictObject({
2795
- 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))
2796
2826
  });
2797
2827
 
2798
2828
  // ../tracking-core/src/events/page-exit.ts
2799
- import * as z9 from "zod/mini";
2800
- var pageExitMetadataSchema = z9.strictObject({
2801
- 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)),
2802
2832
  // null = left without any scroll signal; floor is 0 so a valid 0% is never
2803
2833
  // rejected (a single bad field 422s the whole keepalive beacon batch).
2804
- 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))),
2805
2835
  // The gating baseline: the fraction of the page visible at load with
2806
2836
  // zero scrolling — or, for pages that grew after the post-paint snapshot
2807
2837
  // (skeleton/streaming renders), the first-scroll position that
@@ -2809,104 +2839,104 @@ var pageExitMetadataSchema = z9.strictObject({
2809
2839
  // ended before the snapshot. Optionality is load-bearing: SDK builds
2810
2840
  // predating this field keep POSTing page_exit without the key —
2811
2841
  // requiring it would 422 whole keepalive beacon batches.
2812
- scroll_baseline_percent: z9.optional(z9.nullable(z9.int().check(z9.gte(0), z9.lte(100)))),
2813
- page: z9.strictObject({
2814
- 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()
2815
2845
  })
2816
2846
  });
2817
- var pageExitConfigSchema = z9.strictObject({});
2847
+ var pageExitConfigSchema = z10.strictObject({});
2818
2848
 
2819
2849
  // ../tracking-core/src/events/phone-click.ts
2820
- import * as z10 from "zod/mini";
2821
- var phoneClickMetadataSchema = z10.strictObject({
2822
- phone_number: z10.string(),
2823
- page: z10.strictObject({
2824
- 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()
2825
2855
  }),
2826
- section: z10.optional(z10.nullable(z10.string()))
2856
+ section: z11.optional(z11.nullable(z11.string()))
2827
2857
  });
2828
- var phoneClickConfigSchema = z10.strictObject({
2829
- autoCapture: z10.optional(
2830
- z10.strictObject({
2831
- selector: z10.optional(z10.string())
2858
+ var phoneClickConfigSchema = z11.strictObject({
2859
+ autoCapture: z11.optional(
2860
+ z11.strictObject({
2861
+ selector: z11.optional(z11.string())
2832
2862
  })
2833
2863
  )
2834
2864
  });
2835
2865
 
2836
2866
  // ../tracking-core/src/events/scroll-depth.ts
2837
- import * as z11 from "zod/mini";
2838
- var scrollDepthMetadataSchema = z11.strictObject({
2839
- depth_percent: z11.int().check(z11.gte(1), z11.lte(100)),
2840
- page: z11.strictObject({
2841
- 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()
2842
2872
  })
2843
2873
  });
2844
- var scrollDepthConfigSchema = z11.strictObject({
2845
- 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))
2846
2876
  });
2847
2877
 
2848
2878
  // ../tracking-core/src/events/specific-page-visit.ts
2849
- import * as z12 from "zod/mini";
2879
+ import * as z13 from "zod/mini";
2850
2880
  var PAGE_IDENTITY_MAX_LENGTH = 64;
2851
2881
  var PAGE_IDENTITY_PATTERN = /^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/;
2852
- var pageIdentitySchema = z12.string().check(
2853
- z12.maxLength(PAGE_IDENTITY_MAX_LENGTH),
2854
- z12.regex(PAGE_IDENTITY_PATTERN, {
2882
+ var pageIdentitySchema = z13.string().check(
2883
+ z13.maxLength(PAGE_IDENTITY_MAX_LENGTH),
2884
+ z13.regex(PAGE_IDENTITY_PATTERN, {
2855
2885
  message: "page identity must be lowercase snake_case, start with a letter, and contain at most 64 characters"
2856
2886
  })
2857
2887
  );
2858
2888
  var specificPageNameSchema = pageIdentitySchema;
2859
- var specificPageVisitMetadataSchema = z12.strictObject({
2889
+ var specificPageVisitMetadataSchema = z13.strictObject({
2860
2890
  page_name: specificPageNameSchema,
2861
- page: z12.strictObject({
2862
- path: z12.string()
2891
+ page: z13.strictObject({
2892
+ path: z13.string()
2863
2893
  })
2864
2894
  });
2865
- var specificPageVisitConfigSchema = z12.strictObject({
2866
- pages: z12.array(
2867
- z12.strictObject({
2895
+ var specificPageVisitConfigSchema = z13.strictObject({
2896
+ pages: z13.array(
2897
+ z13.strictObject({
2868
2898
  name: specificPageNameSchema,
2869
- pathPattern: z12.custom((value) => value instanceof RegExp, {
2899
+ pathPattern: z13.custom((value) => value instanceof RegExp, {
2870
2900
  message: "pathPattern must be a RegExp"
2871
2901
  })
2872
2902
  })
2873
- ).check(z12.minLength(1))
2903
+ ).check(z13.minLength(1))
2874
2904
  });
2875
2905
 
2876
2906
  // ../tracking-core/src/events/site-link.ts
2877
- import * as z13 from "zod/mini";
2878
- var siteLinkClickMetadataSchema = z13.strictObject({
2879
- destination_host: z13.string(),
2880
- destination_url: z13.string(),
2881
- page: z13.strictObject({
2882
- 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()
2883
2913
  })
2884
2914
  });
2885
- var siteLinkClickConfigSchema = z13.strictObject({});
2886
- var siteLinkArrivalMetadataSchema = z13.strictObject({
2887
- outcome: z13.enum(["linked", "stale", "invalid"]),
2888
- origin_session_id: z13.optional(z13.nullable(z13.string())),
2889
- 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())),
2890
2920
  // Milliseconds between the origin click and this page load.
2891
- transit_ms: z13.optional(z13.nullable(z13.number())),
2921
+ transit_ms: z14.optional(z14.nullable(z14.number())),
2892
2922
  // True when this browser had no visitor id and took the origin's.
2893
- adopted_visitor: z13.boolean(),
2894
- page: z13.strictObject({
2895
- path: z13.string()
2923
+ adopted_visitor: z14.boolean(),
2924
+ page: z14.strictObject({
2925
+ path: z14.string()
2896
2926
  })
2897
2927
  });
2898
- var siteLinkArrivalConfigSchema = z13.strictObject({});
2928
+ var siteLinkArrivalConfigSchema = z14.strictObject({});
2899
2929
 
2900
2930
  // ../tracking-core/src/events/time-on-site.ts
2901
- import * as z14 from "zod/mini";
2902
- var timeOnSiteMetadataSchema = z14.strictObject({
2903
- duration_ms: z14.int().check(z14.nonnegative()),
2904
- page: z14.strictObject({
2905
- 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()
2906
2936
  })
2907
2937
  });
2908
- var timeOnSiteConfigSchema = z14.strictObject({
2909
- thresholdSeconds: z14.int().check(z14.positive())
2938
+ var timeOnSiteConfigSchema = z15.strictObject({
2939
+ thresholdSeconds: z15.int().check(z15.positive())
2910
2940
  });
2911
2941
 
2912
2942
  // ../tracking-core/src/events/registry.ts
@@ -2988,6 +3018,12 @@ var EVENT_REGISTRY = {
2988
3018
  metadataSchema: formStepMetadataSchema,
2989
3019
  configSchema: formStepConfigSchema
2990
3020
  },
3021
+ form_details: {
3022
+ kind: "manual",
3023
+ semantics: EVENT_SEMANTICS.form_details,
3024
+ metadataSchema: formDetailsMetadataSchema,
3025
+ configSchema: formDetailsConfigSchema
3026
+ },
2991
3027
  phone_click: {
2992
3028
  kind: "manual",
2993
3029
  semantics: EVENT_SEMANTICS.phone_click,
@@ -3026,6 +3062,7 @@ function salvageFormSubmit(metadata) {
3026
3062
  ...valid("contract_version", form.contract_version),
3027
3063
  ...valid("contract_hash", form.contract_hash),
3028
3064
  ...valid("extra", form.extra),
3065
+ ...valid("submission_id", form.submission_id),
3029
3066
  contract_violations: [...reported, INVALID_SHAPE].slice(-MAX_CONTRACT_VIOLATIONS)
3030
3067
  },
3031
3068
  page: { path: typeof page.path === "string" ? page.path : currentPath2() }
@@ -3306,7 +3343,7 @@ function attachScrollDepth(client, config) {
3306
3343
  }
3307
3344
  const thresholds = new Set(config.thresholds);
3308
3345
  let firedForPath = /* @__PURE__ */ new Set();
3309
- let currentPath3 = window.location.pathname;
3346
+ let currentPath4 = window.location.pathname;
3310
3347
  let rafId = null;
3311
3348
  const gate = createBaselineGate();
3312
3349
  function checkThresholds() {
@@ -3322,7 +3359,7 @@ function attachScrollDepth(client, config) {
3322
3359
  eventType: "scroll_depth",
3323
3360
  metadata: {
3324
3361
  depth_percent: threshold,
3325
- page: { path: currentPath3 }
3362
+ page: { path: currentPath4 }
3326
3363
  },
3327
3364
  pageUrl: window.location.href,
3328
3365
  occurredAt: null
@@ -3339,8 +3376,8 @@ function attachScrollDepth(client, config) {
3339
3376
  }
3340
3377
  function resetIfPathChanged() {
3341
3378
  const newPath = window.location.pathname;
3342
- if (newPath === currentPath3) return;
3343
- currentPath3 = newPath;
3379
+ if (newPath === currentPath4) return;
3380
+ currentPath4 = newPath;
3344
3381
  firedForPath = /* @__PURE__ */ new Set();
3345
3382
  gate.rebaseline();
3346
3383
  }
@@ -3403,13 +3440,13 @@ function attachMultiPageSession(client, config) {
3403
3440
  return storage.getItem(FIRED_KEY) === "1";
3404
3441
  }
3405
3442
  function check2() {
3406
- const currentPath3 = window.location.pathname;
3407
- if (currentPath3 === lastCheckedPath) return;
3408
- lastCheckedPath = currentPath3;
3443
+ const currentPath4 = window.location.pathname;
3444
+ if (currentPath4 === lastCheckedPath) return;
3445
+ lastCheckedPath = currentPath4;
3409
3446
  resetIfSessionChanged();
3410
3447
  if (hasFired()) return;
3411
3448
  const paths = getDistinctPaths();
3412
- paths.add(currentPath3);
3449
+ paths.add(currentPath4);
3413
3450
  saveDistinctPaths(paths);
3414
3451
  if (paths.size >= pageThreshold) {
3415
3452
  storage.setItem(FIRED_KEY, "1");
@@ -3454,7 +3491,7 @@ function attachFormStart(client, config) {
3454
3491
  }
3455
3492
  const selector = config.selector ?? "form";
3456
3493
  let firedForms = /* @__PURE__ */ new Set();
3457
- let currentPath3 = window.location.pathname;
3494
+ let currentPath4 = window.location.pathname;
3458
3495
  let pendingTap = null;
3459
3496
  function getFormKey(form) {
3460
3497
  if (form.id) return `id:${form.id}`;
@@ -3505,8 +3542,8 @@ function attachFormStart(client, config) {
3505
3542
  }
3506
3543
  function resetIfPathChanged() {
3507
3544
  const newPath = window.location.pathname;
3508
- if (newPath === currentPath3) return;
3509
- currentPath3 = newPath;
3545
+ if (newPath === currentPath4) return;
3546
+ currentPath4 = newPath;
3510
3547
  firedForms = /* @__PURE__ */ new Set();
3511
3548
  }
3512
3549
  const originalPushState = history.pushState.bind(history);
@@ -3547,7 +3584,7 @@ function attachPageExit(client) {
3547
3584
  return () => {
3548
3585
  };
3549
3586
  }
3550
- let currentPath3 = window.location.pathname;
3587
+ let currentPath4 = window.location.pathname;
3551
3588
  let activeSince = document.visibilityState === "visible" ? Date.now() : null;
3552
3589
  let accumulatedMs = 0;
3553
3590
  let maxScrollPercent = null;
@@ -3597,9 +3634,9 @@ function attachPageExit(client) {
3597
3634
  }
3598
3635
  function onNavigate() {
3599
3636
  const newPath = window.location.pathname;
3600
- if (newPath === currentPath3) return;
3601
- emitSegment(currentPath3, false);
3602
- currentPath3 = newPath;
3637
+ if (newPath === currentPath4) return;
3638
+ emitSegment(currentPath4, false);
3639
+ currentPath4 = newPath;
3603
3640
  maxScrollPercent = null;
3604
3641
  gate.rebaseline();
3605
3642
  accumulatedMs = 0;
@@ -3607,13 +3644,13 @@ function attachPageExit(client) {
3607
3644
  }
3608
3645
  function onVisibilityChange() {
3609
3646
  if (document.visibilityState === "hidden") {
3610
- emitSegment(currentPath3, true);
3647
+ emitSegment(currentPath4, true);
3611
3648
  } else {
3612
3649
  activeSince = Date.now();
3613
3650
  }
3614
3651
  }
3615
3652
  function onPageHide() {
3616
- emitSegment(currentPath3, true);
3653
+ emitSegment(currentPath4, true);
3617
3654
  }
3618
3655
  const unsubscribeNav = onHistoryChange(onNavigate);
3619
3656
  window.addEventListener("scroll", onScroll, { passive: true });
@@ -3793,7 +3830,7 @@ function attachPhoneClickCapture(client, config) {
3793
3830
  }
3794
3831
 
3795
3832
  // ../tracking-core/src/lead-forms/lead-forms.gen.ts
3796
- import * as z15 from "zod/mini";
3833
+ import * as z16 from "zod/mini";
3797
3834
  var LEAD_FORM_REGISTRY_VERSION = 2;
3798
3835
  var LEAD_FORM_ROLES = [
3799
3836
  "given_name",
@@ -3819,28 +3856,28 @@ var LEAD_FORM_ROLES = [
3819
3856
  "attribution"
3820
3857
  ];
3821
3858
  var leadFormPrimitiveSchemas = /* @__PURE__ */ (() => ({
3822
- string: z15.string().check(z15.maxLength(120)),
3823
- text: z15.string().check(z15.maxLength(2e3)),
3824
- enum: z15.string().check(z15.regex(/^[a-z0-9-]{1,48}$/)),
3825
- multi_enum: z15.array(z15.string().check(z15.regex(/^[a-z0-9-]{1,48}$/))).check(z15.maxLength(10)),
3826
- bool: z15.boolean(),
3827
- date: z15.string().check(z15.regex(/^\d{4}-\d{2}-\d{2}$/)),
3828
- time_window: z15.strictObject({
3829
- start: z15.string().check(z15.regex(/^([01]\d|2[0-3]):[0-5]\d$/)),
3830
- end: z15.nullable(z15.string().check(z15.regex(/^([01]\d|2[0-3]):[0-5]\d$/))),
3831
- 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)))
3832
3869
  }),
3833
- phone: z15.string().check(z15.regex(/^\+[1-9]\d{6,14}$/)),
3834
- email: z15.string().check(z15.maxLength(320), z15.regex(/^[^\s@]+@[^\s@]+$/)),
3835
- address: z15.strictObject({
3836
- line1: z15.string().check(z15.maxLength(120)),
3837
- line2: z15.optional(z15.string().check(z15.maxLength(120))),
3838
- city: z15.optional(z15.string().check(z15.maxLength(120))),
3839
- region: z15.optional(z15.string().check(z15.maxLength(120))),
3840
- postal_code: z15.optional(z15.string().check(z15.maxLength(120))),
3841
- 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)))
3842
3879
  }),
3843
- number: z15.number()
3880
+ number: z16.number()
3844
3881
  }))();
3845
3882
  var LEAD_FORM_ROLE_SPECS = {
3846
3883
  given_name: { primitive: "string", smsLabel: "", contactIdentity: true },
@@ -3922,34 +3959,70 @@ function createLeadFormSubmit(tracking, contracts, options = {}) {
3922
3959
  contracts,
3923
3960
  settings
3924
3961
  );
3962
+ const submission = { submissionId: uuidV4(), formId: input.formId, kind: input.kind };
3925
3963
  const metadata = {
3926
3964
  form: {
3927
3965
  id: input.formId,
3928
3966
  action: input.action ?? null,
3929
- fields: fields.map(([role, value]) => ({
3930
- name: role,
3931
- type: INPUT_TYPES[primitiveOf(role) ?? "string"],
3932
- label: labelOf(role),
3933
- value,
3934
- role
3935
- })),
3967
+ fields: fields.map(fieldEntry),
3936
3968
  kind: input.kind,
3937
3969
  contract_version: LEAD_FORM_REGISTRY_VERSION,
3938
3970
  ...hash ? { contract_hash: hash } : {},
3939
3971
  ...input.extra?.length ? { extra: input.extra } : {},
3940
- ...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
3941
3974
  },
3942
- page: { path: typeof window === "undefined" ? "/" : window.location.pathname }
3975
+ page: { path: currentPath3() }
3943
3976
  };
3944
3977
  tracking.trackEvent("form_submit", metadata);
3945
- 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 };
3946
4007
  }
3947
4008
  };
3948
4009
  }
3949
- 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 } = {}) {
3950
4023
  const generated = contracts?.contracts[kind];
3951
4024
  const live = liveContract(settings.trackingConfig, kind);
3952
- const violations = check(live === void 0 ? generated : fromLive(live), fields);
4025
+ const violations = check(live === void 0 ? generated : fromLive(live), fields, partial);
3953
4026
  const liveHash = live === void 0 ? void 0 : live?.contract_hash ?? null;
3954
4027
  if (contracts && (liveHash !== void 0 && (generated?.hash ?? null) !== liveHash || contracts.registryVersion !== LEAD_FORM_REGISTRY_VERSION)) {
3955
4028
  violations.push({ role: null, rule: "contract_behind" });
@@ -3995,7 +4068,7 @@ function normalize(role, value) {
3995
4068
  function isBlank(value) {
3996
4069
  return value === void 0 || value === null || typeof value === "string" && value.trim() === "" || Array.isArray(value) && value.length === 0;
3997
4070
  }
3998
- function check(contract, fields) {
4071
+ function check(contract, fields, partial) {
3999
4072
  const answered = new Map(fields);
4000
4073
  const violations = [];
4001
4074
  for (const [role, value] of fields) {
@@ -4013,6 +4086,7 @@ function check(contract, fields) {
4013
4086
  violations.push({ role, rule: "unknown_option" });
4014
4087
  }
4015
4088
  }
4089
+ if (partial) return violations;
4016
4090
  for (const { role, requiredWhen } of contract?.requires ?? []) {
4017
4091
  const owing = requiredWhen === null || optionKeys(answered.get(requiredWhen.role)).some((key) => requiredWhen.anyOf.includes(key));
4018
4092
  if (owing && !answered.has(role)) violations.push({ role, rule: "missing_required" });
@@ -4375,7 +4449,7 @@ function GoogleAdsTracking(props) {
4375
4449
  import { createContext as createContext2, useContext as useContext2, useEffect as useEffect5, useMemo as useMemo4 } from "react";
4376
4450
 
4377
4451
  // package.json
4378
- var version = "1.17.0";
4452
+ var version = "1.18.0";
4379
4453
 
4380
4454
  // ../tracking-core/src/phone-react.tsx
4381
4455
  import {