@multiplayer-app/session-recorder-browser 2.0.81-beta.0 → 2.0.84-beta.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.
@@ -0,0 +1,9 @@
1
+ export declare class Observable<N extends string> {
2
+ protected _observers: Map<N, Set<Function>>;
3
+ on(name: N, f: Function): void;
4
+ once(name: N, f: Function): void;
5
+ off(name: N, f: Function): void;
6
+ emit(name: N, args: any[]): void;
7
+ destroy(): void;
8
+ }
9
+ //# sourceMappingURL=observable.d.ts.map
@@ -0,0 +1,39 @@
1
+ export class Observable {
2
+ constructor() {
3
+ this._observers = new Map();
4
+ }
5
+ on(name, f) {
6
+ let listeners = this._observers.get(name);
7
+ if (!listeners) {
8
+ listeners = new Set();
9
+ this._observers.set(name, listeners);
10
+ }
11
+ listeners.add(f);
12
+ }
13
+ once(name, f) {
14
+ const _f = (...args) => {
15
+ this.off(name, _f);
16
+ f(...args);
17
+ };
18
+ this.on(name, _f);
19
+ }
20
+ off(name, f) {
21
+ const observers = this._observers.get(name);
22
+ if (observers) {
23
+ observers.delete(f);
24
+ if (observers.size === 0) {
25
+ this._observers.delete(name);
26
+ }
27
+ }
28
+ }
29
+ emit(name, args) {
30
+ const listeners = this._observers.get(name);
31
+ if (listeners) {
32
+ Array.from(listeners).forEach((f) => f(...args));
33
+ }
34
+ }
35
+ destroy() {
36
+ this._observers.clear();
37
+ }
38
+ }
39
+ //# sourceMappingURL=observable.js.map
@@ -1,3 +1,6 @@
1
+ import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';
2
+ import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch';
3
+ import { UserInteractionInstrumentation } from '@opentelemetry/instrumentation-user-interaction';
1
4
  import { TracerBrowserConfig } from '../../types';
2
- export declare const getInstrumentations: (config: TracerBrowserConfig) => import("@opentelemetry/instrumentation").Instrumentation<import("@opentelemetry/instrumentation").InstrumentationConfig>[][];
5
+ export declare const getInstrumentations: (config: TracerBrowserConfig) => (XMLHttpRequestInstrumentation | FetchInstrumentation | UserInteractionInstrumentation)[];
3
6
  //# sourceMappingURL=index.d.ts.map
@@ -1,102 +1,102 @@
1
- import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web';
1
+ import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';
2
+ import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch';
3
+ import { UserInteractionInstrumentation } from '@opentelemetry/instrumentation-user-interaction';
2
4
  import { headersToObject, processHttpPayload, extractResponseBody, getElementInnerText, getElementTextContent, } from '../helpers';
3
5
  import { OTEL_IGNORE_URLS } from '../../config';
