@multiplayer-app/session-recorder-react-native 1.3.22 → 1.3.32
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/README.md +22 -13
- package/lib/module/config/defaults.js +2 -2
- package/lib/module/config/defaults.js.map +1 -1
- package/lib/module/config/session-recorder.js.map +1 -1
- package/lib/module/otel/CrashBufferSpanProcessor.js +14 -13
- package/lib/module/otel/CrashBufferSpanProcessor.js.map +1 -1
- package/lib/module/otel/index.js +93 -71
- package/lib/module/otel/index.js.map +1 -1
- package/lib/module/recorder/index.js +1 -1
- package/lib/module/recorder/index.js.map +1 -1
- package/lib/module/services/api.service.js.map +1 -1
- package/lib/module/services/crashBuffer.service.js +51 -19
- package/lib/module/services/crashBuffer.service.js.map +1 -1
- package/lib/module/services/socket.service.js +2 -2
- package/lib/module/services/socket.service.js.map +1 -1
- package/lib/module/session-recorder.js +29 -78
- package/lib/module/session-recorder.js.map +1 -1
- package/lib/module/types/session-recorder.js.map +1 -1
- package/lib/module/utils/rrweb-events.js +1 -1
- package/lib/module/utils/rrweb-events.js.map +1 -1
- package/lib/typescript/src/config/defaults.d.ts.map +1 -1
- package/lib/typescript/src/config/session-recorder.d.ts.map +1 -1
- package/lib/typescript/src/otel/CrashBufferSpanProcessor.d.ts +3 -4
- package/lib/typescript/src/otel/CrashBufferSpanProcessor.d.ts.map +1 -1
- package/lib/typescript/src/otel/index.d.ts +2 -5
- package/lib/typescript/src/otel/index.d.ts.map +1 -1
- package/lib/typescript/src/services/api.service.d.ts +2 -1
- package/lib/typescript/src/services/api.service.d.ts.map +1 -1
- package/lib/typescript/src/services/crashBuffer.service.d.ts +4 -23
- package/lib/typescript/src/services/crashBuffer.service.d.ts.map +1 -1
- package/lib/typescript/src/services/socket.service.d.ts +4 -1
- package/lib/typescript/src/services/socket.service.d.ts.map +1 -1
- package/lib/typescript/src/session-recorder.d.ts +0 -3
- package/lib/typescript/src/session-recorder.d.ts.map +1 -1
- package/lib/typescript/src/types/session-recorder.d.ts +6 -13
- package/lib/typescript/src/types/session-recorder.d.ts.map +1 -1
- package/lib/typescript/src/utils/rrweb-events.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/config/defaults.ts +29 -29
- package/src/config/session-recorder.ts +8 -2
- package/src/otel/CrashBufferSpanProcessor.ts +17 -24
- package/src/otel/index.ts +124 -76
- package/src/recorder/index.ts +1 -1
- package/src/services/api.service.ts +2 -1
- package/src/services/crashBuffer.service.ts +73 -31
- package/src/services/socket.service.ts +5 -2
- package/src/session-recorder.ts +43 -98
- package/src/types/session-recorder.ts +15 -18
- package/src/utils/rrweb-events.ts +3 -3
package/src/session-recorder.ts
CHANGED
|
@@ -180,95 +180,32 @@ class SessionRecorder
|
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
public async flushBuffer(payload?: { reason?: string }): Promise<any> {
|
|
184
|
-
if (!this._configs?.buffering?.enabled) return null;
|
|
185
|
-
if (this._isFlushingBuffer) return null;
|
|
186
|
-
if (this.sessionState !== SessionState.stopped || this.sessionId)
|
|
187
|
-
return null;
|
|
188
|
-
|
|
189
|
-
const windowMs = Math.max(
|
|
190
|
-
10_000,
|
|
191
|
-
(this._configs.buffering.windowMinutes || 2) * 60 * 1000
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
this._isFlushingBuffer = true;
|
|
195
|
-
try {
|
|
196
|
-
const reason = payload?.reason || 'manual';
|
|
197
|
-
await this._crashBuffer.setAttrs({
|
|
198
|
-
sessionAttributes: this.sessionAttributes,
|
|
199
|
-
resourceAttributes: getNavigatorInfo(),
|
|
200
|
-
userAttributes: this._userAttributes,
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
const snapshot = await this._crashBuffer.snapshot(windowMs);
|
|
204
|
-
if (
|
|
205
|
-
snapshot.rrwebEvents.length === 0 &&
|
|
206
|
-
snapshot.otelSpans.length === 0
|
|
207
|
-
) {
|
|
208
|
-
return null;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const request: StartSessionRequest = {
|
|
212
|
-
name: `${this._configs.application} ${getFormattedDate(new Date())}`,
|
|
213
|
-
stoppedAt: new Date().toISOString(),
|
|
214
|
-
sessionAttributes: this.sessionAttributes,
|
|
215
|
-
resourceAttributes: getNavigatorInfo(),
|
|
216
|
-
...(this._userAttributes
|
|
217
|
-
? { userAttributes: this._userAttributes }
|
|
218
|
-
: {}),
|
|
219
|
-
debugSessionData: {
|
|
220
|
-
meta: {
|
|
221
|
-
reason,
|
|
222
|
-
windowMs: snapshot.windowMs,
|
|
223
|
-
fromTs: snapshot.fromTs,
|
|
224
|
-
toTs: snapshot.toTs,
|
|
225
|
-
},
|
|
226
|
-
events: snapshot.rrwebEvents,
|
|
227
|
-
spans: snapshot.otelSpans.map((s) => s.span),
|
|
228
|
-
attrs: snapshot.attrs,
|
|
229
|
-
},
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
try {
|
|
233
|
-
const res = await this._apiService.startSession(request);
|
|
234
|
-
await this._crashBuffer.clear();
|
|
235
|
-
return res;
|
|
236
|
-
} catch (_e) {
|
|
237
|
-
// swallow: flush is best-effort; never throw into app code
|
|
238
|
-
return null;
|
|
239
|
-
}
|
|
240
|
-
} finally {
|
|
241
|
-
this._isFlushingBuffer = false;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
183
|
private async _flushBuffer(sessionId: string): Promise<any> {
|
|
246
|
-
if (
|
|
247
|
-
|
|
248
|
-
|
|
184
|
+
if (
|
|
185
|
+
!sessionId ||
|
|
186
|
+
!this._crashBuffer ||
|
|
187
|
+
this._isFlushingBuffer ||
|
|
188
|
+
!this._configs?.buffering?.enabled ||
|
|
189
|
+
this.sessionState !== SessionState.stopped
|
|
190
|
+
) {
|
|
249
191
|
return null;
|
|
250
|
-
|
|
251
|
-
const windowMs = Math.max(
|
|
252
|
-
10_000,
|
|
253
|
-
(this._configs.buffering.windowMinutes || 2) * 60 * 1000
|
|
254
|
-
);
|
|
192
|
+
}
|
|
255
193
|
|
|
256
194
|
this._isFlushingBuffer = true;
|
|
257
195
|
try {
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
snapshot.otelSpans.length === 0
|
|
262
|
-
) {
|
|
196
|
+
const { events, spans, startedAt, stoppedAt } =
|
|
197
|
+
await this._crashBuffer.snapshot();
|
|
198
|
+
if (events.length === 0 && spans.length === 0) {
|
|
263
199
|
return null;
|
|
264
200
|
}
|
|
265
|
-
const spans = snapshot.otelSpans.map((s) => s.span);
|
|
266
|
-
const events = snapshot.rrwebEvents.map((e) => e.event);
|
|
267
201
|
await Promise.all([
|
|
268
|
-
this._tracer.exportTraces(spans),
|
|
269
|
-
this._apiService.exportEvents(sessionId, {
|
|
202
|
+
this._tracer.exportTraces(spans.map((s) => s.span)),
|
|
203
|
+
this._apiService.exportEvents(sessionId, {
|
|
204
|
+
events: events.map((e) => e.event),
|
|
205
|
+
}),
|
|
270
206
|
this._apiService.updateSessionAttributes(sessionId, {
|
|
271
|
-
|
|
207
|
+
startedAt: new Date(startedAt).toISOString(),
|
|
208
|
+
stoppedAt: new Date(stoppedAt).toISOString(),
|
|
272
209
|
sessionAttributes: this.sessionAttributes,
|
|
273
210
|
resourceAttributes: getNavigatorInfo(),
|
|
274
211
|
userAttributes: this._userAttributes || undefined,
|
|
@@ -285,7 +222,7 @@ class SessionRecorder
|
|
|
285
222
|
private async _createExceptionSession(span: any): Promise<void> {
|
|
286
223
|
try {
|
|
287
224
|
const session = await this._apiService.createErrorSession({ span });
|
|
288
|
-
if (session) {
|
|
225
|
+
if (session?._id) {
|
|
289
226
|
void this._flushBuffer(session._id);
|
|
290
227
|
}
|
|
291
228
|
} catch (_ignored) {
|
|
@@ -341,7 +278,7 @@ class SessionRecorder
|
|
|
341
278
|
const bufferEnabled = Boolean(this._configs.buffering?.enabled);
|
|
342
279
|
const windowMs = Math.max(
|
|
343
280
|
10_000,
|
|
344
|
-
(this._configs.buffering?.windowMinutes ||
|
|
281
|
+
(this._configs.buffering?.windowMinutes || 0.5) * 60 * 1000
|
|
345
282
|
);
|
|
346
283
|
this._tracer.setCrashBuffer(
|
|
347
284
|
bufferEnabled ? this._crashBuffer : undefined,
|
|
@@ -365,8 +302,13 @@ class SessionRecorder
|
|
|
365
302
|
);
|
|
366
303
|
|
|
367
304
|
this._crashBuffer.on('error-span-appended', (payload) => {
|
|
368
|
-
if (
|
|
369
|
-
|
|
305
|
+
if (
|
|
306
|
+
!payload.span ||
|
|
307
|
+
this.sessionId ||
|
|
308
|
+
this.sessionState !== SessionState.stopped
|
|
309
|
+
) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
370
312
|
this._createExceptionSession(payload.span);
|
|
371
313
|
});
|
|
372
314
|
|
|
@@ -387,21 +329,20 @@ class SessionRecorder
|
|
|
387
329
|
}
|
|
388
330
|
|
|
389
331
|
private _startBufferOnlyRecording(): void {
|
|
390
|
-
if (
|
|
391
|
-
|
|
332
|
+
if (
|
|
333
|
+
this.sessionId ||
|
|
334
|
+
!this._crashBuffer ||
|
|
335
|
+
!this._configs?.buffering?.enabled ||
|
|
336
|
+
this.sessionState !== SessionState.stopped
|
|
337
|
+
) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
392
340
|
|
|
393
341
|
const windowMs = Math.max(
|
|
394
342
|
10_000,
|
|
395
|
-
(this._configs.buffering.windowMinutes ||
|
|
343
|
+
(this._configs.buffering.windowMinutes || 0.5) * 60 * 1000
|
|
396
344
|
);
|
|
397
345
|
|
|
398
|
-
// Best-effort: persist current attrs so flush has context.
|
|
399
|
-
this._crashBuffer.setAttrs({
|
|
400
|
-
sessionAttributes: this.sessionAttributes,
|
|
401
|
-
resourceAttributes: getNavigatorInfo(),
|
|
402
|
-
userAttributes: this._userAttributes,
|
|
403
|
-
});
|
|
404
|
-
|
|
405
346
|
// Wire buffer into tracer + recorder (only used when sessionId is null).
|
|
406
347
|
this._tracer.setCrashBuffer(this._crashBuffer, windowMs);
|
|
407
348
|
this._recorder.init(this._configs, this._socketService, this._crashBuffer, {
|
|
@@ -448,9 +389,7 @@ class SessionRecorder
|
|
|
448
389
|
});
|
|
449
390
|
|
|
450
391
|
this._socketService.on(SESSION_SAVE_BUFFER_EVENT, (payload: any) => {
|
|
451
|
-
|
|
452
|
-
void this._flushBuffer(payload.debugSession._id);
|
|
453
|
-
}
|
|
392
|
+
this._flushBuffer(payload?.debugSession?._id);
|
|
454
393
|
});
|
|
455
394
|
}
|
|
456
395
|
|
|
@@ -628,7 +567,13 @@ class SessionRecorder
|
|
|
628
567
|
return;
|
|
629
568
|
}
|
|
630
569
|
this._userAttributes = userAttributes;
|
|
631
|
-
|
|
570
|
+
|
|
571
|
+
const data = {
|
|
572
|
+
userAttributes: this._userAttributes,
|
|
573
|
+
clientId: this._tracer.clientId,
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
this._socketService.setUser(data);
|
|
632
577
|
}
|
|
633
578
|
|
|
634
579
|
/**
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { type Span } from '@opentelemetry/api';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
type ISession,
|
|
4
|
+
type SessionType,
|
|
5
|
+
type IUserAttributes,
|
|
6
|
+
} from '@multiplayer-app/session-recorder-common';
|
|
3
7
|
import { type PropagateTraceHeaderCorsUrls } from '@opentelemetry/sdk-trace-web';
|
|
4
8
|
|
|
5
|
-
|
|
6
9
|
// WidgetButtonPlacement moved to configs.ts
|
|
7
10
|
|
|
8
11
|
export enum SessionState {
|
|
@@ -157,11 +160,11 @@ export interface SessionRecorderOptions {
|
|
|
157
160
|
};
|
|
158
161
|
|
|
159
162
|
/**
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
useWebsocket?: boolean
|
|
163
|
+
* @description
|
|
164
|
+
* If true, webSocket will be used to manage remote recording sessions.
|
|
165
|
+
* @default true
|
|
166
|
+
*/
|
|
167
|
+
useWebsocket?: boolean;
|
|
165
168
|
|
|
166
169
|
/**
|
|
167
170
|
* (Optional) Client-side crash buffer configuration.
|
|
@@ -169,11 +172,11 @@ export interface SessionRecorderOptions {
|
|
|
169
172
|
* even if the user did not start a manual/continuous recording.
|
|
170
173
|
*/
|
|
171
174
|
buffering?: {
|
|
172
|
-
/** Enable/disable buffering. @default
|
|
173
|
-
enabled?: boolean
|
|
174
|
-
/** Rolling window size (minutes). @default
|
|
175
|
-
windowMinutes?: number
|
|
176
|
-
}
|
|
175
|
+
/** Enable/disable buffering. @default false */
|
|
176
|
+
enabled?: boolean;
|
|
177
|
+
/** Rolling window size (minutes). @default 0.5 */
|
|
178
|
+
windowMinutes?: number;
|
|
179
|
+
};
|
|
177
180
|
}
|
|
178
181
|
|
|
179
182
|
/**
|
|
@@ -361,12 +364,6 @@ export interface ISessionRecorder {
|
|
|
361
364
|
* Capture an exception and send it as an error trace
|
|
362
365
|
*/
|
|
363
366
|
captureException(error: unknown, errorInfo?: Record<string, any>): void;
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Flush the local crash buffer by creating a debug session and uploading buffered data.
|
|
367
|
-
* No-op if a live recording is currently active.
|
|
368
|
-
*/
|
|
369
|
-
flushBuffer(payload?: { reason?: string }): Promise<any>;
|
|
370
367
|
}
|
|
371
368
|
|
|
372
369
|
/**
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Dimensions } from 'react-native';
|
|
2
2
|
import {
|
|
3
|
-
EventType,
|
|
4
|
-
type eventWithTime,
|
|
5
3
|
NodeType,
|
|
6
|
-
|
|
4
|
+
EventType,
|
|
7
5
|
IncrementalSource,
|
|
8
6
|
type mutationData,
|
|
7
|
+
type eventWithTime,
|
|
8
|
+
type serializedNodeWithId,
|
|
9
9
|
} from '@rrweb/types';
|
|
10
10
|
import { getAppMetadata } from './platform';
|
|
11
11
|
|