@aranova/tracking-react 0.5.0 → 0.6.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.js CHANGED
@@ -267,7 +267,7 @@ function getVisitorId() {
267
267
  }
268
268
  function getOrRotateSessionId(now = Date.now()) {
269
269
  if (typeof window === "undefined")
270
- return safeUuid();
270
+ return { id: safeUuid(), isNew: true };
271
271
  const raw = readLocalStorage(SESSION_STORAGE_KEY);
272
272
  if (raw) {
273
273
  try {
@@ -276,7 +276,7 @@ function getOrRotateSessionId(now = Date.now()) {
276
276
  if (now - parsed.last_event_at <= SESSION_IDLE_MS) {
277
277
  const refreshed = { id: parsed.id, last_event_at: now };
278
278
  writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(refreshed));
279
- return parsed.id;
279
+ return { id: parsed.id, isNew: false };
280
280
  }
281
281
  }
282
282
  } catch {
@@ -284,7 +284,7 @@ function getOrRotateSessionId(now = Date.now()) {
284
284
  }
285
285
  const fresh = { id: safeUuid(), last_event_at: now };
286
286
  writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(fresh));
287
- return fresh.id;
287
+ return { id: fresh.id, isNew: true };
288
288
  }
289
289
 
290
290
  // ../tracking-core/src/events/page-view.ts
@@ -295,7 +295,7 @@ var pageViewMetadataSchema = import_zod.z.object({
295
295
  path: import_zod.z.string(),
296
296
  search: import_zod.z.string(),
297
297
  hash: import_zod.z.string()
298
- }),
298
+ }).strict(),
299
299
  referrer: import_zod.z.string().nullable(),
300
300
  // `.nullable().optional()` — absent (undefined) OR explicit null OR a
301
301
  // real viewport object. Mirrors Pydantic's `_Viewport | None = None`
@@ -303,7 +303,7 @@ var pageViewMetadataSchema = import_zod.z.object({
303
303
  viewport: import_zod.z.object({
304
304
  w: import_zod.z.number(),
305
305
  h: import_zod.z.number()
306
- }).nullable().optional()
306
+ }).strict().nullable().optional()
307
307
  }).strict();
308
308
  var pageViewConfigSchema = import_zod.z.object({}).strict();
309
309
 
@@ -424,6 +424,56 @@ function attachAutoPageView(client, options = {}) {
424
424
  };
425
425
  }
426
426
 
427
+ // ../tracking-core/src/heartbeat.ts
428
+ function serializeValue(value) {
429
+ if (value instanceof RegExp) return value.source;
430
+ if (Array.isArray(value)) return value.map(serializeValue);
431
+ if (value !== null && typeof value === "object") {
432
+ const out = {};
433
+ for (const [k, v] of Object.entries(value)) {
434
+ out[k] = serializeValue(v);
435
+ }
436
+ return out;
437
+ }
438
+ return value;
439
+ }
440
+ function buildHeartbeatMetadata(surface, sdkVersion, packageName, triggers) {
441
+ const automaticNames = triggers ? Object.keys(triggers.automatic) : [];
442
+ const manualNames = triggers?.manual ? Object.keys(triggers.manual) : [];
443
+ let triggerConfig = null;
444
+ if (triggers) {
445
+ const cfg = {};
446
+ for (const [name, config] of Object.entries(triggers.automatic)) {
447
+ const serialized = serializeValue(config);
448
+ if (Object.keys(serialized).length > 0) {
449
+ cfg[name] = serialized;
450
+ }
451
+ }
452
+ if (triggers.manual) {
453
+ for (const [name, config] of Object.entries(triggers.manual)) {
454
+ if (config === void 0) continue;
455
+ const serialized = serializeValue(config);
456
+ if (Object.keys(serialized).length > 0) {
457
+ cfg[name] = serialized;
458
+ }
459
+ }
460
+ }
461
+ if (Object.keys(cfg).length > 0) {
462
+ triggerConfig = cfg;
463
+ }
464
+ }
465
+ return {
466
+ sdk_version: sdkVersion ?? "unknown",
467
+ package_name: packageName,
468
+ surface,
469
+ triggers: {
470
+ automatic: automaticNames,
471
+ manual: manualNames
472
+ },
473
+ trigger_config: triggerConfig
474
+ };
475
+ }
476
+
427
477
  // ../tracking-core/src/ingest.ts
428
478
  var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
429
479
  var DEFAULT_MAX_QUEUE_SIZE = 10;
