@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.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
|
-
|
|
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
|
-
|
|
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/
|
|
582
|
+
// ../tracking-core/src/events/cta-click.ts
|
|
511
583
|
import { z as z2 } from "zod";
|
|
512
|
-
var
|
|
584
|
+
var ctaClickMetadataSchema = z2.object({
|
|
585
|
+
cta_name: z2.string(),
|
|
513
586
|
page: z2.object({
|
|
514
587
|
path: z2.string()
|
|
515
|
-
})
|
|
516
|
-
|
|
517
|
-
|
|
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/
|
|
594
|
+
// ../tracking-core/src/events/sdk-heartbeat.ts
|
|
528
595
|
import { z as z3 } from "zod";
|
|
529
|
-
var
|
|
530
|
-
|
|
531
|
-
|
|
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
|
|
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/
|
|
609
|
+
// ../tracking-core/src/events/form-start.ts
|
|
541
610
|
import { z as z4 } from "zod";
|
|
542
|
-
var
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
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
|
|
620
|
+
var formStartConfigSchema = z4.object({
|
|
621
|
+
selector: z4.string().optional()
|
|
622
|
+
}).strict();
|
|
553
623
|
|
|
554
|
-
// ../tracking-core/src/events/
|
|
624
|
+
// ../tracking-core/src/events/form-submit.ts
|
|
555
625
|
import { z as z5 } from "zod";
|
|
556
|
-
var
|
|
557
|
-
|
|
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
|
|
563
|
-
|
|
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
|
-
|
|
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:
|
|
582
|
-
configSchema:
|
|
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.
|
|
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
|
|
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
|
|
1168
|
+
const firedPagesRef = useRef(/* @__PURE__ */ new Set());
|
|
847
1169
|
useEffect3(() => {
|
|
848
|
-
if (!
|
|
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
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
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() {
|