@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.d.mts +544 -100
- package/dist/index.d.ts +544 -100
- package/dist/index.js +453 -55
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +453 -55
- package/dist/index.mjs.map +1 -1
- package/dist/middleware.js +147 -37
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +147 -37
- package/dist/middleware.mjs.map +1 -1
- package/dist/server.js +147 -37
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +147 -37
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
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
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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 {
|
|
@@ -555,60 +627,144 @@ function createTrackingClient(config) {
|
|
|
555
627
|
};
|
|
556
628
|
}
|
|
557
629
|
|
|
558
|
-
// ../tracking-core/src/events/
|
|
630
|
+
// ../tracking-core/src/events/cta-click.ts
|
|
559
631
|
var import_zod2 = require("zod");
|
|
560
|
-
var
|
|
632
|
+
var ctaClickMetadataSchema = import_zod2.z.object({
|
|
633
|
+
cta_name: import_zod2.z.string(),
|
|
561
634
|
page: import_zod2.z.object({
|
|
562
635
|
path: import_zod2.z.string()
|
|
563
|
-
})
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
// RegExp is runtime-only so we wrap it via z.custom. Consumers pass a
|
|
567
|
-
// real regex at createTracking() time; the factory validates with this
|
|
568
|
-
// schema and then keeps the live RegExp reference for runtime matching.
|
|
569
|
-
pathPattern: import_zod2.z.custom(
|
|
570
|
-
(value) => value instanceof RegExp,
|
|
571
|
-
{ message: "pathPattern must be a RegExp" }
|
|
572
|
-
)
|
|
636
|
+
}),
|
|
637
|
+
section: import_zod2.z.string().nullable().optional(),
|
|
638
|
+
destination_url: import_zod2.z.string().nullable().optional()
|
|
573
639
|
}).strict();
|
|
640
|
+
var ctaClickConfigSchema = import_zod2.z.object({}).strict();
|
|
574
641
|
|
|
575
|
-
// ../tracking-core/src/events/
|
|
642
|
+
// ../tracking-core/src/events/sdk-heartbeat.ts
|
|
576
643
|
var import_zod3 = require("zod");
|
|
577
|
-
var
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
action: import_zod3.z.string().nullable()
|
|
581
|
-
}),
|
|
582
|
-
page: import_zod3.z.object({
|
|
583
|
-
path: import_zod3.z.string()
|
|
584
|
-
})
|
|
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())
|
|
585
647
|
}).strict();
|
|
586
|
-
var
|
|
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()
|
|
654
|
+
}).strict();
|
|
655
|
+
var sdkHeartbeatConfigSchema = import_zod3.z.object({}).strict();
|
|
587
656
|
|
|
588
|
-
// ../tracking-core/src/events/
|
|
657
|
+
// ../tracking-core/src/events/form-start.ts
|
|
589
658
|
var import_zod4 = require("zod");
|
|
590
|
-
var
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
href: import_zod4.z.string()
|
|
659
|
+
var formStartMetadataSchema = import_zod4.z.object({
|
|
660
|
+
form: import_zod4.z.object({
|
|
661
|
+
id: import_zod4.z.string(),
|
|
662
|
+
action: import_zod4.z.string().nullable()
|
|
595
663
|
}),
|
|
596
664
|
page: import_zod4.z.object({
|
|
597
665
|
path: import_zod4.z.string()
|
|
598
666
|
})
|
|
599
667
|
}).strict();
|
|
600
|
-
var
|
|
668
|
+
var formStartConfigSchema = import_zod4.z.object({
|
|
669
|
+
selector: import_zod4.z.string().optional()
|
|
670
|
+
}).strict();
|
|
601
671
|
|
|
602
|
-
// ../tracking-core/src/events/
|
|
672
|
+
// ../tracking-core/src/events/form-submit.ts
|
|
603
673
|
var import_zod5 = require("zod");
|
|
604
|
-
var
|
|
605
|
-
|
|
674
|
+
var formSubmitMetadataSchema = import_zod5.z.object({
|
|
675
|
+
form: import_zod5.z.object({
|
|
676
|
+
id: import_zod5.z.string(),
|
|
677
|
+
action: import_zod5.z.string().nullable(),
|
|
678
|
+
fields: import_zod5.z.array(
|
|
679
|
+
import_zod5.z.object({
|
|
680
|
+
name: import_zod5.z.string(),
|
|
681
|
+
type: import_zod5.z.string(),
|
|
682
|
+
label: import_zod5.z.string().nullable(),
|
|
683
|
+
has_value: import_zod5.z.boolean()
|
|
684
|
+
})
|
|
685
|
+
).optional()
|
|
686
|
+
}),
|
|
606
687
|
page: import_zod5.z.object({
|
|
607
688
|
path: import_zod5.z.string()
|
|
608
689
|
})
|
|
609
690
|
}).strict();
|
|
610
|
-
var
|
|
611
|
-
|
|
691
|
+
var formSubmitConfigSchema = import_zod5.z.object({}).strict();
|
|
692
|
+
|
|
693
|
+
// ../tracking-core/src/events/multi-page-session.ts
|
|
694
|
+
var import_zod6 = require("zod");
|
|
695
|
+
var multiPageSessionMetadataSchema = import_zod6.z.object({
|
|
696
|
+
page_count: import_zod6.z.number().int().min(2),
|
|
697
|
+
page: import_zod6.z.object({
|
|
698
|
+
path: import_zod6.z.string()
|
|
699
|
+
})
|
|
700
|
+
}).strict();
|
|
701
|
+
var multiPageSessionConfigSchema = import_zod6.z.object({
|
|
702
|
+
pageThreshold: import_zod6.z.number().int().min(2)
|
|
703
|
+
}).strict();
|
|
704
|
+
|
|
705
|
+
// ../tracking-core/src/events/phone-click.ts
|
|
706
|
+
var import_zod7 = require("zod");
|
|
707
|
+
var phoneClickMetadataSchema = import_zod7.z.object({
|
|
708
|
+
phone_number: import_zod7.z.string(),
|
|
709
|
+
page: import_zod7.z.object({
|
|
710
|
+
path: import_zod7.z.string()
|
|
711
|
+
}),
|
|
712
|
+
section: import_zod7.z.string().nullable().optional()
|
|
713
|
+
}).strict();
|
|
714
|
+
var phoneClickConfigSchema = import_zod7.z.object({}).strict();
|
|
715
|
+
|
|
716
|
+
// ../tracking-core/src/events/scroll-depth.ts
|
|
717
|
+
var import_zod8 = require("zod");
|
|
718
|
+
var scrollDepthMetadataSchema = import_zod8.z.object({
|
|
719
|
+
depth_percent: import_zod8.z.number().int().min(1).max(100),
|
|
720
|
+
page: import_zod8.z.object({
|
|
721
|
+
path: import_zod8.z.string()
|
|
722
|
+
})
|
|
723
|
+
}).strict();
|
|
724
|
+
var scrollDepthConfigSchema = import_zod8.z.object({
|
|
725
|
+
thresholds: import_zod8.z.array(import_zod8.z.number().int().min(1).max(100)).min(1)
|
|
726
|
+
}).strict();
|
|
727
|
+
|
|
728
|
+
// ../tracking-core/src/events/specific-page-visit.ts
|
|
729
|
+
var import_zod9 = require("zod");
|
|
730
|
+
var SPECIFIC_PAGE_NAMES = [
|
|
731
|
+
"contact_page",
|
|
732
|
+
"about_page",
|
|
733
|
+
"services_page",
|
|
734
|
+
"booking_page",
|
|
735
|
+
"location_page",
|
|
736
|
+
"pricing_page",
|
|
737
|
+
"faq_page",
|
|
738
|
+
"testimonials_page"
|
|
739
|
+
];
|
|
740
|
+
var specificPageNameSchema = import_zod9.z.enum(SPECIFIC_PAGE_NAMES);
|
|
741
|
+
var specificPageVisitMetadataSchema = import_zod9.z.object({
|
|
742
|
+
page_name: specificPageNameSchema,
|
|
743
|
+
page: import_zod9.z.object({
|
|
744
|
+
path: import_zod9.z.string()
|
|
745
|
+
})
|
|
746
|
+
}).strict();
|
|
747
|
+
var specificPageVisitConfigSchema = import_zod9.z.object({
|
|
748
|
+
pages: import_zod9.z.array(
|
|
749
|
+
import_zod9.z.object({
|
|
750
|
+
name: specificPageNameSchema,
|
|
751
|
+
pathPattern: import_zod9.z.custom((value) => value instanceof RegExp, {
|
|
752
|
+
message: "pathPattern must be a RegExp"
|
|
753
|
+
})
|
|
754
|
+
})
|
|
755
|
+
).min(1)
|
|
756
|
+
}).strict();
|
|
757
|
+
|
|
758
|
+
// ../tracking-core/src/events/time-on-site.ts
|
|
759
|
+
var import_zod10 = require("zod");
|
|
760
|
+
var timeOnSiteMetadataSchema = import_zod10.z.object({
|
|
761
|
+
duration_ms: import_zod10.z.number().int().nonnegative(),
|
|
762
|
+
page: import_zod10.z.object({
|
|
763
|
+
path: import_zod10.z.string()
|
|
764
|
+
})
|
|
765
|
+
}).strict();
|
|
766
|
+
var timeOnSiteConfigSchema = import_zod10.z.object({
|
|
767
|
+
thresholdSeconds: import_zod10.z.number().int().positive()
|
|
612
768
|
}).strict();
|
|
613
769
|
|
|
614
770
|
// ../tracking-core/src/events/registry.ts
|
|
@@ -624,10 +780,31 @@ var EVENT_REGISTRY = {
|
|
|
624
780
|
metadataSchema: timeOnSiteMetadataSchema,
|
|
625
781
|
configSchema: timeOnSiteConfigSchema
|
|
626
782
|
},
|
|
627
|
-
|
|
783
|
+
specific_page_visit: {
|
|
784
|
+
kind: "automatic",
|
|
785
|
+
metadataSchema: specificPageVisitMetadataSchema,
|
|
786
|
+
configSchema: specificPageVisitConfigSchema
|
|
787
|
+
},
|
|
788
|
+
scroll_depth: {
|
|
789
|
+
kind: "automatic",
|
|
790
|
+
metadataSchema: scrollDepthMetadataSchema,
|
|
791
|
+
configSchema: scrollDepthConfigSchema
|
|
792
|
+
},
|
|
793
|
+
multi_page_session: {
|
|
794
|
+
kind: "automatic",
|
|
795
|
+
metadataSchema: multiPageSessionMetadataSchema,
|
|
796
|
+
configSchema: multiPageSessionConfigSchema
|
|
797
|
+
},
|
|
798
|
+
form_start: {
|
|
799
|
+
kind: "automatic",
|
|
800
|
+
metadataSchema: formStartMetadataSchema,
|
|
801
|
+
configSchema: formStartConfigSchema
|
|
802
|
+
},
|
|
803
|
+
// --- SDK-internal automatic (not consumer-configurable) ---
|
|
804
|
+
sdk_heartbeat: {
|
|
628
805
|
kind: "automatic",
|
|
629
|
-
metadataSchema:
|
|
630
|
-
configSchema:
|
|
806
|
+
metadataSchema: sdkHeartbeatMetadataSchema,
|
|
807
|
+
configSchema: sdkHeartbeatConfigSchema
|
|
631
808
|
},
|
|
632
809
|
// --- manual triggers ---
|
|
633
810
|
form_submit: {
|
|
@@ -639,6 +816,11 @@ var EVENT_REGISTRY = {
|
|
|
639
816
|
kind: "manual",
|
|
640
817
|
metadataSchema: phoneClickMetadataSchema,
|
|
641
818
|
configSchema: phoneClickConfigSchema
|
|
819
|
+
},
|
|
820
|
+
cta_click: {
|
|
821
|
+
kind: "manual",
|
|
822
|
+
metadataSchema: ctaClickMetadataSchema,
|
|
823
|
+
configSchema: ctaClickConfigSchema
|
|
642
824
|
}
|
|
643
825
|
};
|
|
644
826
|
var ALL_AUTOMATIC_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.kind === "automatic").map(([name]) => name);
|
|
@@ -729,6 +911,144 @@ function attachTimeOnSite(client, config) {
|
|
|
729
911
|
};
|
|
730
912
|
}
|
|
731
913
|
|
|
914
|
+
// ../tracking-core/src/triggers/scroll-depth.ts
|
|
915
|
+
function attachScrollDepth(client, config) {
|
|
916
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
917
|
+
return () => {
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
const thresholds = new Set(config.thresholds);
|
|
921
|
+
let firedForPath = /* @__PURE__ */ new Set();
|
|
922
|
+
let currentPath = window.location.pathname;
|
|
923
|
+
let rafId = null;
|
|
924
|
+
function getScrollPercent() {
|
|
925
|
+
const doc = document.documentElement;
|
|
926
|
+
const scrollTop = window.scrollY || doc.scrollTop;
|
|
927
|
+
const scrollHeight = doc.scrollHeight;
|
|
928
|
+
const clientHeight = doc.clientHeight;
|
|
929
|
+
if (scrollHeight <= clientHeight) return 100;
|
|
930
|
+
return Math.round((scrollTop + clientHeight) / scrollHeight * 100);
|
|
931
|
+
}
|
|
932
|
+
function checkThresholds() {
|
|
933
|
+
const percent = getScrollPercent();
|
|
934
|
+
for (const threshold of thresholds) {
|
|
935
|
+
if (percent >= threshold && !firedForPath.has(threshold)) {
|
|
936
|
+
firedForPath.add(threshold);
|
|
937
|
+
client.trackEvent({
|
|
938
|
+
eventType: "scroll_depth",
|
|
939
|
+
metadata: {
|
|
940
|
+
depth_percent: threshold,
|
|
941
|
+
page: { path: currentPath }
|
|
942
|
+
},
|
|
943
|
+
pageUrl: window.location.href,
|
|
944
|
+
occurredAt: null
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
function onScroll() {
|
|
950
|
+
if (rafId !== null) return;
|
|
951
|
+
rafId = requestAnimationFrame(() => {
|
|
952
|
+
rafId = null;
|
|
953
|
+
checkThresholds();
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
function resetIfPathChanged() {
|
|
957
|
+
const newPath = window.location.pathname;
|
|
958
|
+
if (newPath === currentPath) return;
|
|
959
|
+
currentPath = newPath;
|
|
960
|
+
firedForPath = /* @__PURE__ */ new Set();
|
|
961
|
+
setTimeout(checkThresholds, 0);
|
|
962
|
+
}
|
|
963
|
+
const originalPushState = history.pushState.bind(history);
|
|
964
|
+
const originalReplaceState = history.replaceState.bind(history);
|
|
965
|
+
function patchedPushState(...args) {
|
|
966
|
+
originalPushState(...args);
|
|
967
|
+
setTimeout(resetIfPathChanged, 0);
|
|
968
|
+
}
|
|
969
|
+
function patchedReplaceState(...args) {
|
|
970
|
+
originalReplaceState(...args);
|
|
971
|
+
setTimeout(resetIfPathChanged, 0);
|
|
972
|
+
}
|
|
973
|
+
history.pushState = patchedPushState;
|
|
974
|
+
history.replaceState = patchedReplaceState;
|
|
975
|
+
window.addEventListener("popstate", resetIfPathChanged);
|
|
976
|
+
window.addEventListener("scroll", onScroll, { passive: true });
|
|
977
|
+
setTimeout(checkThresholds, 0);
|
|
978
|
+
return () => {
|
|
979
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
980
|
+
history.pushState = originalPushState;
|
|
981
|
+
history.replaceState = originalReplaceState;
|
|
982
|
+
window.removeEventListener("popstate", resetIfPathChanged);
|
|
983
|
+
window.removeEventListener("scroll", onScroll);
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// ../tracking-core/src/triggers/form-start.ts
|
|
988
|
+
function attachFormStart(client, config) {
|
|
989
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
990
|
+
return () => {
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
const selector = config.selector ?? "form";
|
|
994
|
+
let firedForms = /* @__PURE__ */ new Set();
|
|
995
|
+
let currentPath = window.location.pathname;
|
|
996
|
+
function getFormKey(form) {
|
|
997
|
+
if (form.id) return `id:${form.id}`;
|
|
998
|
+
const explicitAction = form.getAttribute("action");
|
|
999
|
+
if (explicitAction) return `action:${explicitAction}`;
|
|
1000
|
+
const forms = Array.from(document.querySelectorAll(selector));
|
|
1001
|
+
return `index:${forms.indexOf(form)}`;
|
|
1002
|
+
}
|
|
1003
|
+
function onFocusIn(event) {
|
|
1004
|
+
const target = event.target;
|
|
1005
|
+
if (!(target instanceof HTMLElement)) return;
|
|
1006
|
+
const form = target.closest(selector);
|
|
1007
|
+
if (!form || form.tagName !== "FORM") return;
|
|
1008
|
+
const key = getFormKey(form);
|
|
1009
|
+
if (firedForms.has(key)) return;
|
|
1010
|
+
firedForms.add(key);
|
|
1011
|
+
client.trackEvent({
|
|
1012
|
+
eventType: "form_start",
|
|
1013
|
+
metadata: {
|
|
1014
|
+
form: {
|
|
1015
|
+
id: form.id || "",
|
|
1016
|
+
action: form.getAttribute("action") ?? null
|
|
1017
|
+
},
|
|
1018
|
+
page: { path: window.location.pathname }
|
|
1019
|
+
},
|
|
1020
|
+
pageUrl: window.location.href,
|
|
1021
|
+
occurredAt: null
|
|
1022
|
+
});
|
|
1023
|
+
}
|
|
1024
|
+
function resetIfPathChanged() {
|
|
1025
|
+
const newPath = window.location.pathname;
|
|
1026
|
+
if (newPath === currentPath) return;
|
|
1027
|
+
currentPath = newPath;
|
|
1028
|
+
firedForms = /* @__PURE__ */ new Set();
|
|
1029
|
+
}
|
|
1030
|
+
const originalPushState = history.pushState.bind(history);
|
|
1031
|
+
const originalReplaceState = history.replaceState.bind(history);
|
|
1032
|
+
function patchedPushState(...args) {
|
|
1033
|
+
originalPushState(...args);
|
|
1034
|
+
setTimeout(resetIfPathChanged, 0);
|
|
1035
|
+
}
|
|
1036
|
+
function patchedReplaceState(...args) {
|
|
1037
|
+
originalReplaceState(...args);
|
|
1038
|
+
setTimeout(resetIfPathChanged, 0);
|
|
1039
|
+
}
|
|
1040
|
+
history.pushState = patchedPushState;
|
|
1041
|
+
history.replaceState = patchedReplaceState;
|
|
1042
|
+
window.addEventListener("popstate", resetIfPathChanged);
|
|
1043
|
+
document.addEventListener("focusin", onFocusIn);
|
|
1044
|
+
return () => {
|
|
1045
|
+
history.pushState = originalPushState;
|
|
1046
|
+
history.replaceState = originalReplaceState;
|
|
1047
|
+
window.removeEventListener("popstate", resetIfPathChanged);
|
|
1048
|
+
document.removeEventListener("focusin", onFocusIn);
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
|
|
732
1052
|
// src/ConsentBanner.tsx
|
|
733
1053
|
var import_react = require("react");
|
|
734
1054
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -828,7 +1148,7 @@ function GoogleAdsTracking({ gtagId }) {
|
|
|
828
1148
|
var import_navigation = require("next/navigation");
|
|
829
1149
|
|
|
830
1150
|
// package.json
|
|
831
|
-
var version = "0.
|
|
1151
|
+
var version = "0.5.1";
|
|
832
1152
|
|
|
833
1153
|
// src/factory.tsx
|
|
834
1154
|
var import_react3 = require("react");
|
|
@@ -855,7 +1175,7 @@ function createTracking(options) {
|
|
|
855
1175
|
};
|
|
856
1176
|
}
|
|
857
1177
|
const TrackingContext = (0, import_react3.createContext)(null);
|
|
858
|
-
const
|
|
1178
|
+
const specificPageVisitConfig = triggers.automatic.specific_page_visit ?? null;
|
|
859
1179
|
const timeOnSiteConfig = triggers.automatic.time_on_site ?? null;
|
|
860
1180
|
function TrackingProvider({ children }) {
|
|
861
1181
|
const pathname = (0, import_navigation.usePathname)();
|
|
@@ -868,6 +1188,7 @@ function createTracking(options) {
|
|
|
868
1188
|
surface: "next",
|
|
869
1189
|
packageName: "@aranova/tracking-next",
|
|
870
1190
|
sdkVersion: version,
|
|
1191
|
+
triggers,
|
|
871
1192
|
debug
|
|
872
1193
|
}),
|
|
873
1194
|
triggers,
|
|
@@ -881,29 +1202,34 @@ function createTracking(options) {
|
|
|
881
1202
|
endpoint,
|
|
882
1203
|
surface: "next",
|
|
883
1204
|
packageName: "@aranova/tracking-next",
|
|
1205
|
+
triggers,
|
|
884
1206
|
debug
|
|
885
1207
|
});
|
|
886
1208
|
fireManualPageView(rawClient);
|
|
887
1209
|
}, [pathname, searchParams]);
|
|
888
|
-
const
|
|
1210
|
+
const firedPagesRef = (0, import_react3.useRef)(/* @__PURE__ */ new Set());
|
|
889
1211
|
(0, import_react3.useEffect)(() => {
|
|
890
|
-
if (!
|
|
891
|
-
if (!contactPageVisitConfig.pathPattern.test(pathname)) return;
|
|
892
|
-
if (lastContactPathRef.current === pathname) return;
|
|
893
|
-
lastContactPathRef.current = pathname;
|
|
1212
|
+
if (!specificPageVisitConfig || pathname === null) return;
|
|
894
1213
|
const rawClient = getOrCreateTrackingClient({
|
|
895
1214
|
apiKey,
|
|
896
1215
|
endpoint,
|
|
897
1216
|
surface: "next",
|
|
898
1217
|
packageName: "@aranova/tracking-next",
|
|
1218
|
+
triggers,
|
|
899
1219
|
debug
|
|
900
1220
|
});
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
1221
|
+
for (const { name, pathPattern } of specificPageVisitConfig.pages) {
|
|
1222
|
+
if (!pathPattern.test(pathname)) continue;
|
|
1223
|
+
const key = `${name}:${pathname}`;
|
|
1224
|
+
if (firedPagesRef.current.has(key)) continue;
|
|
1225
|
+
firedPagesRef.current.add(key);
|
|
1226
|
+
rawClient.trackEvent({
|
|
1227
|
+
eventType: "specific_page_visit",
|
|
1228
|
+
metadata: { page_name: name, page: { path: pathname } },
|
|
1229
|
+
pageUrl: null,
|
|
1230
|
+
occurredAt: null
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
907
1233
|
}, [pathname]);
|
|
908
1234
|
(0, import_react3.useEffect)(() => {
|
|
909
1235
|
const rawClient = getOrCreateTrackingClient({
|
|
@@ -911,6 +1237,7 @@ function createTracking(options) {
|
|
|
911
1237
|
endpoint,
|
|
912
1238
|
surface: "next",
|
|
913
1239
|
packageName: "@aranova/tracking-next",
|
|
1240
|
+
triggers,
|
|
914
1241
|
debug
|
|
915
1242
|
});
|
|
916
1243
|
return attachBfcacheRestore(rawClient);
|
|
@@ -922,10 +1249,81 @@ function createTracking(options) {
|
|
|
922
1249
|
endpoint,
|
|
923
1250
|
surface: "next",
|
|
924
1251
|
packageName: "@aranova/tracking-next",
|
|
1252
|
+
triggers,
|
|
925
1253
|
debug
|
|
926
1254
|
});
|
|
927
1255
|
return attachTimeOnSite(rawClient, timeOnSiteConfig);
|
|
928
1256
|
}, []);
|
|
1257
|
+
const multiPageSessionConfig = triggers.automatic.multi_page_session ?? null;
|
|
1258
|
+
const mpsLastPathRef = (0, import_react3.useRef)(null);
|
|
1259
|
+
(0, import_react3.useEffect)(() => {
|
|
1260
|
+
if (!multiPageSessionConfig || pathname === null) return;
|
|
1261
|
+
if (pathname === mpsLastPathRef.current) return;
|
|
1262
|
+
mpsLastPathRef.current = pathname;
|
|
1263
|
+
const MPS_PATHS_KEY = "aranova_tracking_mps_paths";
|
|
1264
|
+
const MPS_SESSION_KEY = "aranova_tracking_mps_session";
|
|
1265
|
+
const MPS_FIRED_KEY = "aranova_tracking_mps_fired";
|
|
1266
|
+
try {
|
|
1267
|
+
const store = window.sessionStorage;
|
|
1268
|
+
const currentSession = getOrRotateSessionId().id;
|
|
1269
|
+
const storedSession = store.getItem(MPS_SESSION_KEY);
|
|
1270
|
+
if (storedSession !== currentSession) {
|
|
1271
|
+
store.setItem(MPS_SESSION_KEY, currentSession);
|
|
1272
|
+
store.removeItem(MPS_PATHS_KEY);
|
|
1273
|
+
store.removeItem(MPS_FIRED_KEY);
|
|
1274
|
+
}
|
|
1275
|
+
if (store.getItem(MPS_FIRED_KEY) === "1") return;
|
|
1276
|
+
const raw = store.getItem(MPS_PATHS_KEY);
|
|
1277
|
+
const paths = raw ? new Set(JSON.parse(raw)) : /* @__PURE__ */ new Set();
|
|
1278
|
+
paths.add(pathname);
|
|
1279
|
+
store.setItem(MPS_PATHS_KEY, JSON.stringify([...paths]));
|
|
1280
|
+
if (paths.size >= multiPageSessionConfig.pageThreshold) {
|
|
1281
|
+
store.setItem(MPS_FIRED_KEY, "1");
|
|
1282
|
+
const rawClient = getOrCreateTrackingClient({
|
|
1283
|
+
apiKey,
|
|
1284
|
+
endpoint,
|
|
1285
|
+
surface: "next",
|
|
1286
|
+
packageName: "@aranova/tracking-next",
|
|
1287
|
+
triggers,
|
|
1288
|
+
debug
|
|
1289
|
+
});
|
|
1290
|
+
rawClient.trackEvent({
|
|
1291
|
+
eventType: "multi_page_session",
|
|
1292
|
+
metadata: {
|
|
1293
|
+
page_count: paths.size,
|
|
1294
|
+
page: { path: pathname }
|
|
1295
|
+
},
|
|
1296
|
+
pageUrl: null,
|
|
1297
|
+
occurredAt: null
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
} catch {
|
|
1301
|
+
}
|
|
1302
|
+
}, [pathname]);
|
|
1303
|
+
(0, import_react3.useEffect)(() => {
|
|
1304
|
+
const detachers = [];
|
|
1305
|
+
const rawClient = getOrCreateTrackingClient({
|
|
1306
|
+
apiKey,
|
|
1307
|
+
endpoint,
|
|
1308
|
+
surface: "next",
|
|
1309
|
+
packageName: "@aranova/tracking-next",
|
|
1310
|
+
triggers,
|
|
1311
|
+
debug
|
|
1312
|
+
});
|
|
1313
|
+
const scrollDepth = triggers.automatic.scroll_depth;
|
|
1314
|
+
if (scrollDepth) {
|
|
1315
|
+
detachers.push(attachScrollDepth(rawClient, scrollDepth));
|
|
1316
|
+
}
|
|
1317
|
+
const formStart = triggers.automatic.form_start;
|
|
1318
|
+
if (formStart) {
|
|
1319
|
+
detachers.push(attachFormStart(rawClient, formStart));
|
|
1320
|
+
}
|
|
1321
|
+
return () => {
|
|
1322
|
+
for (let i = detachers.length - 1; i >= 0; i--) {
|
|
1323
|
+
detachers[i]();
|
|
1324
|
+
}
|
|
1325
|
+
};
|
|
1326
|
+
}, []);
|
|
929
1327
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TrackingContext.Provider, { value: client, children });
|
|
930
1328
|
}
|
|
931
1329
|
function useTracking() {
|