4
6
  export const getInstrumentations = (config) => {
5
7
  return [
6
- getWebAutoInstrumentations({
7
- '@opentelemetry/instrumentation-xml-http-request': {
8
- clearTimingResources: true,
9
- ignoreUrls: [...OTEL_IGNORE_URLS, ...(config.ignoreUrls || [])],
10
- propagateTraceHeaderCorsUrls: config.propagateTraceHeaderCorsUrls,
11
- applyCustomAttributesOnSpan: (span, xhr) => {
12
- if (!config)
8
+ new XMLHttpRequestInstrumentation({
9
+ clearTimingResources: true,
10
+ ignoreUrls: [...OTEL_IGNORE_URLS, ...(config.ignoreUrls || [])],
11
+ propagateTraceHeaderCorsUrls: config.propagateTraceHeaderCorsUrls,
12
+ applyCustomAttributesOnSpan: (span, xhr) => {
13
+ if (!config)
14
+ return;
15
+ const { captureBody, captureHeaders } = config;
16
+ try {
17
+ if (!captureBody && !captureHeaders) {
13
18
  return;
14
- const { captureBody, captureHeaders } = config;
15
- try {
16
- if (!captureBody && !captureHeaders) {
17
- return;
18
- }
19
- // @ts-ignore
20
- const networkRequest = xhr.networkRequest;
21
- const requestBody = networkRequest.requestBody;
22
- const responseBody = networkRequest.responseBody;
23
- const requestHeaders = networkRequest.requestHeaders || {};
24
- const responseHeaders = networkRequest.responseHeaders || {};
25
- const payload = {
26
- requestBody,
27
- responseBody,
28
- requestHeaders,
29
- responseHeaders,
30
- };
31
- processHttpPayload(payload, config, span);
32
- }
33
- catch (error) {
34
- // eslint-disable-next-line
35
- console.error('[MULTIPLAYER_SESSION_RECORDER] Failed to capture xml-http payload', error);
36
19
  }
37
- },
20
+ // @ts-ignore
21
+ const networkRequest = xhr.networkRequest;
22
+ const requestBody = networkRequest.requestBody;
23
+ const responseBody = networkRequest.responseBody;
24
+ const requestHeaders = networkRequest.requestHeaders || {};
25
+ const responseHeaders = networkRequest.responseHeaders || {};
26
+ const payload = {
27
+ requestBody,
28
+ responseBody,
29
+ requestHeaders,
30
+ responseHeaders,
31
+ };
32
+ processHttpPayload(payload, config, span);
33
+ }
34
+ catch (error) {
35
+ // eslint-disable-next-line
36
+ console.error('[MULTIPLAYER_SESSION_RECORDER] Failed to capture xml-http payload', error);
37
+ }
38
38
  },
39
- '@opentelemetry/instrumentation-fetch': {
40
- clearTimingResources: true,
41
- ignoreUrls: [...OTEL_IGNORE_URLS, ...(config.ignoreUrls || [])],
42
- propagateTraceHeaderCorsUrls: config.propagateTraceHeaderCorsUrls,
43
- applyCustomAttributesOnSpan: async (span, request, response) => {
44
- if (!config)
39
+ }),
40
+ new FetchInstrumentation({
41
+ clearTimingResources: true,
42
+ ignoreUrls: [...OTEL_IGNORE_URLS, ...(config.ignoreUrls || [])],
43
+ propagateTraceHeaderCorsUrls: config.propagateTraceHeaderCorsUrls,
44
+ applyCustomAttributesOnSpan: async (span, request, response) => {
45
+ if (!config)
46
+ return;
47
+ const { captureBody, captureHeaders } = config;
48
+ try {
49
+ if (!captureBody && !captureHeaders) {
45
50
  return;
46
- const { captureBody, captureHeaders } = config;
47
- try {
48
- if (!captureBody && !captureHeaders) {
49
- return;
50
- }
51
- // Try to get data from our fetch wrapper first
52
- // @ts-ignore
53
- const networkRequest = response === null || response === void 0 ? void 0 : response.networkRequest;
54
- let requestBody = null;
55
- let responseBody = null;
56
- let requestHeaders = {};
57
- let responseHeaders = {};
58
- if (networkRequest) {
59
- // Use data captured by our fetch wrapper
60
- requestBody = networkRequest.requestBody;
61
- responseBody = networkRequest.responseBody;
62
- requestHeaders = networkRequest.requestHeaders || {};
63
- responseHeaders = networkRequest.responseHeaders || {};
64
- }
65
- else {
66
- // Fallback to original OpenTelemetry approach
67
- requestBody = request.body;
68
- requestHeaders = headersToObject(request.headers);
69
- responseHeaders = headersToObject(response instanceof Response ? response.headers : undefined);
70
- if (response instanceof Response && response.body) {
71
- responseBody = await extractResponseBody(response);
72
- }
73
- }
74
- const payload = {
75
- requestBody,
76
- responseBody,
77
- requestHeaders,
78
- responseHeaders,
79
- };
80
- processHttpPayload(payload, config, span);
81
51
  }
82
- catch (error) {
83
- // eslint-disable-next-line
84
- console.error('[MULTIPLAYER_SESSION_RECORDER] Failed to capture fetch payload', error);
52
+ // Try to get data from our fetch wrapper first
53
+ // @ts-ignore
54
+ const networkRequest = response === null || response === void 0 ? void 0 : response.networkRequest;
55
+ let requestBody = null;
56
+ let responseBody = null;
57
+ let requestHeaders = {};
58
+ let responseHeaders = {};
59
+ if (networkRequest) {
60
+ // Use data captured by our fetch wrapper
61
+ requestBody = networkRequest.requestBody;
62
+ responseBody = networkRequest.responseBody;
63
+ requestHeaders = networkRequest.requestHeaders || {};
64
+ responseHeaders = networkRequest.responseHeaders || {};
85
65
  }
86
- },
87
- },
88
- '@opentelemetry/instrumentation-user-interaction': {
89
- shouldPreventSpanCreation: (_event, element, span) => {
90
- if (span['parentSpanContext']) {
91
- return true;
66
+ else {
67
+ // Fallback to original OpenTelemetry approach
68
+ requestBody = request.body;
69
+ requestHeaders = headersToObject(request.headers);
70
+ responseHeaders = headersToObject(response instanceof Response ? response.headers : undefined);
71
+ if (response instanceof Response && response.body) {
72
+ responseBody = await extractResponseBody(response);
73
+ }
92
74
  }
93
- span.setAttribute('target.innerText', getElementInnerText(element));
94
- span.setAttribute('target.textContent', getElementTextContent(element));
95
- Array.from(element.attributes).forEach((attribute) => {
96
- span.setAttribute(`target.attribute.${attribute.name}`, attribute.value);
97
- });
98
- return false;
99
- },
75
+ const payload = {
76
+ requestBody,
77
+ responseBody,
78
+ requestHeaders,
79
+ responseHeaders,
80
+ };
81
+ processHttpPayload(payload, config, span);
82
+ }
83
+ catch (error) {
84
+ // eslint-disable-next-line
85
+ console.error('[MULTIPLAYER_SESSION_RECORDER] Failed to capture fetch payload', error);
86
+ }
87
+ },
88
+ }),
89
+ new UserInteractionInstrumentation({
90
+ shouldPreventSpanCreation: (_event, element, span) => {
91
+ if (span['parentSpanContext']) {
92
+ return true;
93
+ }
94
+ span.setAttribute('target.innerText', getElementInnerText(element));
95
+ span.setAttribute('target.textContent', getElementTextContent(element));
96
+ Array.from(element.attributes).forEach((attribute) => {
97
+ span.setAttribute(`target.attribute.${attribute.name}`, attribute.value);
98
+ });
99
+ return false;
100
100
  },
101
101
  }),
102
102
  ];
@@ -1,4 +1,4 @@
1
- import { Observable } from 'lib0/observable';
1
+ import { Observable } from '../observable';
2
2
  import { SESSION_AUTO_CREATED, SESSION_STOPPED_EVENT, REMOTE_SESSION_RECORDING_START, REMOTE_SESSION_RECORDING_STOP, SESSION_SAVE_BUFFER_EVENT } from '../config';
3
3
  import { type ISession, type IUserAttributes } from '@multiplayer-app/session-recorder-common';
4
4
  export type SocketServiceEvents = typeof SESSION_STOPPED_EVENT | typeof SESSION_AUTO_CREATED | typeof REMOTE_SESSION_RECORDING_START | typeof REMOTE_SESSION_RECORDING_STOP | typeof SESSION_SAVE_BUFFER_EVENT;
@@ -1,5 +1,5 @@
1
1
  import io from 'socket.io-client';
2
- import { Observable } from 'lib0/observable';
2
+ import { Observable } from '../observable';
3
3
  import messagingService from '../services/messaging.service';
4
4
  import { SESSION_ADD_EVENT, SESSION_AUTO_CREATED, SESSION_STOPPED_EVENT, SESSION_SUBSCRIBE_EVENT, SESSION_UNSUBSCRIBE_EVENT, SOCKET_SET_USER_EVENT, REMOTE_SESSION_RECORDING_START, REMOTE_SESSION_RECORDING_STOP, SESSION_STARTED_EVENT, SESSION_SAVE_BUFFER_EVENT, } from '../config';
5
5
  import { ATTR_MULTIPLAYER_SESSION_CLIENT_ID, } from '@multiplayer-app/session-recorder-common';
@@ -1,4 +1,4 @@
1
- import { Observable } from 'lib0/observable';
1
+ import { Observable } from './observable';
2
2
  import { SessionType, type ISession, type IUserAttributes } from '@multiplayer-app/session-recorder-common';
3
3
  import { SessionState, SessionRecorderOptions, SessionRecorderEvents } from './types';
4
4
  import { ISessionRecorder } from './types';
@@ -1,4 +1,4 @@
1
- import { Observable } from 'lib0/observable';
1
+ import { Observable } from './observable';
2
2
  import { SessionType } from '@multiplayer-app/session-recorder-common';
3
3
  import { TracerBrowserSDK } from './otel';
4
4
  import { RecorderBrowserSDK } from './rrweb';
@@ -1,4 +1,4 @@
1
- import { Observable } from 'lib0/observable';
1
+ import { Observable } from '../observable';
2
2
  import { SessionWidgetConfig, SessionState, ToastConfig } from '../types';
3
3
  import { ButtonState, ContinuousRecordingSaveButtonState } from './buttonStateConfigs';
4
4
  import './styles/button.scss';
@@ -1,4 +1,4 @@
1
- import { Observable } from 'lib0/observable';
1
+ import { Observable } from '../observable';
2
2
  import { insertTrustedHTML, injectStylesIntoShadowRoot, formatTimeForSessionTimer } from '../utils';
3
3
  import { SessionState } from '../types';
4
4
  import { POPOVER_WIDTH, NON_DRAGGABLE_OFFSET, POPOVER_DISTANCE_FROM_BUTTON, } from './constants';
@@ -4,7 +4,7 @@ import { PropagateTraceHeaderCorsUrls } from '@opentelemetry/sdk-trace-web';
4
4
  import type { MaskTextFn, MaskInputFn, MaskInputOptions } from 'rrweb-snapshot';
5
5
  import type { maskTextClass } from '@rrweb/types';
6
6
  import { LogData } from '@rrweb/rrweb-plugin-console-record';
7
- import { Observable } from 'lib0/observable';
7
+ import { Observable } from '../observable';
8
8
  import type { NavigationRecorderPublicApi } from '../navigation';
9
9
  export declare enum WidgetButtonPlacement {
10
10
  topLeft = "top-left",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multiplayer-app/session-recorder-browser",
3
- "version": "2.0.81-beta.0",
3
+ "version": "2.0.84-beta.0",
4
4
  "description": "Multiplayer Fullstack Session Recorder for Browser",
5
5
  "author": {
6
6
  "name": "Multiplayer Software, Inc.",
@@ -28,9 +28,7 @@
28
28
  "types": "./dist/index.d.ts",
29
29
  "import": "./dist/index.js",
30
30
  "require": "./dist/index.umd.js"
31
- },
32
- "./browser": "./dist/browser/index.js",
33
- "./exporters": "./dist/exporters/index.js"
31
+ }
34
32
  },
35
33
  "engines": {
36
34
  "node": ">=18",
@@ -50,8 +48,12 @@
50
48
  "lint": "eslint 'src/**/*.ts' --config eslint.config.js",
51
49
  "preversion": "npm run lint",
52
50
  "postversion:skip": "git push && git push --tags",
53
- "build": "rm -rf dist tsconfig.tsbuildinfo && tsc && webpack",
54
- "prepublishOnly": "npm run build"
51
+ "build": "rm -rf dist tsconfig.tsbuildinfo && tsc && webpack --config-name esm --config-name umd && node scripts/sync-exports.js",
52
+ "build:browser": "webpack --config-name browser && node scripts/sync-exports.js",
53
+ "build:exporters": "webpack --config-name exporters && node scripts/sync-exports.js",
54
+ "build:extras": "webpack --config-name browser --config-name exporters && node scripts/sync-exports.js",
55
+ "build:all": "rm -rf dist tsconfig.tsbuildinfo && tsc && webpack && node scripts/sync-exports.js",
56
+ "prepublishOnly": "npm run build:all"
55
57
  },
56
58
  "devDependencies": {
57
59
  "@types/node": "^22.0.0",
@@ -71,12 +73,13 @@
71
73
  "webpack-cli": "5.1.4"
72
74
  },
73
75
  "dependencies": {
74
- "@multiplayer-app/session-recorder-common": "2.0.81-beta.0",
75
- "@opentelemetry/auto-instrumentations-web": "0.49.0",
76
- "@opentelemetry/context-zone": "2.0.1",
76
+ "@multiplayer-app/session-recorder-common": "2.0.84-beta.0",
77
77
  "@opentelemetry/core": "2.0.1",
78
78
  "@opentelemetry/exporter-trace-otlp-http": "0.203.0",
79
79
  "@opentelemetry/instrumentation": "0.203.0",
80
+ "@opentelemetry/instrumentation-fetch": "0.203.0",
81
+ "@opentelemetry/instrumentation-user-interaction": "0.48.1",
82
+ "@opentelemetry/instrumentation-xml-http-request": "0.203.0",
80
83
  "@opentelemetry/otlp-exporter-base": "0.203.0",
81
84
  "@opentelemetry/otlp-transformer": "0.203.0",
82
85
  "@opentelemetry/resources": "2.0.1",
@@ -86,7 +89,6 @@
86
89
  "@rrweb/packer": "2.0.0-alpha.20",
87
90
  "@rrweb/rrweb-plugin-console-record": "2.0.0-alpha.20",
88
91
  "dompurify": "^3.4.2",
89
- "lib0": "0.2.82",
90
92
  "rrweb": "2.0.0-alpha.20",
91
93
  "socket.io-client": "4.7.5",
92
94
  "to-json-schema": "^0.2.5"