@multiplayer-app/session-recorder-browser 2.0.36 → 2.0.39
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/browser/index.js +73 -19
- package/dist/exporters/index.js +1 -1
- package/dist/exporters/index.js.map +1 -1
- package/dist/index.js +73 -19
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +73 -19
- package/dist/index.umd.js.map +1 -1
- package/dist/rrweb/index.d.ts +1 -0
- package/dist/rrweb/index.d.ts.map +1 -1
- package/dist/rrweb/index.js +10 -2
- package/dist/rrweb/index.js.map +1 -1
- package/dist/services/crashBuffer.service.d.ts +2 -1
- package/dist/services/crashBuffer.service.d.ts.map +1 -1
- package/dist/services/crashBuffer.service.js +5 -1
- package/dist/services/crashBuffer.service.js.map +1 -1
- package/dist/services/socket.service.d.ts +3 -0
- package/dist/services/socket.service.d.ts.map +1 -1
- package/dist/services/socket.service.js +47 -5
- package/dist/services/socket.service.js.map +1 -1
- package/dist/session-recorder.d.ts.map +1 -1
- package/dist/session-recorder.js +10 -10
- package/dist/session-recorder.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -24263,7 +24263,7 @@ const CONTINUOUS_DEBUGGING_TIMEOUT = 60000; // 1 minutes
|
|
|
24263
24263
|
const DEBUG_SESSION_MAX_DURATION_SECONDS = 10 * 60 + 30; // TODO: move to shared config otel core
|
|
24264
24264
|
const REMOTE_SESSION_RECORDING_START = 'remote-session-recording:start';
|
|
24265
24265
|
const REMOTE_SESSION_RECORDING_STOP = 'remote-session-recording:stop';
|
|
24266
|
-
const PACKAGE_VERSION_EXPORT = "2.0.
|
|
24266
|
+
const PACKAGE_VERSION_EXPORT = "2.0.39" || 0;
|
|
24267
24267
|
// Regex patterns for OpenTelemetry ignore URLs
|
|
24268
24268
|
const OTEL_IGNORE_URLS = [
|
|
24269
24269
|
// Traces endpoint
|
|
@@ -25951,6 +25951,7 @@ if (typeof XMLHttpRequest !== 'undefined') {
|
|
|
25951
25951
|
|
|
25952
25952
|
class RecorderBrowserSDK {
|
|
25953
25953
|
constructor() {
|
|
25954
|
+
this.generation = 0;
|
|
25954
25955
|
this.intervals = {
|
|
25955
25956
|
restart: null,
|
|
25956
25957
|
bufferSnapshot: null,
|
|
@@ -25986,12 +25987,15 @@ class RecorderBrowserSDK {
|
|
|
25986
25987
|
throw new Error('Configuration not initialized. Call init() before start().');
|
|
25987
25988
|
}
|
|
25988
25989
|
this.startedAt = new Date().toISOString();
|
|
25990
|
+
const gen = ++this.generation;
|
|
25989
25991
|
this.stopFn = (0,rrweb__WEBPACK_IMPORTED_MODULE_6__.record)({
|
|
25990
25992
|
...this._buildRecordOptions(),
|
|
25991
25993
|
emit: async (event) => {
|
|
25994
|
+
if (gen !== this.generation)
|
|
25995
|
+
return;
|
|
25992
25996
|
const ts = event.timestamp;
|
|
25993
25997
|
if (!sessionId) {
|
|
25994
|
-
await this._handleBufferOnlyEvent(event, ts);
|
|
25998
|
+
await this._handleBufferOnlyEvent(event, ts, gen);
|
|
25995
25999
|
return;
|
|
25996
26000
|
}
|
|
25997
26001
|
this._handleLiveSessionEvent(event, ts, sessionId, sessionType);
|
|
@@ -26007,6 +26011,7 @@ class RecorderBrowserSDK {
|
|
|
26007
26011
|
var _a;
|
|
26008
26012
|
try {
|
|
26009
26013
|
(_a = this.stopFn) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
26014
|
+
this.stopFn = undefined;
|
|
26010
26015
|
this.start(sessionId, sessionType);
|
|
26011
26016
|
}
|
|
26012
26017
|
catch (_e) {
|
|
@@ -26020,6 +26025,7 @@ class RecorderBrowserSDK {
|
|
|
26020
26025
|
var _a, _b, _c;
|
|
26021
26026
|
(_a = this.stopFn) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
26022
26027
|
this.stopFn = undefined;
|
|
26028
|
+
this.generation++;
|
|
26023
26029
|
if (!((_b = this.config) === null || _b === void 0 ? void 0 : _b.useWebsocket)) {
|
|
26024
26030
|
(_c = this.socketService) === null || _c === void 0 ? void 0 : _c.close();
|
|
26025
26031
|
}
|
|
@@ -26059,13 +26065,15 @@ class RecorderBrowserSDK {
|
|
|
26059
26065
|
* @param event - Event.
|
|
26060
26066
|
* @param ts - Timestamp.
|
|
26061
26067
|
*/
|
|
26062
|
-
async _handleBufferOnlyEvent(event, ts) {
|
|
26068
|
+
async _handleBufferOnlyEvent(event, ts, gen) {
|
|
26063
26069
|
if (!this.crashBuffer)
|
|
26064
26070
|
return;
|
|
26065
26071
|
try {
|
|
26066
26072
|
this._applyConsoleMasking(event);
|
|
26067
26073
|
const packedEvent = (0,_rrweb_packer__WEBPACK_IMPORTED_MODULE_0__.pack)(event);
|
|
26068
26074
|
this.stoppedAt = new Date(ts).toISOString();
|
|
26075
|
+
if (gen !== this.generation)
|
|
26076
|
+
return;
|
|
26069
26077
|
await this.crashBuffer.appendEvent({
|
|
26070
26078
|
ts,
|
|
26071
26079
|
isFullSnapshot: event.type === _rrweb_types__WEBPACK_IMPORTED_MODULE_1__.EventType.FullSnapshot,
|
|
@@ -26335,10 +26343,11 @@ class ApiService {
|
|
|
26335
26343
|
|
|
26336
26344
|
|
|
26337
26345
|
class CrashBufferService {
|
|
26338
|
-
constructor(db, tabId, windowMs) {
|
|
26346
|
+
constructor(db, tabId, windowMs, ready = Promise.resolve()) {
|
|
26339
26347
|
this.db = db;
|
|
26340
26348
|
this.tabId = tabId;
|
|
26341
26349
|
this.windowMs = windowMs;
|
|
26350
|
+
this.ready = ready;
|
|
26342
26351
|
this.lastPruneAt = 0;
|
|
26343
26352
|
this.pruneInFlight = null;
|
|
26344
26353
|
this.isActive = true;
|
|
@@ -26361,6 +26370,7 @@ class CrashBufferService {
|
|
|
26361
26370
|
if (!this.isActive)
|
|
26362
26371
|
return;
|
|
26363
26372
|
const isFullSnapshot = Boolean(payload.isFullSnapshot);
|
|
26373
|
+
await this.ready;
|
|
26364
26374
|
await this._safe(async () => {
|
|
26365
26375
|
await this.db.appendEvent({
|
|
26366
26376
|
tabId: this.tabId,
|
|
@@ -26381,6 +26391,7 @@ class CrashBufferService {
|
|
|
26381
26391
|
if (!this.isActive)
|
|
26382
26392
|
return;
|
|
26383
26393
|
let errorEvent = null;
|
|
26394
|
+
await this.ready;
|
|
26384
26395
|
await this._safe(async () => {
|
|
26385
26396
|
const records = payload.map((p) => {
|
|
26386
26397
|
var _a, _b;
|
|
@@ -26429,6 +26440,7 @@ class CrashBufferService {
|
|
|
26429
26440
|
}
|
|
26430
26441
|
async snapshot(_windowMs, now = Date.now()) {
|
|
26431
26442
|
var _a, _b;
|
|
26443
|
+
await this.ready;
|
|
26432
26444
|
const stoppedAt = now;
|
|
26433
26445
|
const startedAt = Math.max(0, stoppedAt - this.windowMs);
|
|
26434
26446
|
// Always include a full snapshot "anchor" if one exists at/before the window start.
|
|
@@ -27063,6 +27075,8 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
|
|
|
27063
27075
|
this.sessionId = null;
|
|
27064
27076
|
this.usePostMessage = false;
|
|
27065
27077
|
this.isInitialized = false;
|
|
27078
|
+
this.lastUserPayload = null;
|
|
27079
|
+
this.lastSubscribeSession = null;
|
|
27066
27080
|
this.options = {
|
|
27067
27081
|
apiKey: '',
|
|
27068
27082
|
socketUrl: '',
|
|
@@ -27125,6 +27139,15 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
|
|
|
27125
27139
|
this.isConnecting = false;
|
|
27126
27140
|
this.isConnected = true;
|
|
27127
27141
|
this.usePostMessage = false;
|
|
27142
|
+
// Re-establish identity and session on every (re)connect: socket.io's auto-reconnect
|
|
27143
|
+
// fires 'ready' again after a drop, but the server has no memory of the previous
|
|
27144
|
+
// setUser/subscribe calls — the client must replay them.
|
|
27145
|
+
if (this.lastUserPayload && this.socket) {
|
|
27146
|
+
this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, this.lastUserPayload);
|
|
27147
|
+
}
|
|
27148
|
+
if (this.lastSubscribeSession) {
|
|
27149
|
+
this._emitSubscribe(this.lastSubscribeSession);
|
|
27150
|
+
}
|
|
27128
27151
|
this.flushQueue();
|
|
27129
27152
|
});
|
|
27130
27153
|
this.socket.on('disconnect', (err) => {
|
|
@@ -27191,16 +27214,33 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
|
|
|
27191
27214
|
this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_ADD_EVENT, event);
|
|
27192
27215
|
}
|
|
27193
27216
|
subscribeToSession(session) {
|
|
27217
|
+
// Remember the session so reconnects replay subscribe + started.
|
|
27218
|
+
this.lastSubscribeSession = session;
|
|
27219
|
+
this._emitSubscribe(session);
|
|
27220
|
+
}
|
|
27221
|
+
_emitSubscribe(session) {
|
|
27194
27222
|
this.sessionId = session.shortId || session._id;
|
|
27195
|
-
const
|
|
27223
|
+
const subscribePayload = {
|
|
27196
27224
|
projectId: session.project,
|
|
27197
27225
|
workspaceId: session.workspace,
|
|
27198
27226
|
debugSessionId: this.sessionId,
|
|
27199
27227
|
sessionType: session.creationType,
|
|
27200
27228
|
};
|
|
27201
|
-
|
|
27202
|
-
//
|
|
27203
|
-
|
|
27229
|
+
const startedPayload = { debugSessionId: session._id };
|
|
27230
|
+
// Send directly (not via the queue). The queue would cause a duplicate emit on
|
|
27231
|
+
// the next 'ready' alongside the replay, since 'ready' also replays lastSubscribeSession.
|
|
27232
|
+
if (this.usePostMessage) {
|
|
27233
|
+
this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_SUBSCRIBE_EVENT, subscribePayload);
|
|
27234
|
+
this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STARTED_EVENT, startedPayload);
|
|
27235
|
+
}
|
|
27236
|
+
else if (this.socket && this.isConnected) {
|
|
27237
|
+
this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_SUBSCRIBE_EVENT, subscribePayload);
|
|
27238
|
+
this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STARTED_EVENT, startedPayload);
|
|
27239
|
+
}
|
|
27240
|
+
else {
|
|
27241
|
+
// Not connected: 'ready' will replay via lastSubscribeSession once the socket is up.
|
|
27242
|
+
this._initConnection();
|
|
27243
|
+
}
|
|
27204
27244
|
}
|
|
27205
27245
|
unsubscribeFromSession(stopSession) {
|
|
27206
27246
|
if (this.sessionId) {
|
|
@@ -27209,9 +27249,23 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
|
|
|
27209
27249
|
this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STOPPED_EVENT, {});
|
|
27210
27250
|
}
|
|
27211
27251
|
}
|
|
27252
|
+
this.lastSubscribeSession = null;
|
|
27212
27253
|
}
|
|
27213
27254
|
setUser(data) {
|
|
27214
|
-
|
|
27255
|
+
// Remember the last identity so 'ready' (initial connect + every reconnect) can replay it.
|
|
27256
|
+
// Send directly here rather than queuing: the queue would cause a duplicate emit on the
|
|
27257
|
+
// next 'ready' alongside the replay.
|
|
27258
|
+
this.lastUserPayload = data;
|
|
27259
|
+
if (this.usePostMessage) {
|
|
27260
|
+
this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, data);
|
|
27261
|
+
}
|
|
27262
|
+
else if (this.socket && this.isConnected) {
|
|
27263
|
+
this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, data);
|
|
27264
|
+
}
|
|
27265
|
+
else {
|
|
27266
|
+
// Not connected yet: 'ready' will replay lastUserPayload once the socket is up.
|
|
27267
|
+
this._initConnection();
|
|
27268
|
+
}
|
|
27215
27269
|
}
|
|
27216
27270
|
close() {
|
|
27217
27271
|
return new Promise((resolve) => {
|
|
@@ -27452,13 +27506,11 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
|
|
|
27452
27506
|
this._start();
|
|
27453
27507
|
}
|
|
27454
27508
|
else {
|
|
27455
|
-
// Buffer-only recording when there is no active debug session.
|
|
27456
27509
|
this._startBufferOnlyRecording();
|
|
27457
27510
|
}
|
|
27458
27511
|
this._registerWidgetEvents();
|
|
27459
27512
|
this._registerSocketServiceListeners();
|
|
27460
27513
|
_services_messaging_service__WEBPACK_IMPORTED_MODULE_9__["default"].sendMessage('state-change', this.sessionState);
|
|
27461
|
-
// Emit init observable event
|
|
27462
27514
|
this.emit('init', [this]);
|
|
27463
27515
|
}
|
|
27464
27516
|
_setupCrashBuffer() {
|
|
@@ -27466,7 +27518,8 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
|
|
|
27466
27518
|
if ((_a = this._configs.buffering) === null || _a === void 0 ? void 0 : _a.enabled) {
|
|
27467
27519
|
const windowMinutes = this._configs.buffering.windowMinutes || 0.5;
|
|
27468
27520
|
const windowMs = Math.max(10000, windowMinutes * 60 * 1000);
|
|
27469
|
-
|
|
27521
|
+
const ready = this._bufferDb.clearTab(this._tabId).catch(() => undefined);
|
|
27522
|
+
this._crashBuffer = new _services_crashBuffer_service__WEBPACK_IMPORTED_MODULE_13__.CrashBufferService(this._bufferDb, this._tabId, windowMs, ready);
|
|
27470
27523
|
this._recorder.setCrashBuffer(this._crashBuffer);
|
|
27471
27524
|
this._tracer.setCrashBuffer(this._crashBuffer);
|
|
27472
27525
|
this._crashBuffer.on('error-span-appended', (payload) => {
|
|
@@ -27700,12 +27753,7 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
|
|
|
27700
27753
|
}
|
|
27701
27754
|
}
|
|
27702
27755
|
async _flushBuffer(sessionId) {
|
|
27703
|
-
|
|
27704
|
-
if (!sessionId ||
|
|
27705
|
-
!this._crashBuffer ||
|
|
27706
|
-
this._isFlushingBuffer ||
|
|
27707
|
-
!((_b = (_a = this._configs) === null || _a === void 0 ? void 0 : _a.buffering) === null || _b === void 0 ? void 0 : _b.enabled) ||
|
|
27708
|
-
this.sessionState !== _types__WEBPACK_IMPORTED_MODULE_4__.SessionState.stopped) {
|
|
27756
|
+
if (!sessionId || !this._crashBuffer || this._isFlushingBuffer) {
|
|
27709
27757
|
return null;
|
|
27710
27758
|
}
|
|
27711
27759
|
this._isFlushingBuffer = true;
|
|
@@ -27895,6 +27943,8 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
|
|
|
27895
27943
|
});
|
|
27896
27944
|
this._socketService.on(_config__WEBPACK_IMPORTED_MODULE_5__.SESSION_SAVE_BUFFER_EVENT, (payload) => {
|
|
27897
27945
|
var _a;
|
|
27946
|
+
if (this.sessionState !== _types__WEBPACK_IMPORTED_MODULE_4__.SessionState.stopped)
|
|
27947
|
+
return;
|
|
27898
27948
|
this._flushBuffer((_a = payload === null || payload === void 0 ? void 0 : payload.debugSession) === null || _a === void 0 ? void 0 : _a._id);
|
|
27899
27949
|
});
|
|
27900
27950
|
}
|
|
@@ -27965,7 +28015,11 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
|
|
|
27965
28015
|
this._tracer.stop();
|
|
27966
28016
|
this._recorder.stop();
|
|
27967
28017
|
this._navigationRecorder.stop();
|
|
27968
|
-
|
|
28018
|
+
// rrweb assigns new node IDs on each record() call, so the next buffer
|
|
28019
|
+
// segment must not carry events from the previous generation. Await the
|
|
28020
|
+
// clear so its IDB tx can't race past the fresh FullSnapshot.
|
|
28021
|
+
const cleared = this._crashBuffer ? this._crashBuffer.clear() : Promise.resolve();
|
|
28022
|
+
void cleared.catch(() => undefined).then(() => this._startBufferOnlyRecording());
|
|
27969
28023
|
}
|
|
27970
28024
|
/**
|
|
27971
28025
|
* Pause the session tracing and recording
|