@dataxamas/tracker-js 2.7.0 → 2.8.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/CHANGELOG.md +7 -0
- package/dist/index.cjs +22 -20
- package/dist/index.d.cts +8 -5
- package/dist/index.d.ts +8 -5
- package/dist/index.js +22 -20
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## 2.8.0
|
|
2
|
+
|
|
3
|
+
- Session replay records at most 30 seconds per visit, counted from the visitor's first gesture instead of page
|
|
4
|
+
load. After the cap the visit is not recorded again; a new recording only starts after 10 minutes without
|
|
5
|
+
interaction.
|
|
6
|
+
- The 1-minute idle pause is gone: the 30-second cap already ends the recording first.
|
|
7
|
+
|
|
1
8
|
## 2.7.0
|
|
2
9
|
|
|
3
10
|
- Web Vitals also collect FCP (First Contentful Paint) and TTFB (Time to First Byte), sent in the same batch as
|
package/dist/index.cjs
CHANGED
|
@@ -315,11 +315,10 @@ var DataxamasLogs = class {
|
|
|
315
315
|
};
|
|
316
316
|
|
|
317
317
|
// ../tracker-shared/src/constants.ts
|
|
318
|
-
var MAX_RECORDING_MS =
|
|
318
|
+
var MAX_RECORDING_MS = 30 * 1e3;
|
|
319
319
|
var MAX_EVENTS_PER_RECORDING = 15e3;
|
|
320
320
|
var MAX_BYTES_PER_RECORDING = 5 * 1024 * 1024;
|
|
321
321
|
var REPLAY_IDLE_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
322
|
-
var REPLAY_IDLE_SUSPEND_MS = 60 * 1e3;
|
|
323
322
|
|
|
324
323
|
// src/tracking.ts
|
|
325
324
|
var QUEUE_DELAY_MS = 4e3;
|
|
@@ -339,19 +338,19 @@ var DataxamasTracking = class {
|
|
|
339
338
|
constructor(options) {
|
|
340
339
|
/**
|
|
341
340
|
* Primeiro gesto liga o gravador; os seguintes só o religam se ele tiver parado (aba que foi
|
|
342
|
-
* para segundo plano, reload), no mesmo `recordingId`. Depois do teto
|
|
343
|
-
*
|
|
341
|
+
* para segundo plano, reload), no mesmo `recordingId`. Depois do teto a visita não grava mais;
|
|
342
|
+
* só um gesto depois de muito tempo parado abre uma gravação nova.
|
|
344
343
|
*/
|
|
345
344
|
this.markReplayActivity = () => {
|
|
346
345
|
if (this.replayHalted || this.cutoffPending) return;
|
|
347
346
|
if (document.visibilityState === "hidden") return;
|
|
348
347
|
const now = Date.now();
|
|
349
|
-
if (
|
|
348
|
+
if (now - this.lastActivityAt >= REPLAY_IDLE_TIMEOUT_MS) {
|
|
350
349
|
if (this.isRecording()) this.stopReplayRecorder(false);
|
|
351
350
|
this.rotateRecording();
|
|
352
351
|
}
|
|
353
352
|
this.touchActivity(now);
|
|
354
|
-
if (this.isRecording()) return;
|
|
353
|
+
if (this.replayCapped || this.isRecording()) return;
|
|
355
354
|
this.startReplayRecorder();
|
|
356
355
|
};
|
|
357
356
|
if (!options.apiKey) {
|
|
@@ -634,14 +633,17 @@ var DataxamasTracking = class {
|
|
|
634
633
|
this.lastActivityAt = Date.now();
|
|
635
634
|
this.saveRecording();
|
|
636
635
|
}
|
|
637
|
-
/**
|
|
636
|
+
/**
|
|
637
|
+
* Reload ou navegação completa na mesma aba continua a gravação, se a visita ainda estiver ativa.
|
|
638
|
+
* Se ela já bateu o teto, segue sem gravar.
|
|
639
|
+
*/
|
|
638
640
|
resumeOrRotateRecording() {
|
|
639
641
|
const stored = this.loadRecording();
|
|
640
|
-
if (!stored ||
|
|
642
|
+
if (!stored || Date.now() - stored.lastActivityAt >= REPLAY_IDLE_TIMEOUT_MS) {
|
|
641
643
|
this.rotateRecording();
|
|
642
644
|
return;
|
|
643
645
|
}
|
|
644
|
-
this.replayCapped =
|
|
646
|
+
this.replayCapped = stored.capped;
|
|
645
647
|
this.recordingId = stored.id;
|
|
646
648
|
this.recordingStartedAt = stored.startedAt;
|
|
647
649
|
this.recordingStartedAtMs = stored.startedAtMs;
|
|
@@ -727,8 +729,8 @@ var DataxamasTracking = class {
|
|
|
727
729
|
}
|
|
728
730
|
}
|
|
729
731
|
/**
|
|
730
|
-
* Bateu o teto: encerra a gravação e
|
|
731
|
-
*
|
|
732
|
+
* Bateu o teto: encerra a gravação e a visita não grava mais, em vez de emendar um clipe atrás do
|
|
733
|
+
* outro.
|
|
732
734
|
*/
|
|
733
735
|
scheduleReplayCutoff() {
|
|
734
736
|
if (this.cutoffPending) return;
|
|
@@ -751,11 +753,7 @@ var DataxamasTracking = class {
|
|
|
751
753
|
}, REPLAY_FLUSH_INTERVAL_MS);
|
|
752
754
|
setInterval(() => {
|
|
753
755
|
if (!this.isRecording()) return;
|
|
754
|
-
if (this.exceededReplayCaps())
|
|
755
|
-
this.scheduleReplayCutoff();
|
|
756
|
-
return;
|
|
757
|
-
}
|
|
758
|
-
if (Date.now() - this.lastActivityAt >= REPLAY_IDLE_SUSPEND_MS) this.stopReplayRecorder(false);
|
|
756
|
+
if (this.exceededReplayCaps()) this.scheduleReplayCutoff();
|
|
759
757
|
}, CAP_CHECK_MS);
|
|
760
758
|
window.addEventListener("pagehide", () => this.stopReplayRecorder(true));
|
|
761
759
|
document.addEventListener("visibilitychange", () => {
|
|
@@ -777,9 +775,17 @@ var DataxamasTracking = class {
|
|
|
777
775
|
}
|
|
778
776
|
if (this.isRecording() || this.replayHalted) return;
|
|
779
777
|
if (!this.recordingId) this.rotateRecording();
|
|
778
|
+
if (this.recordingSeq === 0) {
|
|
779
|
+
this.recordingStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
780
|
+
this.recordingStartedAtMs = Date.now();
|
|
781
|
+
}
|
|
780
782
|
this.snapshotFlushed = false;
|
|
781
783
|
this.stopRrweb = this.rrwebRecord({
|
|
782
784
|
emit: (event) => {
|
|
785
|
+
if (this.exceededReplayCaps()) {
|
|
786
|
+
this.scheduleReplayCutoff();
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
783
789
|
this.replayBuffer.push(event);
|
|
784
790
|
this.recordingEvents++;
|
|
785
791
|
if (!this.snapshotFlushed && event.type === 2) {
|
|
@@ -787,10 +793,6 @@ var DataxamasTracking = class {
|
|
|
787
793
|
this.flushReplay(false);
|
|
788
794
|
return;
|
|
789
795
|
}
|
|
790
|
-
if (this.exceededReplayCaps()) {
|
|
791
|
-
this.scheduleReplayCutoff();
|
|
792
|
-
return;
|
|
793
|
-
}
|
|
794
796
|
if (this.replayBuffer.length >= REPLAY_FLUSH_SIZE) this.flushReplay(false);
|
|
795
797
|
},
|
|
796
798
|
maskAllInputs: true,
|
package/dist/index.d.cts
CHANGED
|
@@ -158,7 +158,10 @@ declare class DataxamasTracking {
|
|
|
158
158
|
private loadRecording;
|
|
159
159
|
private saveRecording;
|
|
160
160
|
private rotateRecording;
|
|
161
|
-
/**
|
|
161
|
+
/**
|
|
162
|
+
* Reload ou navegação completa na mesma aba continua a gravação, se a visita ainda estiver ativa.
|
|
163
|
+
* Se ela já bateu o teto, segue sem gravar.
|
|
164
|
+
*/
|
|
162
165
|
private resumeOrRotateRecording;
|
|
163
166
|
private touchActivity;
|
|
164
167
|
private flushReplay;
|
|
@@ -170,14 +173,14 @@ declare class DataxamasTracking {
|
|
|
170
173
|
private sendReplayBatch;
|
|
171
174
|
private stopReplayRecorder;
|
|
172
175
|
/**
|
|
173
|
-
* Bateu o teto: encerra a gravação e
|
|
174
|
-
*
|
|
176
|
+
* Bateu o teto: encerra a gravação e a visita não grava mais, em vez de emendar um clipe atrás do
|
|
177
|
+
* outro.
|
|
175
178
|
*/
|
|
176
179
|
private scheduleReplayCutoff;
|
|
177
180
|
/**
|
|
178
181
|
* Primeiro gesto liga o gravador; os seguintes só o religam se ele tiver parado (aba que foi
|
|
179
|
-
* para segundo plano, reload), no mesmo `recordingId`. Depois do teto
|
|
180
|
-
*
|
|
182
|
+
* para segundo plano, reload), no mesmo `recordingId`. Depois do teto a visita não grava mais;
|
|
183
|
+
* só um gesto depois de muito tempo parado abre uma gravação nova.
|
|
181
184
|
*/
|
|
182
185
|
private markReplayActivity;
|
|
183
186
|
private setupReplayLifecycle;
|
package/dist/index.d.ts
CHANGED
|
@@ -158,7 +158,10 @@ declare class DataxamasTracking {
|
|
|
158
158
|
private loadRecording;
|
|
159
159
|
private saveRecording;
|
|
160
160
|
private rotateRecording;
|
|
161
|
-
/**
|
|
161
|
+
/**
|
|
162
|
+
* Reload ou navegação completa na mesma aba continua a gravação, se a visita ainda estiver ativa.
|
|
163
|
+
* Se ela já bateu o teto, segue sem gravar.
|
|
164
|
+
*/
|
|
162
165
|
private resumeOrRotateRecording;
|
|
163
166
|
private touchActivity;
|
|
164
167
|
private flushReplay;
|
|
@@ -170,14 +173,14 @@ declare class DataxamasTracking {
|
|
|
170
173
|
private sendReplayBatch;
|
|
171
174
|
private stopReplayRecorder;
|
|
172
175
|
/**
|
|
173
|
-
* Bateu o teto: encerra a gravação e
|
|
174
|
-
*
|
|
176
|
+
* Bateu o teto: encerra a gravação e a visita não grava mais, em vez de emendar um clipe atrás do
|
|
177
|
+
* outro.
|
|
175
178
|
*/
|
|
176
179
|
private scheduleReplayCutoff;
|
|
177
180
|
/**
|
|
178
181
|
* Primeiro gesto liga o gravador; os seguintes só o religam se ele tiver parado (aba que foi
|
|
179
|
-
* para segundo plano, reload), no mesmo `recordingId`. Depois do teto
|
|
180
|
-
*
|
|
182
|
+
* para segundo plano, reload), no mesmo `recordingId`. Depois do teto a visita não grava mais;
|
|
183
|
+
* só um gesto depois de muito tempo parado abre uma gravação nova.
|
|
181
184
|
*/
|
|
182
185
|
private markReplayActivity;
|
|
183
186
|
private setupReplayLifecycle;
|
package/dist/index.js
CHANGED
|
@@ -315,11 +315,10 @@ var DataxamasLogs = class {
|
|
|
315
315
|
};
|
|
316
316
|
|
|
317
317
|
// ../tracker-shared/src/constants.ts
|
|
318
|
-
var MAX_RECORDING_MS =
|
|
318
|
+
var MAX_RECORDING_MS = 30 * 1e3;
|
|
319
319
|
var MAX_EVENTS_PER_RECORDING = 15e3;
|
|
320
320
|
var MAX_BYTES_PER_RECORDING = 5 * 1024 * 1024;
|
|
321
321
|
var REPLAY_IDLE_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
322
|
-
var REPLAY_IDLE_SUSPEND_MS = 60 * 1e3;
|
|
323
322
|
|
|
324
323
|
// src/tracking.ts
|
|
325
324
|
var QUEUE_DELAY_MS = 4e3;
|
|
@@ -339,19 +338,19 @@ var DataxamasTracking = class {
|
|
|
339
338
|
constructor(options) {
|
|
340
339
|
/**
|
|
341
340
|
* Primeiro gesto liga o gravador; os seguintes só o religam se ele tiver parado (aba que foi
|
|
342
|
-
* para segundo plano, reload), no mesmo `recordingId`. Depois do teto
|
|
343
|
-
*
|
|
341
|
+
* para segundo plano, reload), no mesmo `recordingId`. Depois do teto a visita não grava mais;
|
|
342
|
+
* só um gesto depois de muito tempo parado abre uma gravação nova.
|
|
344
343
|
*/
|
|
345
344
|
this.markReplayActivity = () => {
|
|
346
345
|
if (this.replayHalted || this.cutoffPending) return;
|
|
347
346
|
if (document.visibilityState === "hidden") return;
|
|
348
347
|
const now = Date.now();
|
|
349
|
-
if (
|
|
348
|
+
if (now - this.lastActivityAt >= REPLAY_IDLE_TIMEOUT_MS) {
|
|
350
349
|
if (this.isRecording()) this.stopReplayRecorder(false);
|
|
351
350
|
this.rotateRecording();
|
|
352
351
|
}
|
|
353
352
|
this.touchActivity(now);
|
|
354
|
-
if (this.isRecording()) return;
|
|
353
|
+
if (this.replayCapped || this.isRecording()) return;
|
|
355
354
|
this.startReplayRecorder();
|
|
356
355
|
};
|
|
357
356
|
if (!options.apiKey) {
|
|
@@ -634,14 +633,17 @@ var DataxamasTracking = class {
|
|
|
634
633
|
this.lastActivityAt = Date.now();
|
|
635
634
|
this.saveRecording();
|
|
636
635
|
}
|
|
637
|
-
/**
|
|
636
|
+
/**
|
|
637
|
+
* Reload ou navegação completa na mesma aba continua a gravação, se a visita ainda estiver ativa.
|
|
638
|
+
* Se ela já bateu o teto, segue sem gravar.
|
|
639
|
+
*/
|
|
638
640
|
resumeOrRotateRecording() {
|
|
639
641
|
const stored = this.loadRecording();
|
|
640
|
-
if (!stored ||
|
|
642
|
+
if (!stored || Date.now() - stored.lastActivityAt >= REPLAY_IDLE_TIMEOUT_MS) {
|
|
641
643
|
this.rotateRecording();
|
|
642
644
|
return;
|
|
643
645
|
}
|
|
644
|
-
this.replayCapped =
|
|
646
|
+
this.replayCapped = stored.capped;
|
|
645
647
|
this.recordingId = stored.id;
|
|
646
648
|
this.recordingStartedAt = stored.startedAt;
|
|
647
649
|
this.recordingStartedAtMs = stored.startedAtMs;
|
|
@@ -727,8 +729,8 @@ var DataxamasTracking = class {
|
|
|
727
729
|
}
|
|
728
730
|
}
|
|
729
731
|
/**
|
|
730
|
-
* Bateu o teto: encerra a gravação e
|
|
731
|
-
*
|
|
732
|
+
* Bateu o teto: encerra a gravação e a visita não grava mais, em vez de emendar um clipe atrás do
|
|
733
|
+
* outro.
|
|
732
734
|
*/
|
|
733
735
|
scheduleReplayCutoff() {
|
|
734
736
|
if (this.cutoffPending) return;
|
|
@@ -751,11 +753,7 @@ var DataxamasTracking = class {
|
|
|
751
753
|
}, REPLAY_FLUSH_INTERVAL_MS);
|
|
752
754
|
setInterval(() => {
|
|
753
755
|
if (!this.isRecording()) return;
|
|
754
|
-
if (this.exceededReplayCaps())
|
|
755
|
-
this.scheduleReplayCutoff();
|
|
756
|
-
return;
|
|
757
|
-
}
|
|
758
|
-
if (Date.now() - this.lastActivityAt >= REPLAY_IDLE_SUSPEND_MS) this.stopReplayRecorder(false);
|
|
756
|
+
if (this.exceededReplayCaps()) this.scheduleReplayCutoff();
|
|
759
757
|
}, CAP_CHECK_MS);
|
|
760
758
|
window.addEventListener("pagehide", () => this.stopReplayRecorder(true));
|
|
761
759
|
document.addEventListener("visibilitychange", () => {
|
|
@@ -777,9 +775,17 @@ var DataxamasTracking = class {
|
|
|
777
775
|
}
|
|
778
776
|
if (this.isRecording() || this.replayHalted) return;
|
|
779
777
|
if (!this.recordingId) this.rotateRecording();
|
|
778
|
+
if (this.recordingSeq === 0) {
|
|
779
|
+
this.recordingStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
780
|
+
this.recordingStartedAtMs = Date.now();
|
|
781
|
+
}
|
|
780
782
|
this.snapshotFlushed = false;
|
|
781
783
|
this.stopRrweb = this.rrwebRecord({
|
|
782
784
|
emit: (event) => {
|
|
785
|
+
if (this.exceededReplayCaps()) {
|
|
786
|
+
this.scheduleReplayCutoff();
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
783
789
|
this.replayBuffer.push(event);
|
|
784
790
|
this.recordingEvents++;
|
|
785
791
|
if (!this.snapshotFlushed && event.type === 2) {
|
|
@@ -787,10 +793,6 @@ var DataxamasTracking = class {
|
|
|
787
793
|
this.flushReplay(false);
|
|
788
794
|
return;
|
|
789
795
|
}
|
|
790
|
-
if (this.exceededReplayCaps()) {
|
|
791
|
-
this.scheduleReplayCutoff();
|
|
792
|
-
return;
|
|
793
|
-
}
|
|
794
796
|
if (this.replayBuffer.length >= REPLAY_FLUSH_SIZE) this.flushReplay(false);
|
|
795
797
|
},
|
|
796
798
|
maskAllInputs: true,
|