@aranova/tracking-next 0.4.2 → 0.5.1

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
@@ -206,7 +206,7 @@ function getVisitorId() {
206
206
  }
207
207
  function getOrRotateSessionId(now = Date.now()) {
208
208
  if (typeof window === "undefined")
209
- return safeUuid();
209
+ return { id: safeUuid(), isNew: true };
210
210
  const raw = readLocalStorage(SESSION_STORAGE_KEY);
211
211
  if (raw) {
212
212
  try {
@@ -215,7 +215,7 @@ function getOrRotateSessionId(now = Date.now()) {
215
215
  if (now - parsed.last_event_at <= SESSION_IDLE_MS) {
216
216
  const refreshed = { id: parsed.id, last_event_at: now };
217
217
  writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(refreshed));
218
- return parsed.id;
218
+ return { id: parsed.id, isNew: false };
219
219
  }
220
220
  }
221
221
  } catch {
@@ -223,7 +223,7 @@ function getOrRotateSessionId(now = Date.now()) {
223
223
  }
224
224
  const fresh = { id: safeUuid(), last_event_at: now };
225
225
  writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(fresh));
226
- return fresh.id;
226
+ return { id: fresh.id, isNew: true };
227
227
  }
228
228
 
229
229
  // ../tracking-core/src/events/page-view.ts
@@ -323,6 +323,56 @@ function attachBfcacheRestore(client) {
323
323
  };
324
324
  }
325
325
 
326
+ // ../tracking-core/src/heartbeat.ts
327
+ function serializeValue(value) {
328
+ if (value instanceof RegExp) return value.source;
329
+ if (Array.isArray(value)) return value.map(serializeValue);
330
+ if (value !== null && typeof value === "object") {
331
+ const out = {};
332
+ for (const [k, v] of Object.entries(value)) {
333
+ out[k] = serializeValue(v);
334
+ }
335
+ return out;
336
+ }
337
+ return value;
338
+ }
339
+ function buildHeartbeatMetadata(surface, sdkVersion, packageName, triggers) {
340
+ const automaticNames = triggers ? Object.keys(triggers.automatic) : [];
341
+ const manualNames = triggers?.manual ? Object.keys(triggers.manual) : [];
342
+ let triggerConfig = null;
343
+ if (triggers) {
344
+ const cfg = {};
345
+ for (const [name, config] of Object.entries(triggers.automatic)) {
346
+ const serialized = serializeValue(config);
347
+ if (Object.keys(serialized).length > 0) {
348
+ cfg[name] = serialized;
349
+ }
350
+ }
351
+ if (triggers.manual) {
352
+ for (const [name, config] of Object.entries(triggers.manual)) {
353
+ if (config === void 0) continue;
354
+ const serialized = serializeValue(config);
355
+ if (Object.keys(serialized).length > 0) {
356
+ cfg[name] = serialized;
357
+ }
358
+ }
359
+ }
360
+ if (Object.keys(cfg).length > 0) {
361
+ triggerConfig = cfg;
362
+ }
363
+ }
364
+ return {
365
+ sdk_version: sdkVersion ?? "unknown",
366
+ package_name: packageName,
367
+ surface,
368
+ triggers: {
369
+ automatic: automaticNames,
370
+ manual: manualNames
371
+ },
372
+ trigger_config: triggerConfig
373
+ };
374
+ }
375
+
326
376
  // ../tracking-core/src/ingest.ts
327
377
  var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
328
378
  var DEFAULT_MAX_QUEUE_SIZE = 10;
