@aranova/tracking-next 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
@@ -254,7 +254,7 @@ function getVisitorId() {
254
254
  }
255
255
  function getOrRotateSessionId(now = Date.now()) {
256
256
  if (typeof window === "undefined")
257
- return safeUuid();
257
+ return { id: safeUuid(), isNew: true };
258
258
  const raw = readLocalStorage(SESSION_STORAGE_KEY);
259
259
  if (raw) {
260
260
  try {
@@ -263,7 +263,7 @@ function getOrRotateSessionId(now = Date.now()) {
263
263
  if (now - parsed.last_event_at <= SESSION_IDLE_MS) {
264
264
  const refreshed = { id: parsed.id, last_event_at: now };
265
265
  writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(refreshed));
266
- return parsed.id;
266
+ return { id: parsed.id, isNew: false };
267
267
  }
268
268
  }
269
269
  } catch {
@@ -271,7 +271,7 @@ function getOrRotateSessionId(now = Date.now()) {
271
271
  }
272
272
  const fresh = { id: safeUuid(), last_event_at: now };
273
273
  writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(fresh));
274
- return fresh.id;
274
+ return { id: fresh.id, isNew: true };
275
275
  }
276
276
 
277
277
  // ../tracking-core/src/events/page-view.ts
@@ -282,7 +282,7 @@ var pageViewMetadataSchema = import_zod.z.object({
282
282
  path: import_zod.z.string(),
283
283
  search: import_zod.z.string(),
284
284
  hash: import_zod.z.string()
285
- }),
285
+ }).strict(),
286
286
  referrer: import_zod.z.string().nullable(),
287
287
  // `.nullable().optional()` — absent (undefined) OR explicit null OR a
288
288
  // real viewport object. Mirrors Pydantic's `_Viewport | None = None`
@@ -290,7 +290,7 @@ var pageViewMetadataSchema = import_zod.z.object({
290
290
  viewport: import_zod.z.object({
291
291
  w: import_zod.z.number(),
292
292
  h: import_zod.z.number()
293
- }).nullable().optional()
293
+ }).strict().nullable().optional()
294
294
  }).strict();
295
295
  var pageViewConfigSchema = import_zod.z.object({}).strict();
296
296
 
@@ -371,6 +371,56 @@ function attachBfcacheRestore(client) {
371
371
  };
372
372
  }
373
373
 
374
+ // ../tracking-core/src/heartbeat.ts
375
+ function serializeValue(value) {
376
+ if (value instanceof RegExp) return value.source;
377
+ if (Array.isArray(value)) return value.map(serializeValue);
378
+ if (value !== null && typeof value === "object") {
379
+ const out = {};
380
+ for (const [k, v] of Object.entries(value)) {
381
+ out[k] = serializeValue(v);
382
+ }
383
+ return out;
384
+ }
385
+ return value;
386
+ }
387
+ function buildHeartbeatMetadata(surface, sdkVersion, packageName, triggers) {
388
+ const automaticNames = triggers ? Object.keys(triggers.automatic) : [];
389
+ const manualNames = triggers?.manual ? Object.keys(triggers.manual) : [];
390
+ let triggerConfig = null;
391
+ if (triggers) {
392
+ const cfg = {};
393
+ for (const [name, config] of Object.entries(triggers.automatic)) {
394
+ const serialized = serializeValue(config);
395
+ if (Object.keys(serialized).length > 0) {
396
+ cfg[name] = serialized;
397
+ }
398
+ }
399
+ if (triggers.manual) {
400
+ for (const [name, config] of Object.entries(triggers.manual)) {
401
+ if (config === void 0) continue;
402
+ const serialized = serializeValue(config);
403
+ if (Object.keys(serialized).length > 0) {
404
+ cfg[name] = serialized;
405
+ }
406
+ }
407
+ }
408
+ if (Object.keys(cfg).length > 0) {
409
+ triggerConfig = cfg;
410
+ }
411
+ }
412
+ return {
413
+ sdk_version: sdkVersion ?? "unknown",
414
+ package_name: packageName,
415
+ surface,
416
+ triggers: {
417
+ automatic: automaticNames,
418
+ manual: manualNames
419
+ },
420
+ trigger_config: triggerConfig
421
+ };
422
+ }
423
+
374
424
  // ../tracking-core/src/ingest.ts
