@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/browser/index.js
CHANGED
|
@@ -25163,7 +25163,7 @@ const CONTINUOUS_DEBUGGING_TIMEOUT = 60000; // 1 minutes
|
|
|
25163
25163
|
const DEBUG_SESSION_MAX_DURATION_SECONDS = 10 * 60 + 30; // TODO: move to shared config otel core
|
|
25164
25164
|
const REMOTE_SESSION_RECORDING_START = 'remote-session-recording:start';
|
|
25165
25165
|
const REMOTE_SESSION_RECORDING_STOP = 'remote-session-recording:stop';
|
|
25166
|
-
const PACKAGE_VERSION_EXPORT = "2.0.
|
|
25166
|
+
const PACKAGE_VERSION_EXPORT = "2.0.39" || 0;
|
|
25167
25167
|
// Regex patterns for OpenTelemetry ignore URLs
|
|
25168
25168
|
const OTEL_IGNORE_URLS = [
|
|
25169
25169
|
// Traces endpoint
|
|
@@ -26907,6 +26907,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
26907
26907
|
|
|
26908
26908
|
class RecorderBrowserSDK {
|
|
26909
26909
|
constructor() {
|
|
26910
|
+
this.generation = 0;
|
|
26910
26911
|
this.intervals = {
|
|
26911
26912
|
restart: null,
|
|
26912
26913
|
bufferSnapshot: null,
|
|
@@ -26942,12 +26943,15 @@ class RecorderBrowserSDK {
|
|
|
26942
26943
|
throw new Error('Configuration not initialized. Call init() before start().');
|
|
26943
26944
|
}
|
|
26944
26945
|
this.startedAt = new Date().toISOString();
|
|
26946
|
+
const gen = ++this.generation;
|
|
26945
26947
|
this.stopFn = (0,rrweb__WEBPACK_IMPORTED_MODULE_6__.record)({
|
|
26946
26948
|
...this._buildRecordOptions(),
|
|
26947
26949
|
emit: async (event) => {
|
|
26950
|
+
if (gen !== this.generation)
|
|
26951
|
+
return;
|
|
26948
26952
|
const ts = event.timestamp;
|
|
26949
26953
|
if (!sessionId) {
|
|
26950
|
-
await this._handleBufferOnlyEvent(event, ts);
|
|
26954
|
+
await this._handleBufferOnlyEvent(event, ts, gen);
|
|
26951
26955
|
return;
|
|
26952
26956
|
}
|
|
26953
26957
|
this._handleLiveSessionEvent(event, ts, sessionId, sessionType);
|
|
@@ -26963,6 +26967,7 @@ class RecorderBrowserSDK {
|
|
|
26963
26967
|
var _a;
|
|
26964
26968
|
try {
|
|
26965
26969
|
(_a = this.stopFn) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
26970
|
+
this.stopFn = undefined;
|
|
26966
26971
|
this.start(sessionId, sessionType);
|
|
26967
26972
|
}
|
|
26968
26973
|
catch (_e) {
|
|
@@ -26976,6 +26981,7 @@ class RecorderBrowserSDK {
|
|
|
26976
26981
|
var _a, _b, _c;
|
|
26977
26982
|
(_a = this.stopFn) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
26978
26983
|
this.stopFn = undefined;
|
|
26984
|
+
this.generation++;
|
|
26979
26985
|
if (!((_b = this.config) === null || _b === void 0 ? void 0 : _b.useWebsocket)) {
|
|
26980
26986
|
(_c = this.socketService) === null || _c === void 0 ? void 0 : _c.close();
|
|
26981
26987
|
}
|
|
@@ -27015,13 +27021,15 @@ class RecorderBrowserSDK {
|
|
|
27015
27021
|
* @param event - Event.
|
|
27016
27022
|
* @param ts - Timestamp.
|
|
27017
27023
|
*/
|
|
27018
|
-
async _handleBufferOnlyEvent(event, ts) {
|
|
27024
|
+
async _handleBufferOnlyEvent(event, ts, gen) {
|
|
27019
27025
|
if (!this.crashBuffer)
|
|
27020
27026
|
return;
|
|
27021
27027
|
try {
|
|
27022
27028
|
this._applyConsoleMasking(event);
|
|
27023
27029
|
const packedEvent = (0,_rrweb_packer__WEBPACK_IMPORTED_MODULE_0__.pack)(event);
|
|
27024
27030
|
this.stoppedAt = new Date(ts).toISOString();
|
|
27031
|
+
if (gen !== this.generation)
|
|
27032
|
+
return;
|
|
27025
27033
|
await this.crashBuffer.appendEvent({
|
|
27026
27034
|
ts,
|
|
27027
27035
|
isFullSnapshot: event.type === _rrweb_types__WEBPACK_IMPORTED_MODULE_1__.EventType.FullSnapshot,
|
|
@@ -27295,10 +27303,11 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
27295
27303
|
|
|
27296
27304
|
|
|
27297
27305
|
class CrashBufferService {
|
|
27298
|
-
constructor(db, tabId, windowMs) {
|
|
27306
|
+
constructor(db, tabId, windowMs, ready = Promise.resolve()) {
|
|
27299
27307
|
this.db = db;
|
|
27300
27308
|
this.tabId = tabId;
|
|
27301
27309
|
this.windowMs = windowMs;
|
|
27310
|
+
this.ready = ready;
|
|
27302
27311
|
this.lastPruneAt = 0;
|
|
27303
27312
|
this.pruneInFlight = null;
|
|
27304
27313
|
this.isActive = true;
|
|
@@ -27321,6 +27330,7 @@ class CrashBufferService {
|
|
|
27321
27330
|
if (!this.isActive)
|
|
27322
27331
|
return;
|
|
27323
27332
|
const isFullSnapshot = Boolean(payload.isFullSnapshot);
|
|
27333
|
+
await this.ready;
|
|
27324
27334
|
await this._safe(async () => {
|
|
27325
27335
|
await this.db.appendEvent({
|
|
27326
27336
|
tabId: this.tabId,
|
|
@@ -27341,6 +27351,7 @@ class CrashBufferService {
|
|
|
27341
27351
|
if (!this.isActive)
|
|
27342
27352
|
return;
|
|
27343
27353
|
let errorEvent = null;
|
|
27354
|
+
await this.ready;
|
|
27344
27355
|
await this._safe(async () => {
|
|
27345
27356
|
const records = payload.map((p) => {
|
|
27346
27357
|
var _a, _b;
|
|
@@ -27389,6 +27400,7 @@ class CrashBufferService {
|
|
|
27389
27400
|
}
|
|
27390
27401
|
async snapshot(_windowMs, now = Date.now()) {
|
|
27391
27402
|
var _a, _b;
|
|
27403
|
+
await this.ready;
|
|
27392
27404
|
const stoppedAt = now;
|
|
27393
27405
|
const startedAt = Math.max(0, stoppedAt - this.windowMs);
|
|
27394
27406
|
// Always include a full snapshot "anchor" if one exists at/before the window start.
|
|
@@ -28029,6 +28041,8 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
|
|
|
28029
28041
|
this.sessionId = null;
|
|
28030
28042
|
this.usePostMessage = false;
|
|
28031
28043
|
this.isInitialized = false;
|
|
28044
|
+
this.lastUserPayload = null;
|
|
28045
|
+
this.lastSubscribeSession = null;
|
|
28032
28046
|
this.options = {
|
|
28033
28047
|
apiKey: '',
|
|
28034
28048
|
socketUrl: '',
|
|
@@ -28091,6 +28105,15 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
|
|
|
28091
28105
|
this.isConnecting = false;
|
|
28092
28106
|
this.isConnected = true;
|
|
28093
28107
|
this.usePostMessage = false;
|
|
28108
|
+
// Re-establish identity and session on every (re)connect: socket.io's auto-reconnect
|
|
28109
|
+
// fires 'ready' again after a drop, but the server has no memory of the previous
|
|
28110
|
+
// setUser/subscribe calls — the client must replay them.
|
|
28111
|
+
if (this.lastUserPayload && this.socket) {
|
|
28112
|
+
this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, this.lastUserPayload);
|
|
28113
|
+
}
|
|
28114
|
+
if (this.lastSubscribeSession) {
|
|
28115
|
+
this._emitSubscribe(this.lastSubscribeSession);
|
|
28116
|
+
}
|
|
28094
28117
|
this.flushQueue();
|
|
28095
28118
|
});
|
|
28096
28119
|
this.socket.on('disconnect', (err) => {
|
|
@@ -28157,16 +28180,33 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
|
|
|
28157
28180
|
this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_ADD_EVENT, event);
|
|
28158
28181
|
}
|
|
28159
28182
|
subscribeToSession(session) {
|
|
28183
|
+
// Remember the session so reconnects replay subscribe + started.
|
|
28184
|
+
this.lastSubscribeSession = session;
|
|
28185
|
+
this._emitSubscribe(session);
|
|
28186
|
+
}
|
|
28187
|
+
_emitSubscribe(session) {
|
|
28160
28188
|
this.sessionId = session.shortId || session._id;
|
|
28161
|
-
const
|
|
28189
|
+
const subscribePayload = {
|
|
28162
28190
|
projectId: session.project,
|
|
28163
28191
|
workspaceId: session.workspace,
|
|
28164
28192
|
debugSessionId: this.sessionId,
|
|
28165
28193
|
sessionType: session.creationType,
|
|
28166
28194
|
};
|
|
28167
|
-
|
|
28168
|
-
//
|
|
28169
|
-
|
|
28195
|
+
const startedPayload = { debugSessionId: session._id };
|
|
28196
|
+
// Send directly (not via the queue). The queue would cause a duplicate emit on
|
|
28197
|
+
// the next 'ready' alongside the replay, since 'ready' also replays lastSubscribeSession.
|
|
28198
|
+
if (this.usePostMessage) {
|
|
28199
|
+
this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_SUBSCRIBE_EVENT, subscribePayload);
|
|
28200
|
+
this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STARTED_EVENT, startedPayload);
|
|
28201
|
+
}
|
|
28202
|
+
else if (this.socket && this.isConnected) {
|
|
28203
|
+
this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_SUBSCRIBE_EVENT, subscribePayload);
|
|
28204
|
+
this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STARTED_EVENT, startedPayload);
|
|
28205
|
+
}
|
|
28206
|
+
else {
|
|
28207
|
+
// Not connected: 'ready' will replay via lastSubscribeSession once the socket is up.
|
|
28208
|
+
this._initConnection();
|
|
28209
|
+
}
|
|
28170
28210
|
}
|
|
28171
28211
|
unsubscribeFromSession(stopSession) {
|
|
28172
28212
|
if (this.sessionId) {
|
|
@@ -28175,9 +28215,23 @@ class SocketService extends lib0_observable__WEBPACK_IMPORTED_MODULE_4__.Observa
|
|
|
28175
28215
|
this.emitSocketEvent(_config__WEBPACK_IMPORTED_MODULE_2__.SESSION_STOPPED_EVENT, {});
|
|
28176
28216
|
}
|
|
28177
28217
|
}
|
|
28218
|
+
this.lastSubscribeSession = null;
|
|
28178
28219
|
}
|
|
28179
28220
|
setUser(data) {
|
|
28180
|
-
|
|
28221
|
+
// Remember the last identity so 'ready' (initial connect + every reconnect) can replay it.
|
|
28222
|
+
// Send directly here rather than queuing: the queue would cause a duplicate emit on the
|
|
28223
|
+
// next 'ready' alongside the replay.
|
|
28224
|
+
this.lastUserPayload = data;
|
|
28225
|
+
if (this.usePostMessage) {
|
|
28226
|
+
this.sendViaPostMessage(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, data);
|
|
28227
|
+
}
|
|
28228
|
+
else if (this.socket && this.isConnected) {
|
|
28229
|
+
this.socket.emit(_config__WEBPACK_IMPORTED_MODULE_2__.SOCKET_SET_USER_EVENT, data);
|
|
28230
|
+
}
|
|
28231
|
+
else {
|
|
28232
|
+
// Not connected yet: 'ready' will replay lastUserPayload once the socket is up.
|
|
28233
|
+
this._initConnection();
|
|
28234
|
+
}
|
|
28181
28235
|
}
|
|
28182
28236
|
close() {
|
|
28183
28237
|
return new Promise((resolve) => {
|
|
@@ -28420,13 +28474,11 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
|
|
|
28420
28474
|
this._start();
|
|
28421
28475
|
}
|
|
28422
28476
|
else {
|
|
28423
|
-
// Buffer-only recording when there is no active debug session.
|
|
28424
28477
|
this._startBufferOnlyRecording();
|
|
28425
28478
|
}
|
|
28426
28479
|
this._registerWidgetEvents();
|
|
28427
28480
|
this._registerSocketServiceListeners();
|
|
28428
28481
|
_services_messaging_service__WEBPACK_IMPORTED_MODULE_9__["default"].sendMessage('state-change', this.sessionState);
|
|
28429
|
-
// Emit init observable event
|
|
28430
28482
|
this.emit('init', [this]);
|
|
28431
28483
|
}
|
|
28432
28484
|
_setupCrashBuffer() {
|
|
@@ -28434,7 +28486,8 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
|
|
|
28434
28486
|
if ((_a = this._configs.buffering) === null || _a === void 0 ? void 0 : _a.enabled) {
|
|
28435
28487
|
const windowMinutes = this._configs.buffering.windowMinutes || 0.5;
|
|
28436
28488
|
const windowMs = Math.max(10000, windowMinutes * 60 * 1000);
|
|
28437
|
-
|
|
28489
|
+
const ready = this._bufferDb.clearTab(this._tabId).catch(() => undefined);
|
|
28490
|
+
this._crashBuffer = new _services_crashBuffer_service__WEBPACK_IMPORTED_MODULE_13__.CrashBufferService(this._bufferDb, this._tabId, windowMs, ready);
|
|
28438
28491
|
this._recorder.setCrashBuffer(this._crashBuffer);
|
|
28439
28492
|
this._tracer.setCrashBuffer(this._crashBuffer);
|
|
28440
28493
|
this._crashBuffer.on('error-span-appended', (payload) => {
|
|
@@ -28668,12 +28721,7 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
|
|
|
28668
28721
|
}
|
|
28669
28722
|
}
|
|
28670
28723
|
async _flushBuffer(sessionId) {
|
|
28671
|
-
|
|
28672
|
-
if (!sessionId ||
|
|
28673
|
-
!this._crashBuffer ||
|
|
28674
|
-
this._isFlushingBuffer ||
|
|
28675
|
-
!((_b = (_a = this._configs) === null || _a === void 0 ? void 0 : _a.buffering) === null || _b === void 0 ? void 0 : _b.enabled) ||
|
|
28676
|
-
this.sessionState !== _types__WEBPACK_IMPORTED_MODULE_4__.SessionState.stopped) {
|
|
28724
|
+
if (!sessionId || !this._crashBuffer || this._isFlushingBuffer) {
|
|
28677
28725
|
return null;
|
|
28678
28726
|
}
|
|
28679
28727
|
this._isFlushingBuffer = true;
|
|
@@ -28863,6 +28911,8 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
|
|
|
28863
28911
|
});
|
|
28864
28912
|
this._socketService.on(_config__WEBPACK_IMPORTED_MODULE_5__.SESSION_SAVE_BUFFER_EVENT, (payload) => {
|
|
28865
28913
|
var _a;
|
|
28914
|
+
if (this.sessionState !== _types__WEBPACK_IMPORTED_MODULE_4__.SessionState.stopped)
|
|
28915
|
+
return;
|
|
28866
28916
|
this._flushBuffer((_a = payload === null || payload === void 0 ? void 0 : payload.debugSession) === null || _a === void 0 ? void 0 : _a._id);
|
|
28867
28917
|
});
|
|
28868
28918
|
}
|
|
@@ -28933,7 +28983,11 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_16__.Obse
|
|
|
28933
28983
|
this._tracer.stop();
|
|
28934
28984
|
this._recorder.stop();
|
|
28935
28985
|
this._navigationRecorder.stop();
|
|
28936
|
-
|
|
28986
|
+
// rrweb assigns new node IDs on each record() call, so the next buffer
|
|
28987
|
+
// segment must not carry events from the previous generation. Await the
|
|
28988
|
+
// clear so its IDB tx can't race past the fresh FullSnapshot.
|
|
28989
|
+
const cleared = this._crashBuffer ? this._crashBuffer.clear() : Promise.resolve();
|
|
28990
|
+
void cleared.catch(() => undefined).then(() => this._startBufferOnlyRecording());
|
|
28937
28991
|
}
|
|
28938
28992
|
/**
|
|
28939
28993
|
* Pause the session tracing and recording
|