@@ -503,11 +553,33 @@ function createTrackingClient(config) {
503
553
  let firstPage = null;
504
554
  let destroyed = false;
505
555
  const visitorId = getVisitorId();
506
- let sessionId = getOrRotateSessionId();
556
+ const initialSession = getOrRotateSessionId();
557
+ let sessionId = initialSession.id;
507
558
  if (typeof window !== "undefined")
508
559
  firstPage = window.location.href;
560
+ function enqueueHeartbeat() {
561
+ const metadata = buildHeartbeatMetadata(
562
+ config.surface,
563
+ sdkVersion,
564
+ packageName,
565
+ config.triggers ?? null
566
+ );
567
+ queue.push({
568
+ event_type: "sdk_heartbeat",
569
+ page_url: typeof window === "undefined" ? null : window.location.href,
570
+ metadata,
571
+ occurred_at: (/* @__PURE__ */ new Date()).toISOString()
572
+ });
573
+ }
574
+ if (initialSession.isNew) {
575
+ enqueueHeartbeat();
576
+ }
509
577
  function buildSessionPayload() {
510
- sessionId = getOrRotateSessionId();
578
+ const rotated = getOrRotateSessionId();
579
+ if (rotated.isNew && rotated.id !== sessionId) {
580
+ enqueueHeartbeat();
581
+ }
582
+ sessionId = rotated.id;
511
583
  const params = readTrackingParams();
512
584
  const context = buildContext(config.surface, sdkVersion, packageName);
513
585
  return {
@@ -614,85 +686,110 @@ var ctaClickMetadataSchema = import_zod2.z.object({
614
686
  cta_name: import_zod2.z.string(),
615
687
  page: import_zod2.z.object({
616
688
  path: import_zod2.z.string()
617
- }),
689
+ }).strict(),
618
690
  section: import_zod2.z.string().nullable().optional(),
619
691
  destination_url: import_zod2.z.string().nullable().optional()
620
692
  }).strict();
621
693
  var ctaClickConfigSchema = import_zod2.z.object({}).strict();
622
694
 
623
- // ../tracking-core/src/events/form-start.ts
695
+ // ../tracking-core/src/events/sdk-heartbeat.ts
624
696
  var import_zod3 = require("zod");
625
- var formStartMetadataSchema = import_zod3.z.object({
626
- form: import_zod3.z.object({
627
- id: import_zod3.z.string(),
628
- action: import_zod3.z.string().nullable()
629
- }),
630
- page: import_zod3.z.object({
631
- path: import_zod3.z.string()
632
- })
697
+ var sdkHeartbeatTriggersSchema = import_zod3.z.object({
698
+ automatic: import_zod3.z.array(import_zod3.z.string()),
699
+ manual: import_zod3.z.array(import_zod3.z.string())
633
700
  }).strict();
634
- var formStartConfigSchema = import_zod3.z.object({
635
- selector: import_zod3.z.string().optional()
701
+ var sdkHeartbeatMetadataSchema = import_zod3.z.object({
702
+ sdk_version: import_zod3.z.string(),
703
+ package_name: import_zod3.z.string().nullable(),
704
+ surface: import_zod3.z.enum(["next", "react", "script"]),
705
+ triggers: sdkHeartbeatTriggersSchema,
706
+ trigger_config: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown())).nullable().optional()
636
707
  }).strict();
708
+ var sdkHeartbeatConfigSchema = import_zod3.z.object({}).strict();
637
709
 
638
- // ../tracking-core/src/events/form-submit.ts
710
+ // ../tracking-core/src/events/form-start.ts
639
711
  var import_zod4 = require("zod");
640
- var formSubmitMetadataSchema = import_zod4.z.object({
712
+ var formStartMetadataSchema = import_zod4.z.object({
641
713
  form: import_zod4.z.object({
642
714
  id: import_zod4.z.string(),
643
- action: import_zod4.z.string().nullable(),
644
- fields: import_zod4.z.array(
645
- import_zod4.z.object({
646
- name: import_zod4.z.string(),
647
- type: import_zod4.z.string(),
648
- label: import_zod4.z.string().nullable(),
649
- has_value: import_zod4.z.boolean()
650
- })
651
- ).optional()
652
- }),
715
+ action: import_zod4.z.string().nullable()
716
+ }).strict(),
653
717
  page: import_zod4.z.object({
654
718
  path: import_zod4.z.string()
655
- })
719
+ }).strict()
720
+ }).strict();
721
+ var formStartConfigSchema = import_zod4.z.object({
722
+ selector: import_zod4.z.string().optional()
656
723
  }).strict();
657
- var formSubmitConfigSchema = import_zod4.z.object({}).strict();
658
724
 
659
- // ../tracking-core/src/events/multi-page-session.ts
725
+ // ../tracking-core/src/events/form-submit.ts
660
726
  var import_zod5 = require("zod");
661
- var multiPageSessionMetadataSchema = import_zod5.z.object({
662
- page_count: import_zod5.z.number().int().min(2),
727
+ var jsonValueSchema = import_zod5.z.lazy(
728
+ () => import_zod5.z.union([
729
+ import_zod5.z.string(),
730
+ import_zod5.z.number().finite(),
731
+ import_zod5.z.boolean(),
732
+ import_zod5.z.null(),
733
+ import_zod5.z.array(jsonValueSchema),
734
+ import_zod5.z.record(jsonValueSchema)
735
+ ])
736
+ );
737
+ var formSubmitMetadataSchema = import_zod5.z.object({
738
+ form: import_zod5.z.object({
739
+ id: import_zod5.z.string(),
740
+ action: import_zod5.z.string().nullable(),
741
+ fields: import_zod5.z.array(
742
+ import_zod5.z.object({
743
+ name: import_zod5.z.string(),
744
+ type: import_zod5.z.string(),
745
+ label: import_zod5.z.string().nullable(),
746
+ value: jsonValueSchema
747
+ }).strict()
748
+ ).optional()
749
+ }).strict(),
663
750
  page: import_zod5.z.object({
664
751
  path: import_zod5.z.string()
665
- })
666
- }).strict();
667
- var multiPageSessionConfigSchema = import_zod5.z.object({
668
- pageThreshold: import_zod5.z.number().int().min(2)
752
+ }).strict()
669
753
  }).strict();
754
+ var formSubmitConfigSchema = import_zod5.z.object({}).strict();
670
755
 
671
- // ../tracking-core/src/events/phone-click.ts
756
+ // ../tracking-core/src/events/multi-page-session.ts
672
757
  var import_zod6 = require("zod");
673
- var phoneClickMetadataSchema = import_zod6.z.object({
674
- phone_number: import_zod6.z.string(),
758
+ var multiPageSessionMetadataSchema = import_zod6.z.object({
759
+ page_count: import_zod6.z.number().int().min(2),
675
760
  page: import_zod6.z.object({
676
761
  path: import_zod6.z.string()
677
- }),
678
- section: import_zod6.z.string().nullable().optional()
762
+ }).strict()
763
+ }).strict();
764
+ var multiPageSessionConfigSchema = import_zod6.z.object({
765
+ pageThreshold: import_zod6.z.number().int().min(2)
679
766
  }).strict();
680
- var phoneClickConfigSchema = import_zod6.z.object({}).strict();
681
767
 
682
- // ../tracking-core/src/events/scroll-depth.ts
768
+ // ../tracking-core/src/events/phone-click.ts
683
769
  var import_zod7 = require("zod");
684
- var scrollDepthMetadataSchema = import_zod7.z.object({
685
- depth_percent: import_zod7.z.number().int().min(1).max(100),
770
+ var phoneClickMetadataSchema = import_zod7.z.object({
771
+ phone_number: import_zod7.z.string(),
686
772
  page: import_zod7.z.object({
687
773
  path: import_zod7.z.string()
688
- })
774
+ }).strict(),
775
+ section: import_zod7.z.string().nullable().optional()
776
+ }).strict();
777
+ var phoneClickConfigSchema = import_zod7.z.object({}).strict();
778
+
779
+ // ../tracking-core/src/events/scroll-depth.ts
780
+ var import_zod8 = require("zod");
781
+ var scrollDepthMetadataSchema = import_zod8.z.object({
782
+ depth_percent: import_zod8.z.number().int().min(1).max(100),
783
+ page: import_zod8.z.object({
784
+ path: import_zod8.z.string()
785
+ }).strict()
689
786
  }).strict();
690
- var scrollDepthConfigSchema = import_zod7.z.object({
691
- thresholds: import_zod7.z.array(import_zod7.z.number().int().min(1).max(100)).min(1)
787
+ var scrollDepthConfigSchema = import_zod8.z.object({
788
+ thresholds: import_zod8.z.array(import_zod8.z.number().int().min(1).max(100)).min(1)
692
789
  }).strict();
693
790
 
694
791
  // ../tracking-core/src/events/specific-page-visit.ts
695
- var import_zod8 = require("zod");
792
+ var import_zod9 = require("zod");
696
793
  var SPECIFIC_PAGE_NAMES = [
697
794
  "contact_page",
698
795
  "about_page",
@@ -703,34 +800,34 @@ var SPECIFIC_PAGE_NAMES = [
703
800
  "faq_page",
704
801
  "testimonials_page"
705
802
  ];
706
- var specificPageNameSchema = import_zod8.z.enum(SPECIFIC_PAGE_NAMES);
707
- var specificPageVisitMetadataSchema = import_zod8.z.object({
803
+ var specificPageNameSchema = import_zod9.z.enum(SPECIFIC_PAGE_NAMES);
804
+ var specificPageVisitMetadataSchema = import_zod9.z.object({
708
805
  page_name: specificPageNameSchema,
709
- page: import_zod8.z.object({
710
- path: import_zod8.z.string()
711
- })
806
+ page: import_zod9.z.object({
807
+ path: import_zod9.z.string()
808
+ }).strict()
712
809
  }).strict();
713
- var specificPageVisitConfigSchema = import_zod8.z.object({
714
- pages: import_zod8.z.array(
715
- import_zod8.z.object({
810
+ var specificPageVisitConfigSchema = import_zod9.z.object({
811
+ pages: import_zod9.z.array(
812
+ import_zod9.z.object({
716
813
  name: specificPageNameSchema,
717
- pathPattern: import_zod8.z.custom((value) => value instanceof RegExp, {
814
+ pathPattern: import_zod9.z.custom((value) => value instanceof RegExp, {
718
815
  message: "pathPattern must be a RegExp"
719
816
  })
720
- })
817
+ }).strict()
721
818
  ).min(1)
722
819
  }).strict();
723
820
 
724
821
  // ../tracking-core/src/events/time-on-site.ts
725
- var import_zod9 = require("zod");
726
- var timeOnSiteMetadataSchema = import_zod9.z.object({
727
- duration_ms: import_zod9.z.number().int().nonnegative(),
728
- page: import_zod9.z.object({
729
- path: import_zod9.z.string()
730
- })
822
+ var import_zod10 = require("zod");
823
+ var timeOnSiteMetadataSchema = import_zod10.z.object({
824
+ duration_ms: import_zod10.z.number().int().nonnegative(),
825
+ page: import_zod10.z.object({
826
+ path: import_zod10.z.string()
827
+ }).strict()
731
828
  }).strict();
732
- var timeOnSiteConfigSchema = import_zod9.z.object({
733
- thresholdSeconds: import_zod9.z.number().int().positive()
829
+ var timeOnSiteConfigSchema = import_zod10.z.object({
830
+ thresholdSeconds: import_zod10.z.number().int().positive()
734
831
  }).strict();
735
832
 
736
833
  // ../tracking-core/src/events/registry.ts
@@ -766,6 +863,12 @@ var EVENT_REGISTRY = {
766
863
  metadataSchema: formStartMetadataSchema,
767
864
  configSchema: formStartConfigSchema
768
865
  },
866
+ // --- SDK-internal automatic (not consumer-configurable) ---
867
+ sdk_heartbeat: {
868
+ kind: "automatic",
869
+ metadataSchema: sdkHeartbeatMetadataSchema,
870
+ configSchema: sdkHeartbeatConfigSchema
871
+ },
769
872
  // --- manual triggers ---
770
873
  form_submit: {
771
874
  kind: "manual",
@@ -1025,7 +1128,7 @@ function attachMultiPageSession(client, config) {
1025
1128
  }
1026
1129
  }
1027
1130
  function resetIfSessionChanged() {
1028
- const currentSession = getOrRotateSessionId();
1131
+ const currentSession = getOrRotateSessionId().id;
1029
1132
  const storedSession = storage.getItem(SESSION_KEY);
1030
1133
  if (storedSession !== currentSession) {
1031
1134
  storage.setItem(SESSION_KEY, currentSession);
@@ -1233,7 +1336,7 @@ function useConsentState() {
1233
1336
  var import_react4 = require("react");
1234
1337
 
1235
1338
  // package.json
1236
- var version = "0.5.0";
1339
+ var version = "0.6.0";
1237
1340
 
1238
1341
  // src/factory.tsx
1239
1342
  var import_jsx_runtime2 = require("react/jsx-runtime");
@@ -1269,6 +1372,7 @@ function createTracking(options) {
1269
1372
  surface: "react",
1270
1373
  packageName: "@aranova/tracking-react",
1271
1374
  sdkVersion: version,
1375
+ triggers,
1272
1376
  debug
1273
1377
  }),
1274
1378
  triggers,
@@ -1287,6 +1391,7 @@ function createTracking(options) {
1287
1391
  endpoint,
1288
1392
  surface: "react",
1289
1393
  packageName: "@aranova/tracking-react",
1394
+ triggers,
1290
1395
  debug
1291
1396
  });
1292
1397
  detachers.push(attachAutoPageView(rawClient));