@aranova/tracking-next 0.5.0 → 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 {
@@ -519,79 +591,94 @@ var ctaClickMetadataSchema = z2.object({
519
591
  }).strict();
520
592
  var ctaClickConfigSchema = z2.object({}).strict();
521
593
 
522
- // ../tracking-core/src/events/form-start.ts
594
+ // ../tracking-core/src/events/sdk-heartbeat.ts
523
595
  import { z as z3 } from "zod";
524
- var formStartMetadataSchema = z3.object({
525
- form: z3.object({
526
- id: z3.string(),
527
- action: z3.string().nullable()
528
- }),
529
- page: z3.object({
530
- path: z3.string()
531
- })
596
+ var sdkHeartbeatTriggersSchema = z3.object({
597
+ automatic: z3.array(z3.string()),
598
+ manual: z3.array(z3.string())
532
599
  }).strict();
533
- var formStartConfigSchema = z3.object({
534
- selector: z3.string().optional()
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()
535
606
  }).strict();
607
+ var sdkHeartbeatConfigSchema = z3.object({}).strict();
536
608
 
537
- // ../tracking-core/src/events/form-submit.ts
609
+ // ../tracking-core/src/events/form-start.ts
538
610
  import { z as z4 } from "zod";
539
- var formSubmitMetadataSchema = z4.object({
611
+ var formStartMetadataSchema = z4.object({
540
612
  form: z4.object({
541
613
  id: z4.string(),
542
- action: z4.string().nullable(),
543
- fields: z4.array(
544
- z4.object({
545
- name: z4.string(),
546
- type: z4.string(),
547
- label: z4.string().nullable(),
548
- has_value: z4.boolean()
549
- })
550
- ).optional()
614
+ action: z4.string().nullable()
551
615
  }),
552
616
  page: z4.object({
553
617
  path: z4.string()
554
618
  })
555
619
  }).strict();
556
- var formSubmitConfigSchema = z4.object({}).strict();
620
+ var formStartConfigSchema = z4.object({
621
+ selector: z4.string().optional()
622
+ }).strict();
557
623
 
558
- // ../tracking-core/src/events/multi-page-session.ts
624
+ // ../tracking-core/src/events/form-submit.ts
559
625
  import { z as z5 } from "zod";
560
- var multiPageSessionMetadataSchema = z5.object({
561
- page_count: z5.number().int().min(2),
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
+ }),
562
639
  page: z5.object({
563
640
  path: z5.string()
564
641
  })
565
642
  }).strict();
566
- var multiPageSessionConfigSchema = z5.object({
567
- pageThreshold: z5.number().int().min(2)
568
- }).strict();
643
+ var formSubmitConfigSchema = z5.object({}).strict();
569
644
 
570
- // ../tracking-core/src/events/phone-click.ts
645
+ // ../tracking-core/src/events/multi-page-session.ts
571
646
  import { z as z6 } from "zod";
572
- var phoneClickMetadataSchema = z6.object({
573
- phone_number: z6.string(),
647
+ var multiPageSessionMetadataSchema = z6.object({
648
+ page_count: z6.number().int().min(2),
574
649
  page: z6.object({
575
650
  path: z6.string()
576
- }),
577
- section: z6.string().nullable().optional()
651
+ })
652
+ }).strict();
653
+ var multiPageSessionConfigSchema = z6.object({
654
+ pageThreshold: z6.number().int().min(2)
578
655
  }).strict();
579
- var phoneClickConfigSchema = z6.object({}).strict();
580
656
 
581
- // ../tracking-core/src/events/scroll-depth.ts
657
+ // ../tracking-core/src/events/phone-click.ts
582
658
  import { z as z7 } from "zod";
583
- var scrollDepthMetadataSchema = z7.object({
584
- depth_percent: z7.number().int().min(1).max(100),
659
+ var phoneClickMetadataSchema = z7.object({
660
+ phone_number: z7.string(),
585
661
  page: z7.object({
586
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()
587
674
  })
588
675
  }).strict();
589
- var scrollDepthConfigSchema = z7.object({
590
- thresholds: z7.array(z7.number().int().min(1).max(100)).min(1)
676
+ var scrollDepthConfigSchema = z8.object({
677
+ thresholds: z8.array(z8.number().int().min(1).max(100)).min(1)
591
678
  }).strict();
592
679
 
593
680
  // ../tracking-core/src/events/specific-page-visit.ts
594
- import { z as z8 } from "zod";
681
+ import { z as z9 } from "zod";
595
682
  var SPECIFIC_PAGE_NAMES = [
596
683
  "contact_page",
597
684
  "about_page",
@@ -602,18 +689,18 @@ var SPECIFIC_PAGE_NAMES = [
602
689
  "faq_page",
603
690
  "testimonials_page"
604
691
  ];
605
- var specificPageNameSchema = z8.enum(SPECIFIC_PAGE_NAMES);
606
- var specificPageVisitMetadataSchema = z8.object({
692
+ var specificPageNameSchema = z9.enum(SPECIFIC_PAGE_NAMES);
693
+ var specificPageVisitMetadataSchema = z9.object({
607
694
  page_name: specificPageNameSchema,
608
- page: z8.object({
609
- path: z8.string()
695
+ page: z9.object({
696
+ path: z9.string()
610
697
  })
611
698
  }).strict();
612
- var specificPageVisitConfigSchema = z8.object({
613
- pages: z8.array(
614
- z8.object({
699
+ var specificPageVisitConfigSchema = z9.object({
700
+ pages: z9.array(
701
+ z9.object({
615
702
  name: specificPageNameSchema,
616
- pathPattern: z8.custom((value) => value instanceof RegExp, {
703
+ pathPattern: z9.custom((value) => value instanceof RegExp, {
617
704
  message: "pathPattern must be a RegExp"
618
705
  })
619
706
  })
@@ -621,15 +708,15 @@ var specificPageVisitConfigSchema = z8.object({
621
708
  }).strict();
622
709
 
623
710
  // ../tracking-core/src/events/time-on-site.ts
624
- import { z as z9 } from "zod";
625
- var timeOnSiteMetadataSchema = z9.object({
626
- duration_ms: z9.number().int().nonnegative(),
627
- page: z9.object({
628
- path: z9.string()
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()
629
716
  })
630
717
  }).strict();
631
- var timeOnSiteConfigSchema = z9.object({
632
- thresholdSeconds: z9.number().int().positive()
718
+ var timeOnSiteConfigSchema = z10.object({
719
+ thresholdSeconds: z10.number().int().positive()
633
720
  }).strict();
634
721
 
635
722
  // ../tracking-core/src/events/registry.ts
@@ -665,6 +752,12 @@ var EVENT_REGISTRY = {
665
752
  metadataSchema: formStartMetadataSchema,
666
753
  configSchema: formStartConfigSchema
667
754
  },
755
+ // --- SDK-internal automatic (not consumer-configurable) ---
756
+ sdk_heartbeat: {
757
+ kind: "automatic",
758
+ metadataSchema: sdkHeartbeatMetadataSchema,
759
+ configSchema: sdkHeartbeatConfigSchema
760
+ },
668
761
  // --- manual triggers ---
669
762
  form_submit: {
670
763
  kind: "manual",
@@ -1007,7 +1100,7 @@ function GoogleAdsTracking({ gtagId }) {
1007
1100
  import { usePathname, useSearchParams } from "next/navigation";
1008
1101
 
1009
1102
  // package.json
1010
- var version = "0.5.0";
1103
+ var version = "0.5.1";
1011
1104
 
1012
1105
  // src/factory.tsx
1013
1106
  import {
@@ -1053,6 +1146,7 @@ function createTracking(options) {
1053
1146
  surface: "next",
1054
1147
  packageName: "@aranova/tracking-next",
1055
1148
  sdkVersion: version,
1149
+ triggers,
1056
1150
  debug
1057
1151
  }),
1058
1152
  triggers,
@@ -1066,6 +1160,7 @@ function createTracking(options) {
1066
1160
  endpoint,
1067
1161
  surface: "next",
1068
1162
  packageName: "@aranova/tracking-next",
1163
+ triggers,
1069
1164
  debug
1070
1165
  });
1071
1166
  fireManualPageView(rawClient);
@@ -1078,6 +1173,7 @@ function createTracking(options) {
1078
1173
  endpoint,
1079
1174
  surface: "next",
1080
1175
  packageName: "@aranova/tracking-next",
1176
+ triggers,
1081
1177
  debug
1082
1178
  });
1083
1179
  for (const { name, pathPattern } of specificPageVisitConfig.pages) {
@@ -1099,6 +1195,7 @@ function createTracking(options) {
1099
1195
  endpoint,
1100
1196
  surface: "next",
1101
1197
  packageName: "@aranova/tracking-next",
1198
+ triggers,
1102
1199
  debug
1103
1200
  });
1104
1201
  return attachBfcacheRestore(rawClient);
@@ -1110,6 +1207,7 @@ function createTracking(options) {
1110
1207
  endpoint,
1111
1208
  surface: "next",
1112
1209
  packageName: "@aranova/tracking-next",
1210
+ triggers,
1113
1211
  debug
1114
1212
  });
1115
1213
  return attachTimeOnSite(rawClient, timeOnSiteConfig);
@@ -1125,7 +1223,7 @@ function createTracking(options) {
1125
1223
  const MPS_FIRED_KEY = "aranova_tracking_mps_fired";
1126
1224
  try {
1127
1225
  const store = window.sessionStorage;
1128
- const currentSession = getOrRotateSessionId();
1226
+ const currentSession = getOrRotateSessionId().id;
1129
1227
  const storedSession = store.getItem(MPS_SESSION_KEY);
1130
1228
  if (storedSession !== currentSession) {
1131
1229
  store.setItem(MPS_SESSION_KEY, currentSession);
@@ -1144,6 +1242,7 @@ function createTracking(options) {
1144
1242
  endpoint,
1145
1243
  surface: "next",
1146
1244
  packageName: "@aranova/tracking-next",
1245
+ triggers,
1147
1246
  debug
1148
1247
  });
1149
1248
  rawClient.trackEvent({
@@ -1166,6 +1265,7 @@ function createTracking(options) {
1166
1265
  endpoint,
1167
1266
  surface: "next",
1168
1267
  packageName: "@aranova/tracking-next",
1268
+ triggers,
1169
1269
  debug
1170
1270
  });
1171
1271
  const scrollDepth = triggers.automatic.scroll_depth;