@@ -402,11 +452,33 @@ function createTrackingClient(config) {
402
452
  let firstPage = null;
403
453
  let destroyed = false;
404
454
  const visitorId = getVisitorId();
405
- let sessionId = getOrRotateSessionId();
455
+ const initialSession = getOrRotateSessionId();
456
+ let sessionId = initialSession.id;
406
457
  if (typeof window !== "undefined")
407
458
  firstPage = window.location.href;
459
+ function enqueueHeartbeat() {
460
+ const metadata = buildHeartbeatMetadata(
461
+ config.surface,
462
+ sdkVersion,
463
+ packageName,
464
+ config.triggers ?? null
465
+ );
466
+ queue.push({
467
+ event_type: "sdk_heartbeat",
468
+ page_url: typeof window === "undefined" ? null : window.location.href,
469
+ metadata,
470
+ occurred_at: (/* @__PURE__ */ new Date()).toISOString()
471
+ });
472
+ }
473
+ if (initialSession.isNew) {
474
+ enqueueHeartbeat();
475
+ }
408
476
  function buildSessionPayload() {
409
- sessionId = getOrRotateSessionId();
477
+ const rotated = getOrRotateSessionId();
478
+ if (rotated.isNew && rotated.id !== sessionId) {
479
+ enqueueHeartbeat();
480
+ }
481
+ sessionId = rotated.id;
410
482
  const params = readTrackingParams();
411
483
  const context = buildContext(config.surface, sdkVersion, packageName);
412
484
  return {
@@ -507,60 +579,144 @@ function createTrackingClient(config) {
507
579
  };
508
580
  }
509
581
 
510
- // ../tracking-core/src/events/contact-page-visit.ts
582
+ // ../tracking-core/src/events/cta-click.ts
511
583
  import { z as z2 } from "zod";
512
- var contactPageVisitMetadataSchema = z2.object({
584
+ var ctaClickMetadataSchema = z2.object({
585
+ cta_name: z2.string(),
513
586
  page: z2.object({
514
587
  path: z2.string()
515
- })
516
- }).strict();
517
- var contactPageVisitConfigSchema = z2.object({
518
- // RegExp is runtime-only so we wrap it via z.custom. Consumers pass a
519
- // real regex at createTracking() time; the factory validates with this
520
- // schema and then keeps the live RegExp reference for runtime matching.
521
- pathPattern: z2.custom(
522
- (value) => value instanceof RegExp,
523
- { message: "pathPattern must be a RegExp" }
524
- )
588
+ }),
589
+ section: z2.string().nullable().optional(),
590
+ destination_url: z2.string().nullable().optional()
525
591
  }).strict();
592
+ var ctaClickConfigSchema = z2.object({}).strict();
526
593
 
527
- // ../tracking-core/src/events/form-submit.ts
594
+ // ../tracking-core/src/events/sdk-heartbeat.ts
528
595
  import { z as z3 } from "zod";
529
- var formSubmitMetadataSchema = z3.object({
530
- form: z3.object({
531
- id: z3.string(),
532
- action: z3.string().nullable()
533
- }),
534
- page: z3.object({
535
- path: z3.string()
536
- })
596
+ var sdkHeartbeatTriggersSchema = z3.object({
597
+ automatic: z3.array(z3.string()),
598
+ manual: z3.array(z3.string())
537
599
  }).strict();
538
- var formSubmitConfigSchema = z3.object({}).strict();
600
+ var sdkHeartbeatMetadataSchema = z3.object({
601
+ sdk_version: z3.string(),
602
+ package_name: z3.string().nullable(),
603
+ surface: z3.enum(["next", "react", "script"]),
604
+ triggers: sdkHeartbeatTriggersSchema,
605
+ trigger_config: z3.record(z3.string(), z3.record(z3.string(), z3.unknown())).nullable().optional()
606
+ }).strict();
607
+ var sdkHeartbeatConfigSchema = z3.object({}).strict();
539
608
 
540
- // ../tracking-core/src/events/phone-click.ts
609
+ // ../tracking-core/src/events/form-start.ts
541
610
  import { z as z4 } from "zod";
542
- var phoneClickMetadataSchema = z4.object({
543
- element: z4.object({
544
- tag: z4.string(),
545
- text: z4.string().nullable(),
546
- href: z4.string()
611
+ var formStartMetadataSchema = z4.object({
612
+ form: z4.object({
613
+ id: z4.string(),
614
+ action: z4.string().nullable()
547
615
  }),
548
616
  page: z4.object({
549
617
  path: z4.string()
550
618
  })
551
619
  }).strict();
552
- var phoneClickConfigSchema = z4.object({}).strict();
620
+ var formStartConfigSchema = z4.object({
621
+ selector: z4.string().optional()
622
+ }).strict();
553
623
 
554
- // ../tracking-core/src/events/time-on-site.ts
624
+ // ../tracking-core/src/events/form-submit.ts
555
625
  import { z as z5 } from "zod";
556
- var timeOnSiteMetadataSchema = z5.object({
557
- duration_ms: z5.number().int().nonnegative(),
626
+ var formSubmitMetadataSchema = z5.object({
627
+ form: z5.object({
628
+ id: z5.string(),
629
+ action: z5.string().nullable(),
630
+ fields: z5.array(
631
+ z5.object({
632
+ name: z5.string(),
633
+ type: z5.string(),
634
+ label: z5.string().nullable(),
635
+ has_value: z5.boolean()
636
+ })
637
+ ).optional()
638
+ }),
558
639
  page: z5.object({
559
640
  path: z5.string()
560
641
  })
561
642
  }).strict();
562
- var timeOnSiteConfigSchema = z5.object({
563
- thresholdSeconds: z5.number().int().positive()
643
+ var formSubmitConfigSchema = z5.object({}).strict();
644
+
645
+ // ../tracking-core/src/events/multi-page-session.ts
646
+ import { z as z6 } from "zod";
647
+ var multiPageSessionMetadataSchema = z6.object({
648
+ page_count: z6.number().int().min(2),
649
+ page: z6.object({
650
+ path: z6.string()
651
+ })
652
+ }).strict();
653
+ var multiPageSessionConfigSchema = z6.object({
654
+ pageThreshold: z6.number().int().min(2)
655
+ }).strict();
656
+
657
+ // ../tracking-core/src/events/phone-click.ts
658
+ import { z as z7 } from "zod";
659
+ var phoneClickMetadataSchema = z7.object({
660
+ phone_number: z7.string(),
661
+ page: z7.object({
662
+ path: z7.string()
663
+ }),
664
+ section: z7.string().nullable().optional()
665
+ }).strict();
666
+ var phoneClickConfigSchema = z7.object({}).strict();
667
+
668
+ // ../tracking-core/src/events/scroll-depth.ts
669
+ import { z as z8 } from "zod";
670
+ var scrollDepthMetadataSchema = z8.object({
671
+ depth_percent: z8.number().int().min(1).max(100),
672
+ page: z8.object({
673
+ path: z8.string()
674
+ })
675
+ }).strict();
676
+ var scrollDepthConfigSchema = z8.object({
677
+ thresholds: z8.array(z8.number().int().min(1).max(100)).min(1)
678
+ }).strict();
679
+
680
+ // ../tracking-core/src/events/specific-page-visit.ts
681
+ import { z as z9 } from "zod";
682
+ var SPECIFIC_PAGE_NAMES = [
683
+ "contact_page",
684
+ "about_page",
685
+ "services_page",
686
+ "booking_page",
687
+ "location_page",
688
+ "pricing_page",
689
+ "faq_page",
690
+ "testimonials_page"
691
+ ];
692
+ var specificPageNameSchema = z9.enum(SPECIFIC_PAGE_NAMES);
693
+ var specificPageVisitMetadataSchema = z9.object({
694
+ page_name: specificPageNameSchema,
695
+ page: z9.object({
696
+ path: z9.string()
697
+ })
698
+ }).strict();
699
+ var specificPageVisitConfigSchema = z9.object({
700
+ pages: z9.array(
701
+ z9.object({
702
+ name: specificPageNameSchema,
703
+ pathPattern: z9.custom((value) => value instanceof RegExp, {
704
+ message: "pathPattern must be a RegExp"
705
+ })
706
+ })
707
+ ).min(1)
708
+ }).strict();
709
+
710
+ // ../tracking-core/src/events/time-on-site.ts
711
+ import { z as z10 } from "zod";
712
+ var timeOnSiteMetadataSchema = z10.object({
713
+ duration_ms: z10.number().int().nonnegative(),
714
+ page: z10.object({
715
+ path: z10.string()
716
+ })
717
+ }).strict();
718
+ var timeOnSiteConfigSchema = z10.object({
719
+ thresholdSeconds: z10.number().int().positive()
564
720
  }).strict();
565
721
 
566
722
  // ../tracking-core/src/events/registry.ts
@@ -576,10 +732,31 @@ var EVENT_REGISTRY = {
576
732
  metadataSchema: timeOnSiteMetadataSchema,
577
733
  configSchema: timeOnSiteConfigSchema
578
734
  },
579
- contact_page_visit: {
735
+ specific_page_visit: {
736
+ kind: "automatic",
737
+ metadataSchema: specificPageVisitMetadataSchema,
738
+ configSchema: specificPageVisitConfigSchema
739
+ },
740
+ scroll_depth: {
741
+ kind: "automatic",
742
+ metadataSchema: scrollDepthMetadataSchema,
743
+ configSchema: scrollDepthConfigSchema
744
+ },
745
+ multi_page_session: {
746
+ kind: "automatic",
747
+ metadataSchema: multiPageSessionMetadataSchema,
748
+ configSchema: multiPageSessionConfigSchema
749
+ },
750
+ form_start: {
751
+ kind: "automatic",
752
+ metadataSchema: formStartMetadataSchema,
753
+ configSchema: formStartConfigSchema
754
+ },
755
+ // --- SDK-internal automatic (not consumer-configurable) ---
756
+ sdk_heartbeat: {
580
757
  kind: "automatic",
581
- metadataSchema: contactPageVisitMetadataSchema,
582
- configSchema: contactPageVisitConfigSchema
758
+ metadataSchema: sdkHeartbeatMetadataSchema,
759
+ configSchema: sdkHeartbeatConfigSchema
583
760
  },
584
761
  // --- manual triggers ---
585
762
  form_submit: {
@@ -591,6 +768,11 @@ var EVENT_REGISTRY = {
591
768
  kind: "manual",
592
769
  metadataSchema: phoneClickMetadataSchema,
593
770
  configSchema: phoneClickConfigSchema
771
+ },
772
+ cta_click: {
773
+ kind: "manual",
774
+ metadataSchema: ctaClickMetadataSchema,
775
+ configSchema: ctaClickConfigSchema
594
776
  }
595
777
  };
596
778
  var ALL_AUTOMATIC_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.kind === "automatic").map(([name]) => name);
@@ -681,6 +863,144 @@ function attachTimeOnSite(client, config) {
681
863
  };
682
864
  }
683
865
 
866
+ // ../tracking-core/src/triggers/scroll-depth.ts
867
+ function attachScrollDepth(client, config) {
868
+ if (typeof window === "undefined" || typeof document === "undefined") {
869
+ return () => {
870
+ };
871
+ }
872
+ const thresholds = new Set(config.thresholds);
873
+ let firedForPath = /* @__PURE__ */ new Set();
874
+ let currentPath = window.location.pathname;
875
+ let rafId = null;
876
+ function getScrollPercent() {
877
+ const doc = document.documentElement;
878
+ const scrollTop = window.scrollY || doc.scrollTop;
879
+ const scrollHeight = doc.scrollHeight;
880
+ const clientHeight = doc.clientHeight;
881
+ if (scrollHeight <= clientHeight) return 100;
882
+ return Math.round((scrollTop + clientHeight) / scrollHeight * 100);
883
+ }
884
+ function checkThresholds() {
885
+ const percent = getScrollPercent();
886
+ for (const threshold of thresholds) {
887
+ if (percent >= threshold && !firedForPath.has(threshold)) {
888
+ firedForPath.add(threshold);
889
+ client.trackEvent({
890
+ eventType: "scroll_depth",
891
+ metadata: {
892
+ depth_percent: threshold,
893
+ page: { path: currentPath }
894
+ },
895
+ pageUrl: window.location.href,
896
+ occurredAt: null
897
+ });
898
+ }
899
+ }
900
+ }
901
+ function onScroll() {
902
+ if (rafId !== null) return;
903
+ rafId = requestAnimationFrame(() => {
904
+ rafId = null;
905
+ checkThresholds();
906
+ });
907
+ }
908
+ function resetIfPathChanged() {
909
+ const newPath = window.location.pathname;
910
+ if (newPath === currentPath) return;
911
+ currentPath = newPath;
912
+ firedForPath = /* @__PURE__ */ new Set();
913
+ setTimeout(checkThresholds, 0);
914
+ }
915
+ const originalPushState = history.pushState.bind(history);
916
+ const originalReplaceState = history.replaceState.bind(history);
917
+ function patchedPushState(...args) {
918
+ originalPushState(...args);
919
+ setTimeout(resetIfPathChanged, 0);
920
+ }
921
+ function patchedReplaceState(...args) {
922
+ originalReplaceState(...args);
923
+ setTimeout(resetIfPathChanged, 0);
924
+ }
925
+ history.pushState = patchedPushState;
926
+ history.replaceState = patchedReplaceState;
927
+ window.addEventListener("popstate", resetIfPathChanged);
928
+ window.addEventListener("scroll", onScroll, { passive: true });
929
+ setTimeout(checkThresholds, 0);
930
+ return () => {
931
+ if (rafId !== null) cancelAnimationFrame(rafId);
932
+ history.pushState = originalPushState;
933
+ history.replaceState = originalReplaceState;
934
+ window.removeEventListener("popstate", resetIfPathChanged);
935
+ window.removeEventListener("scroll", onScroll);
936
+ };
937
+ }
938
+
939
+ // ../tracking-core/src/triggers/form-start.ts
940
+ function attachFormStart(client, config) {
941
+ if (typeof window === "undefined" || typeof document === "undefined") {
942
+ return () => {
943
+ };
944
+ }
945
+ const selector = config.selector ?? "form";
946
+ let firedForms = /* @__PURE__ */ new Set();
947
+ let currentPath = window.location.pathname;
948
+ function getFormKey(form) {
949
+ if (form.id) return `id:${form.id}`;
950
+ const explicitAction = form.getAttribute("action");
951
+ if (explicitAction) return `action:${explicitAction}`;
952
+ const forms = Array.from(document.querySelectorAll(selector));
953
+ return `index:${forms.indexOf(form)}`;
954
+ }
955
+ function onFocusIn(event) {
956
+ const target = event.target;
957
+ if (!(target instanceof HTMLElement)) return;
958
+ const form = target.closest(selector);
959
+ if (!form || form.tagName !== "FORM") return;
960
+ const key = getFormKey(form);
961
+ if (firedForms.has(key)) return;
962
+ firedForms.add(key);
963
+ client.trackEvent({
964
+ eventType: "form_start",
965
+ metadata: {
966
+ form: {
967
+ id: form.id || "",
968
+ action: form.getAttribute("action") ?? null
969
+ },
970
+ page: { path: window.location.pathname }
971
+ },
972
+ pageUrl: window.location.href,
973
+ occurredAt: null
974
+ });
975
+ }
976
+ function resetIfPathChanged() {
977
+ const newPath = window.location.pathname;
978
+ if (newPath === currentPath) return;
979
+ currentPath = newPath;
980
+ firedForms = /* @__PURE__ */ new Set();
981
+ }
982
+ const originalPushState = history.pushState.bind(history);
983
+ const originalReplaceState = history.replaceState.bind(history);
984
+ function patchedPushState(...args) {
985
+ originalPushState(...args);
986
+ setTimeout(resetIfPathChanged, 0);
987
+ }
988
+ function patchedReplaceState(...args) {
989
+ originalReplaceState(...args);
990
+ setTimeout(resetIfPathChanged, 0);
991
+ }
992
+ history.pushState = patchedPushState;
993
+ history.replaceState = patchedReplaceState;
994
+ window.addEventListener("popstate", resetIfPathChanged);
995
+ document.addEventListener("focusin", onFocusIn);
996
+ return () => {
997
+ history.pushState = originalPushState;
998
+ history.replaceState = originalReplaceState;
999
+ window.removeEventListener("popstate", resetIfPathChanged);
1000
+ document.removeEventListener("focusin", onFocusIn);
1001
+ };
1002
+ }
1003
+
684
1004
  // src/ConsentBanner.tsx
685
1005
  import { useEffect, useState } from "react";
686
1006
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -780,7 +1100,7 @@ function GoogleAdsTracking({ gtagId }) {
780
1100
  import { usePathname, useSearchParams } from "next/navigation";
781
1101
 
782
1102
  // package.json
783
- var version = "0.4.2";
1103
+ var version = "0.5.1";
784
1104
 
785
1105
  // src/factory.tsx
786
1106
  import {
@@ -813,7 +1133,7 @@ function createTracking(options) {
813
1133
  };
814
1134
  }
815
1135
  const TrackingContext = createContext(null);
816
- const contactPageVisitConfig = triggers.automatic.contact_page_visit ?? null;
1136
+ const specificPageVisitConfig = triggers.automatic.specific_page_visit ?? null;
817
1137
  const timeOnSiteConfig = triggers.automatic.time_on_site ?? null;
818
1138
  function TrackingProvider({ children }) {
819
1139
  const pathname = usePathname();
@@ -826,6 +1146,7 @@ function createTracking(options) {
826
1146
  surface: "next",
827
1147
  packageName: "@aranova/tracking-next",
828
1148
  sdkVersion: version,
1149
+ triggers,
829
1150
  debug
830
1151
  }),
831
1152
  triggers,
@@ -839,29 +1160,34 @@ function createTracking(options) {
839
1160
  endpoint,
840
1161
  surface: "next",
841
1162
  packageName: "@aranova/tracking-next",
1163
+ triggers,
842
1164
  debug
843
1165
  });
844
1166
  fireManualPageView(rawClient);
845
1167
  }, [pathname, searchParams]);
846
- const lastContactPathRef = useRef(null);
1168
+ const firedPagesRef = useRef(/* @__PURE__ */ new Set());
847
1169
  useEffect3(() => {
848
- if (!contactPageVisitConfig || pathname === null) return;
849
- if (!contactPageVisitConfig.pathPattern.test(pathname)) return;
850
- if (lastContactPathRef.current === pathname) return;
851
- lastContactPathRef.current = pathname;
1170
+ if (!specificPageVisitConfig || pathname === null) return;
852
1171
  const rawClient = getOrCreateTrackingClient({
853
1172
  apiKey,
854
1173
  endpoint,
855
1174
  surface: "next",
856
1175
  packageName: "@aranova/tracking-next",
1176
+ triggers,
857
1177
  debug
858
1178
  });
859
- rawClient.trackEvent({
860
- eventType: "contact_page_visit",
861
- metadata: { page: { path: pathname } },
862
- pageUrl: null,
863
- occurredAt: null
864
- });
1179
+ for (const { name, pathPattern } of specificPageVisitConfig.pages) {
1180
+ if (!pathPattern.test(pathname)) continue;
1181
+ const key = `${name}:${pathname}`;
1182
+ if (firedPagesRef.current.has(key)) continue;
1183
+ firedPagesRef.current.add(key);
1184
+ rawClient.trackEvent({
1185
+ eventType: "specific_page_visit",
1186
+ metadata: { page_name: name, page: { path: pathname } },
1187
+ pageUrl: null,
1188
+ occurredAt: null
1189
+ });
1190
+ }
865
1191
  }, [pathname]);
866
1192
  useEffect3(() => {
867
1193
  const rawClient = getOrCreateTrackingClient({
@@ -869,6 +1195,7 @@ function createTracking(options) {
869
1195
  endpoint,
870
1196
  surface: "next",
871
1197
  packageName: "@aranova/tracking-next",
1198
+ triggers,
872
1199
  debug
873
1200
  });
874
1201
  return attachBfcacheRestore(rawClient);
@@ -880,10 +1207,81 @@ function createTracking(options) {
880
1207
  endpoint,
881
1208
  surface: "next",
882
1209
  packageName: "@aranova/tracking-next",
1210
+ triggers,
883
1211
  debug
884
1212
  });
885
1213
  return attachTimeOnSite(rawClient, timeOnSiteConfig);
886
1214
  }, []);
1215
+ const multiPageSessionConfig = triggers.automatic.multi_page_session ?? null;
1216
+ const mpsLastPathRef = useRef(null);
1217
+ useEffect3(() => {
1218
+ if (!multiPageSessionConfig || pathname === null) return;
1219
+ if (pathname === mpsLastPathRef.current) return;
1220
+ mpsLastPathRef.current = pathname;
1221
+ const MPS_PATHS_KEY = "aranova_tracking_mps_paths";
1222
+ const MPS_SESSION_KEY = "aranova_tracking_mps_session";
1223
+ const MPS_FIRED_KEY = "aranova_tracking_mps_fired";
1224
+ try {
1225
+ const store = window.sessionStorage;
1226
+ const currentSession = getOrRotateSessionId().id;
1227
+ const storedSession = store.getItem(MPS_SESSION_KEY);
1228
+ if (storedSession !== currentSession) {
1229
+ store.setItem(MPS_SESSION_KEY, currentSession);
1230
+ store.removeItem(MPS_PATHS_KEY);
1231
+ store.removeItem(MPS_FIRED_KEY);
1232
+ }
1233
+ if (store.getItem(MPS_FIRED_KEY) === "1") return;
1234
+ const raw = store.getItem(MPS_PATHS_KEY);
1235
+ const paths = raw ? new Set(JSON.parse(raw)) : /* @__PURE__ */ new Set();
1236
+ paths.add(pathname);
1237
+ store.setItem(MPS_PATHS_KEY, JSON.stringify([...paths]));
1238
+ if (paths.size >= multiPageSessionConfig.pageThreshold) {
1239
+ store.setItem(MPS_FIRED_KEY, "1");
1240
+ const rawClient = getOrCreateTrackingClient({
1241
+ apiKey,
1242
+ endpoint,
1243
+ surface: "next",
1244
+ packageName: "@aranova/tracking-next",
1245
+ triggers,
1246
+ debug
1247
+ });
1248
+ rawClient.trackEvent({
1249
+ eventType: "multi_page_session",
1250
+ metadata: {
1251
+ page_count: paths.size,
1252
+ page: { path: pathname }
1253
+ },
1254
+ pageUrl: null,
1255
+ occurredAt: null
1256
+ });
1257
+ }
1258
+ } catch {
1259
+ }
1260
+ }, [pathname]);
1261
+ useEffect3(() => {
1262
+ const detachers = [];
1263
+ const rawClient = getOrCreateTrackingClient({
1264
+ apiKey,
1265
+ endpoint,
1266
+ surface: "next",
1267
+ packageName: "@aranova/tracking-next",
1268
+ triggers,
1269
+ debug
1270
+ });
1271
+ const scrollDepth = triggers.automatic.scroll_depth;
1272
+ if (scrollDepth) {
1273
+ detachers.push(attachScrollDepth(rawClient, scrollDepth));
1274
+ }
1275
+ const formStart = triggers.automatic.form_start;
1276
+ if (formStart) {
1277
+ detachers.push(attachFormStart(rawClient, formStart));
1278
+ }
1279
+ return () => {
1280
+ for (let i = detachers.length - 1; i >= 0; i--) {
1281
+ detachers[i]();
1282
+ }
1283
+ };
1284
+ }, []);
887
1285
  return /* @__PURE__ */ jsx3(TrackingContext.Provider, { value: client, children });
888
1286
  }
889
1287
  function useTracking() {