375
425
  var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
376
426
  var DEFAULT_MAX_QUEUE_SIZE = 10;
@@ -450,11 +500,33 @@ function createTrackingClient(config) {
450
500
  let firstPage = null;
451
501
  let destroyed = false;
452
502
  const visitorId = getVisitorId();
453
- let sessionId = getOrRotateSessionId();
503
+ const initialSession = getOrRotateSessionId();
504
+ let sessionId = initialSession.id;
454
505
  if (typeof window !== "undefined")
455
506
  firstPage = window.location.href;
507
+ function enqueueHeartbeat() {
508
+ const metadata = buildHeartbeatMetadata(
509
+ config.surface,
510
+ sdkVersion,
511
+ packageName,
512
+ config.triggers ?? null
513
+ );
514
+ queue.push({
515
+ event_type: "sdk_heartbeat",
516
+ page_url: typeof window === "undefined" ? null : window.location.href,
517
+ metadata,
518
+ occurred_at: (/* @__PURE__ */ new Date()).toISOString()
519
+ });
520
+ }
521
+ if (initialSession.isNew) {
522
+ enqueueHeartbeat();
523
+ }
456
524
  function buildSessionPayload() {
457
- sessionId = getOrRotateSessionId();
525
+ const rotated = getOrRotateSessionId();
526
+ if (rotated.isNew && rotated.id !== sessionId) {
527
+ enqueueHeartbeat();
528
+ }
529
+ sessionId = rotated.id;
458
530
  const params = readTrackingParams();
459
531
  const context = buildContext(config.surface, sdkVersion, packageName);
460
532
  return {
@@ -561,85 +633,110 @@ var ctaClickMetadataSchema = import_zod2.z.object({
561
633
  cta_name: import_zod2.z.string(),
562
634
  page: import_zod2.z.object({
563
635
  path: import_zod2.z.string()
564
- }),
636
+ }).strict(),
565
637
  section: import_zod2.z.string().nullable().optional(),
566
638
  destination_url: import_zod2.z.string().nullable().optional()
567
639
  }).strict();
568
640
  var ctaClickConfigSchema = import_zod2.z.object({}).strict();
569
641
 
570
- // ../tracking-core/src/events/form-start.ts
642
+ // ../tracking-core/src/events/sdk-heartbeat.ts
571
643
  var import_zod3 = require("zod");
572
- var formStartMetadataSchema = import_zod3.z.object({
573
- form: import_zod3.z.object({
574
- id: import_zod3.z.string(),
575
- action: import_zod3.z.string().nullable()
576
- }),
577
- page: import_zod3.z.object({
578
- path: import_zod3.z.string()
579
- })
644
+ var sdkHeartbeatTriggersSchema = import_zod3.z.object({
645
+ automatic: import_zod3.z.array(import_zod3.z.string()),
646
+ manual: import_zod3.z.array(import_zod3.z.string())
580
647
  }).strict();
581
- var formStartConfigSchema = import_zod3.z.object({
582
- selector: import_zod3.z.string().optional()
648
+ var sdkHeartbeatMetadataSchema = import_zod3.z.object({
649
+ sdk_version: import_zod3.z.string(),
650
+ package_name: import_zod3.z.string().nullable(),
651
+ surface: import_zod3.z.enum(["next", "react", "script"]),
652
+ triggers: sdkHeartbeatTriggersSchema,
653
+ trigger_config: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown())).nullable().optional()
583
654
  }).strict();
655
+ var sdkHeartbeatConfigSchema = import_zod3.z.object({}).strict();
584
656
 
585
- // ../tracking-core/src/events/form-submit.ts
657
+ // ../tracking-core/src/events/form-start.ts
586
658
  var import_zod4 = require("zod");
587
- var formSubmitMetadataSchema = import_zod4.z.object({
659
+ var formStartMetadataSchema = import_zod4.z.object({
588
660
  form: import_zod4.z.object({
589
661
  id: import_zod4.z.string(),
590
- action: import_zod4.z.string().nullable(),
591
- fields: import_zod4.z.array(
592
- import_zod4.z.object({
593
- name: import_zod4.z.string(),
594
- type: import_zod4.z.string(),
595
- label: import_zod4.z.string().nullable(),
596
- has_value: import_zod4.z.boolean()
597
- })
598
- ).optional()
599
- }),
662
+ action: import_zod4.z.string().nullable()
663
+ }).strict(),
600
664
  page: import_zod4.z.object({
601
665
  path: import_zod4.z.string()
602
- })
666
+ }).strict()
667
+ }).strict();
668
+ var formStartConfigSchema = import_zod4.z.object({
669
+ selector: import_zod4.z.string().optional()
603
670
  }).strict();
604
- var formSubmitConfigSchema = import_zod4.z.object({}).strict();
605
671
 
606
- // ../tracking-core/src/events/multi-page-session.ts
672
+ // ../tracking-core/src/events/form-submit.ts
607
673
  var import_zod5 = require("zod");
608
- var multiPageSessionMetadataSchema = import_zod5.z.object({
609
- page_count: import_zod5.z.number().int().min(2),
674
+ var jsonValueSchema = import_zod5.z.lazy(
675
+ () => import_zod5.z.union([
676
+ import_zod5.z.string(),
677
+ import_zod5.z.number().finite(),
678
+ import_zod5.z.boolean(),
679
+ import_zod5.z.null(),
680
+ import_zod5.z.array(jsonValueSchema),
681
+ import_zod5.z.record(jsonValueSchema)
682
+ ])
683
+ );
684
+ var formSubmitMetadataSchema = import_zod5.z.object({
685
+ form: import_zod5.z.object({
686
+ id: import_zod5.z.string(),
687
+ action: import_zod5.z.string().nullable(),
688
+ fields: import_zod5.z.array(
689
+ import_zod5.z.object({
690
+ name: import_zod5.z.string(),
691
+ type: import_zod5.z.string(),
692
+ label: import_zod5.z.string().nullable(),
693
+ value: jsonValueSchema
694
+ }).strict()
695
+ ).optional()
696
+ }).strict(),
610
697
  page: import_zod5.z.object({
611
698
  path: import_zod5.z.string()
612
- })
613
- }).strict();
614
- var multiPageSessionConfigSchema = import_zod5.z.object({
615
- pageThreshold: import_zod5.z.number().int().min(2)
699
+ }).strict()
616
700
  }).strict();
701
+ var formSubmitConfigSchema = import_zod5.z.object({}).strict();
617
702
 
618
- // ../tracking-core/src/events/phone-click.ts
703
+ // ../tracking-core/src/events/multi-page-session.ts
619
704
  var import_zod6 = require("zod");
620
- var phoneClickMetadataSchema = import_zod6.z.object({
621
- phone_number: import_zod6.z.string(),
705
+ var multiPageSessionMetadataSchema = import_zod6.z.object({
706
+ page_count: import_zod6.z.number().int().min(2),
622
707
  page: import_zod6.z.object({
623
708
  path: import_zod6.z.string()
624
- }),
625
- section: import_zod6.z.string().nullable().optional()
709
+ }).strict()
710
+ }).strict();
711
+ var multiPageSessionConfigSchema = import_zod6.z.object({
712
+ pageThreshold: import_zod6.z.number().int().min(2)
626
713
  }).strict();
627
- var phoneClickConfigSchema = import_zod6.z.object({}).strict();
628
714
 
629
- // ../tracking-core/src/events/scroll-depth.ts
715
+ // ../tracking-core/src/events/phone-click.ts
630
716
  var import_zod7 = require("zod");
631
- var scrollDepthMetadataSchema = import_zod7.z.object({
632
- depth_percent: import_zod7.z.number().int().min(1).max(100),
717
+ var phoneClickMetadataSchema = import_zod7.z.object({
718
+ phone_number: import_zod7.z.string(),
633
719
  page: import_zod7.z.object({
634
720
  path: import_zod7.z.string()
635
- })
721
+ }).strict(),
722
+ section: import_zod7.z.string().nullable().optional()
636
723
  }).strict();
637
- var scrollDepthConfigSchema = import_zod7.z.object({
638
- thresholds: import_zod7.z.array(import_zod7.z.number().int().min(1).max(100)).min(1)
724
+ var phoneClickConfigSchema = import_zod7.z.object({}).strict();
725
+
726
+ // ../tracking-core/src/events/scroll-depth.ts
727
+ var import_zod8 = require("zod");
728
+ var scrollDepthMetadataSchema = import_zod8.z.object({
729
+ depth_percent: import_zod8.z.number().int().min(1).max(100),
730
+ page: import_zod8.z.object({
731
+ path: import_zod8.z.string()
732
+ }).strict()
733
+ }).strict();
734
+ var scrollDepthConfigSchema = import_zod8.z.object({
735
+ thresholds: import_zod8.z.array(import_zod8.z.number().int().min(1).max(100)).min(1)
639
736
  }).strict();
640
737
 
641
738
  // ../tracking-core/src/events/specific-page-visit.ts
642
- var import_zod8 = require("zod");
739
+ var import_zod9 = require("zod");
643
740
  var SPECIFIC_PAGE_NAMES = [
644
741
  "contact_page",
645
742
  "about_page",
@@ -650,34 +747,34 @@ var SPECIFIC_PAGE_NAMES = [
650
747
  "faq_page",
651
748
  "testimonials_page"
652
749
  ];
653
- var specificPageNameSchema = import_zod8.z.enum(SPECIFIC_PAGE_NAMES);
654
- var specificPageVisitMetadataSchema = import_zod8.z.object({
750
+ var specificPageNameSchema = import_zod9.z.enum(SPECIFIC_PAGE_NAMES);
751
+ var specificPageVisitMetadataSchema = import_zod9.z.object({
655
752
  page_name: specificPageNameSchema,
656
- page: import_zod8.z.object({
657
- path: import_zod8.z.string()
658
- })
753
+ page: import_zod9.z.object({
754
+ path: import_zod9.z.string()
755
+ }).strict()
659
756
  }).strict();
660
- var specificPageVisitConfigSchema = import_zod8.z.object({
661
- pages: import_zod8.z.array(
662
- import_zod8.z.object({
757
+ var specificPageVisitConfigSchema = import_zod9.z.object({
758
+ pages: import_zod9.z.array(
759
+ import_zod9.z.object({
663
760
  name: specificPageNameSchema,
664
- pathPattern: import_zod8.z.custom((value) => value instanceof RegExp, {
761
+ pathPattern: import_zod9.z.custom((value) => value instanceof RegExp, {
665
762
  message: "pathPattern must be a RegExp"
666
763
  })
667
- })
764
+ }).strict()
668
765
  ).min(1)
669
766
  }).strict();
670
767
 
671
768
  // ../tracking-core/src/events/time-on-site.ts
672
- var import_zod9 = require("zod");
673
- var timeOnSiteMetadataSchema = import_zod9.z.object({
674
- duration_ms: import_zod9.z.number().int().nonnegative(),
675
- page: import_zod9.z.object({
676
- path: import_zod9.z.string()
677
- })
769
+ var import_zod10 = require("zod");
770
+ var timeOnSiteMetadataSchema = import_zod10.z.object({
771
+ duration_ms: import_zod10.z.number().int().nonnegative(),
772
+ page: import_zod10.z.object({
773
+ path: import_zod10.z.string()
774
+ }).strict()
678
775
  }).strict();
679
- var timeOnSiteConfigSchema = import_zod9.z.object({
680
- thresholdSeconds: import_zod9.z.number().int().positive()
776
+ var timeOnSiteConfigSchema = import_zod10.z.object({
777
+ thresholdSeconds: import_zod10.z.number().int().positive()
681
778
  }).strict();
682
779
 
683
780
  // ../tracking-core/src/events/registry.ts
@@ -713,6 +810,12 @@ var EVENT_REGISTRY = {
713
810
  metadataSchema: formStartMetadataSchema,
714
811
  configSchema: formStartConfigSchema
715
812
  },
813
+ // --- SDK-internal automatic (not consumer-configurable) ---
814
+ sdk_heartbeat: {
815
+ kind: "automatic",
816
+ metadataSchema: sdkHeartbeatMetadataSchema,
817
+ configSchema: sdkHeartbeatConfigSchema
818
+ },
716
819
  // --- manual triggers ---
717
820
  form_submit: {
718
821
  kind: "manual",
@@ -1055,7 +1158,7 @@ function GoogleAdsTracking({ gtagId }) {
1055
1158
  var import_navigation = require("next/navigation");
1056
1159
 
1057
1160
  // package.json
1058
- var version = "0.5.0";
1161
+ var version = "0.6.0";
1059
1162
 
1060
1163
  // src/factory.tsx
1061
1164
  var import_react3 = require("react");
@@ -1095,6 +1198,7 @@ function createTracking(options) {
1095
1198
  surface: "next",
1096
1199
  packageName: "@aranova/tracking-next",
1097
1200
  sdkVersion: version,
1201
+ triggers,
1098
1202
  debug
1099
1203
  }),
1100
1204
  triggers,
@@ -1108,6 +1212,7 @@ function createTracking(options) {
1108
1212
  endpoint,
1109
1213
  surface: "next",
1110
1214
  packageName: "@aranova/tracking-next",
1215
+ triggers,
1111
1216
  debug
1112
1217
  });
1113
1218
  fireManualPageView(rawClient);
@@ -1120,6 +1225,7 @@ function createTracking(options) {
1120
1225
  endpoint,
1121
1226
  surface: "next",
1122
1227
  packageName: "@aranova/tracking-next",
1228
+ triggers,
1123
1229
  debug
1124
1230
  });
1125
1231
  for (const { name, pathPattern } of specificPageVisitConfig.pages) {
@@ -1141,6 +1247,7 @@ function createTracking(options) {
1141
1247
  endpoint,
1142
1248
  surface: "next",
1143
1249
  packageName: "@aranova/tracking-next",
1250
+ triggers,
1144
1251
  debug
1145
1252
  });
1146
1253
  return attachBfcacheRestore(rawClient);
@@ -1152,6 +1259,7 @@ function createTracking(options) {
1152
1259
  endpoint,
1153
1260
  surface: "next",
1154
1261
  packageName: "@aranova/tracking-next",
1262
+ triggers,
1155
1263
  debug
1156
1264
  });
1157
1265
  return attachTimeOnSite(rawClient, timeOnSiteConfig);
@@ -1167,7 +1275,7 @@ function createTracking(options) {
1167
1275
  const MPS_FIRED_KEY = "aranova_tracking_mps_fired";
1168
1276
  try {
1169
1277
  const store = window.sessionStorage;
1170
- const currentSession = getOrRotateSessionId();
1278
+ const currentSession = getOrRotateSessionId().id;
1171
1279
  const storedSession = store.getItem(MPS_SESSION_KEY);
1172
1280
  if (storedSession !== currentSession) {
1173
1281
  store.setItem(MPS_SESSION_KEY, currentSession);
@@ -1186,6 +1294,7 @@ function createTracking(options) {
1186
1294
  endpoint,
1187
1295
  surface: "next",
1188
1296
  packageName: "@aranova/tracking-next",
1297
+ triggers,
1189
1298
  debug
1190
1299
  });
1191
1300
  rawClient.trackEvent({
@@ -1208,6 +1317,7 @@ function createTracking(options) {
1208
1317
  endpoint,
1209
1318
  surface: "next",
1210
1319
  packageName: "@aranova/tracking-next",
1320
+ triggers,
1211
1321
  debug
1212
1322
  });
1213
1323
  const scrollDepth = triggers.automatic.scroll_depth;