@openreplay/tracker 9.0.4 → 9.0.6

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 CHANGED
@@ -1,3 +1,11 @@
1
+ # 9.0.6
2
+
3
+ - added `tokenUrlMatcher` option to network settings, allowing to ingest session token header to custom allowed urls
4
+
5
+ # 9.0.5
6
+
7
+ - same fixes but for fetch proxy
8
+
1
9
  # 9.0.2 & 9.0.3 & 9.0.4
2
10
 
3
11
  - fixes for "setSessionTokenHeader" method
package/cjs/app/index.js CHANGED
@@ -24,6 +24,13 @@ var ActivityState;
24
24
  })(ActivityState || (ActivityState = {}));
25
25
  // TODO: use backendHost only
26
26
  exports.DEFAULT_INGEST_POINT = 'https://api.openreplay.com/ingest';
27
+ function getTimezone() {
28
+ const offset = new Date().getTimezoneOffset() * -1;
29
+ const sign = offset >= 0 ? '+' : '-';
30
+ const hours = Math.floor(Math.abs(offset) / 60);
31
+ const minutes = Math.abs(offset) % 60;
32
+ return `UTC${sign}${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;
33
+ }
27
34
  class App {
28
35
  constructor(projectKey, sessionToken, options) {
29
36
  // if (options.onStart !== undefined) {
@@ -35,7 +42,7 @@ class App {
35
42
  this.stopCallbacks = [];
36
43
  this.commitCallbacks = [];
37
44
  this.activityState = ActivityState.NotActive;
38
- this.version = '9.0.4'; // TODO: version compatability check inside each plugin.
45
+ this.version = '9.0.6'; // TODO: version compatability check inside each plugin.
39
46
  this.compressionThreshold = 24 * 1000;
40
47
  this.restartAttempts = 0;
41
48
  this.bc = null;
@@ -394,7 +401,7 @@ class App {
394
401
  'Content-Type': 'application/json',
395
402
  },
396
403
  body: JSON.stringify(Object.assign(Object.assign({}, this.getTrackerInfo()), { timestamp, userID: this.session.getInfo().userID, token: isNewSession ? undefined : sessionToken, deviceMemory: performance_js_1.deviceMemory,
397
- jsHeapSizeLimit: performance_js_1.jsHeapSizeLimit })),
404
+ jsHeapSizeLimit: performance_js_1.jsHeapSizeLimit, timezone: getTimezone() })),
398
405
  })
399
406
  .then((r) => {
400
407
  if (r.status === 200) {
package/cjs/index.js CHANGED
@@ -153,7 +153,7 @@ class API {
153
153
  // no-cors issue only with text/plain or not-set Content-Type
154
154
  // req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
155
155
  req.send(JSON.stringify({
156
- trackerVersion: '9.0.4',
156
+ trackerVersion: '9.0.6',
157
157
  projectKey: options.projectKey,
158
158
  doNotTrack,
159
159
  // TODO: add precise reason (an exact API missing)
@@ -22,7 +22,8 @@ export declare class FetchProxyHandler<T extends typeof fetch> implements ProxyH
22
22
  private readonly sanitize;
23
23
  private readonly sendMessage;
24
24
  private readonly isServiceUrl;
25
- constructor(ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (item: NetworkRequest) => void, isServiceUrl: (url: string) => boolean);
25
+ private readonly tokenUrlMatcher?;
26
+ constructor(ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (item: NetworkRequest) => void, isServiceUrl: (url: string) => boolean, tokenUrlMatcher?: ((url: string) => boolean) | undefined);
26
27
  apply(target: T, _: typeof window, argsList: [RequestInfo | URL, RequestInit]): any;
27
28
  protected beforeFetch(item: NetworkMessage, input: RequestInfo, init?: RequestInit): void;
28
29
  protected afterFetch(item: NetworkMessage): (resp: Response) => Response;
@@ -30,5 +31,5 @@ export declare class FetchProxyHandler<T extends typeof fetch> implements ProxyH
30
31
  }
31
32
  export default class FetchProxy {
32
33
  static origFetch: typeof fetch;
33
- static create(ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (item: NetworkRequest) => void, isServiceUrl: (url: string) => boolean): typeof fetch;
34
+ static create(ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (item: NetworkRequest) => void, isServiceUrl: (url: string) => boolean, tokenUrlMatcher?: (url: string) => boolean): typeof fetch;
34
35
  }
@@ -106,12 +106,13 @@ class ResponseProxyHandler {
106
106
  }
107
107
  exports.ResponseProxyHandler = ResponseProxyHandler;
108
108
  class FetchProxyHandler {
109
- constructor(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl) {
109
+ constructor(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher) {
110
110
  this.ignoredHeaders = ignoredHeaders;
111
111
  this.setSessionTokenHeader = setSessionTokenHeader;
112
112
  this.sanitize = sanitize;
113
113
  this.sendMessage = sendMessage;
114
114
  this.isServiceUrl = isServiceUrl;
115
+ this.tokenUrlMatcher = tokenUrlMatcher;
115
116
  }
116
117
  apply(target, _, argsList) {
117
118
  const input = argsList[0];
@@ -125,12 +126,19 @@ class FetchProxyHandler {
125
126
  const item = new networkMessage_js_1.default(this.ignoredHeaders, this.setSessionTokenHeader, this.sanitize);
126
127
  this.beforeFetch(item, input, init);
127
128
  this.setSessionTokenHeader((name, value) => {
129
+ if (this.tokenUrlMatcher !== undefined) {
130
+ if (!this.tokenUrlMatcher(item.url)) {
131
+ return;
132
+ }
133
+ }
128
134
  if (argsList[1] === undefined && argsList[0] instanceof Request) {
129
135
  return argsList[0].headers.append(name, value);
130
136
  }
131
137
  else {
138
+ if (!argsList[1])
139
+ argsList[1] = {};
132
140
  if (argsList[1].headers === undefined) {
133
- argsList[1].headers = {};
141
+ argsList[1] = Object.assign(Object.assign({}, argsList[1]), { headers: {} });
134
142
  }
135
143
  if (argsList[1].headers instanceof Headers) {
136
144
  argsList[1].headers.append(name, value);
@@ -139,6 +147,7 @@ class FetchProxyHandler {
139
147
  argsList[1].headers.push([name, value]);
140
148
  }
141
149
  else {
150
+ // @ts-ignore
142
151
  argsList[1].headers[name] = value;
143
152
  }
144
153
  }
@@ -253,8 +262,8 @@ class FetchProxyHandler {
253
262
  }
254
263
  exports.FetchProxyHandler = FetchProxyHandler;
255
264
  class FetchProxy {
256
- static create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl) {
257
- return new Proxy(fetch, new FetchProxyHandler(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl));
265
+ static create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher) {
266
+ return new Proxy(fetch, new FetchProxyHandler(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher));
258
267
  }
259
268
  }
260
269
  exports.default = FetchProxy;
@@ -1,3 +1,3 @@
1
1
  import { RequestResponseData } from './types.js';
2
2
  import { NetworkRequest } from '../../common/messages.gen.js';
3
- export default function setProxy(context: typeof globalThis, ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (message: NetworkRequest) => void, isServiceUrl: (url: string) => boolean): void;
3
+ export default function setProxy(context: typeof globalThis, ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (message: NetworkRequest) => void, isServiceUrl: (url: string) => boolean, tokenUrlMatcher?: (url: string) => boolean): void;
@@ -4,15 +4,15 @@ const fetchProxy_js_1 = require("./fetchProxy.js");
4
4
  const xhrProxy_js_1 = require("./xhrProxy.js");
5
5
  const getWarning = (api) => console.warn(`Openreplay: Can't find ${api} in global context.
6
6
  If you're using serverside rendering in your app, make sure that tracker is loaded dynamically, otherwise ${api} won't be tracked.`);
7
- function setProxy(context, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl) {
7
+ function setProxy(context, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher) {
8
8
  if (context.XMLHttpRequest) {
9
- context.XMLHttpRequest = xhrProxy_js_1.default.create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl);
9
+ context.XMLHttpRequest = xhrProxy_js_1.default.create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher);
10
10
  }
11
11
  else {
12
12
  getWarning('XMLHttpRequest');
13
13
  }
14
14
  if (context.fetch) {
15
- context.fetch = fetchProxy_js_1.default.create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl);
15
+ context.fetch = fetchProxy_js_1.default.create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher);
16
16
  }
17
17
  else {
18
18
  getWarning('fetch');
@@ -14,9 +14,10 @@ export declare class XHRProxyHandler<T extends XMLHttpRequest> implements ProxyH
14
14
  private readonly sanitize;
15
15
  private readonly sendMessage;
16
16
  private readonly isServiceUrl;
17
+ private readonly tokenUrlMatcher?;
17
18
  XMLReq: XMLHttpRequest;
18
19
  item: NetworkMessage;
19
- constructor(XMLReq: XMLHttpRequest, ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (message: NetworkRequest) => void, isServiceUrl: (url: string) => boolean);
20
+ constructor(XMLReq: XMLHttpRequest, ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (message: NetworkRequest) => void, isServiceUrl: (url: string) => boolean, tokenUrlMatcher?: ((url: string) => boolean) | undefined);
20
21
  get(target: T, key: string): any;
21
22
  set(target: T, key: string, value: (args: any[]) => any): boolean;
22
23
  onReadyStateChange(): void;
@@ -43,5 +44,5 @@ export default class XHRProxy {
43
44
  readonly OPENED: number;
44
45
  readonly UNSENT: number;
45
46
  };
46
- static create(ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (data: NetworkRequest) => void, isServiceUrl: (url: string) => boolean): any;
47
+ static create(ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (data: NetworkRequest) => void, isServiceUrl: (url: string) => boolean, tokenUrlMatcher?: (url: string) => boolean): any;
47
48
  }
@@ -11,12 +11,13 @@ exports.XHRProxyHandler = void 0;
11
11
  const networkMessage_js_1 = require("./networkMessage.js");
12
12
  const utils_js_1 = require("./utils.js");
13
13
  class XHRProxyHandler {
14
- constructor(XMLReq, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl) {
14
+ constructor(XMLReq, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher) {
15
15
  this.ignoredHeaders = ignoredHeaders;
16
16
  this.setSessionTokenHeader = setSessionTokenHeader;
17
17
  this.sanitize = sanitize;
18
18
  this.sendMessage = sendMessage;
19
19
  this.isServiceUrl = isServiceUrl;
20
+ this.tokenUrlMatcher = tokenUrlMatcher;
20
21
  this.XMLReq = XMLReq;
21
22
  this.XMLReq.onreadystatechange = () => {
22
23
  this.onReadyStateChange();
@@ -36,6 +37,11 @@ class XHRProxyHandler {
36
37
  return this.getOpen(target);
37
38
  case 'send':
38
39
  this.setSessionTokenHeader((name, value) => {
40
+ if (this.tokenUrlMatcher !== undefined) {
41
+ if (!this.tokenUrlMatcher(this.item.url)) {
42
+ return;
43
+ }
44
+ }
39
45
  target.setRequestHeader(name, value);
40
46
  });
41
47
  return this.getSend(target);
@@ -199,11 +205,11 @@ class XHRProxyHandler {
199
205
  }
200
206
  exports.XHRProxyHandler = XHRProxyHandler;
201
207
  class XHRProxy {
202
- static create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl) {
208
+ static create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher) {
203
209
  return new Proxy(XMLHttpRequest, {
204
210
  construct(original) {
205
211
  const XMLReq = new original();
206
- return new Proxy(XMLReq, new XHRProxyHandler(XMLReq, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl));
212
+ return new Proxy(XMLReq, new XHRProxyHandler(XMLReq, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher));
207
213
  },
208
214
  });
209
215
  }
@@ -25,6 +25,7 @@ export interface Options {
25
25
  sanitizer?: Sanitizer;
26
26
  axiosInstances?: Array<AxiosInstance>;
27
27
  useProxy?: boolean;
28
+ tokenUrlMatcher?: (url: string) => boolean;
28
29
  }
29
30
  export default function (app: App, opts?: Partial<Options>): void;
30
31
  export {};
@@ -76,7 +76,7 @@ function default_1(app, opts = {}) {
76
76
  const patchWindow = (context) => {
77
77
  /* ====== modern way ====== */
78
78
  if (options.useProxy) {
79
- return (0, index_js_1.default)(context, options.ignoreHeaders, setSessionTokenHeader, sanitize, (message) => app.send(message), (url) => app.isServiceURL(url));
79
+ return (0, index_js_1.default)(context, options.ignoreHeaders, setSessionTokenHeader, sanitize, (message) => app.send(message), (url) => app.isServiceURL(url), options.tokenUrlMatcher);
80
80
  }
81
81
  /* ====== Fetch ====== */
82
82
  const origFetch = context.fetch.bind(context);
package/lib/app/index.js CHANGED
@@ -21,6 +21,13 @@ var ActivityState;
21
21
  })(ActivityState || (ActivityState = {}));
22
22
  // TODO: use backendHost only
23
23
  export const DEFAULT_INGEST_POINT = 'https://api.openreplay.com/ingest';
24
+ function getTimezone() {
25
+ const offset = new Date().getTimezoneOffset() * -1;
26
+ const sign = offset >= 0 ? '+' : '-';
27
+ const hours = Math.floor(Math.abs(offset) / 60);
28
+ const minutes = Math.abs(offset) % 60;
29
+ return `UTC${sign}${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;
30
+ }
24
31
  export default class App {
25
32
  constructor(projectKey, sessionToken, options) {
26
33
  // if (options.onStart !== undefined) {
@@ -32,7 +39,7 @@ export default class App {
32
39
  this.stopCallbacks = [];
33
40
  this.commitCallbacks = [];
34
41
  this.activityState = ActivityState.NotActive;
35
- this.version = '9.0.4'; // TODO: version compatability check inside each plugin.
42
+ this.version = '9.0.6'; // TODO: version compatability check inside each plugin.
36
43
  this.compressionThreshold = 24 * 1000;
37
44
  this.restartAttempts = 0;
38
45
  this.bc = null;
@@ -391,7 +398,7 @@ export default class App {
391
398
  'Content-Type': 'application/json',
392
399
  },
393
400
  body: JSON.stringify(Object.assign(Object.assign({}, this.getTrackerInfo()), { timestamp, userID: this.session.getInfo().userID, token: isNewSession ? undefined : sessionToken, deviceMemory,
394
- jsHeapSizeLimit })),
401
+ jsHeapSizeLimit, timezone: getTimezone() })),
395
402
  })
396
403
  .then((r) => {
397
404
  if (r.status === 200) {
package/lib/index.js CHANGED
@@ -148,7 +148,7 @@ export default class API {
148
148
  // no-cors issue only with text/plain or not-set Content-Type
149
149
  // req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
150
150
  req.send(JSON.stringify({
151
- trackerVersion: '9.0.4',
151
+ trackerVersion: '9.0.6',
152
152
  projectKey: options.projectKey,
153
153
  doNotTrack,
154
154
  // TODO: add precise reason (an exact API missing)
@@ -22,7 +22,8 @@ export declare class FetchProxyHandler<T extends typeof fetch> implements ProxyH
22
22
  private readonly sanitize;
23
23
  private readonly sendMessage;
24
24
  private readonly isServiceUrl;
25
- constructor(ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (item: NetworkRequest) => void, isServiceUrl: (url: string) => boolean);
25
+ private readonly tokenUrlMatcher?;
26
+ constructor(ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (item: NetworkRequest) => void, isServiceUrl: (url: string) => boolean, tokenUrlMatcher?: ((url: string) => boolean) | undefined);
26
27
  apply(target: T, _: typeof window, argsList: [RequestInfo | URL, RequestInit]): any;
27
28
  protected beforeFetch(item: NetworkMessage, input: RequestInfo, init?: RequestInit): void;
28
29
  protected afterFetch(item: NetworkMessage): (resp: Response) => Response;
@@ -30,5 +31,5 @@ export declare class FetchProxyHandler<T extends typeof fetch> implements ProxyH
30
31
  }
31
32
  export default class FetchProxy {
32
33
  static origFetch: typeof fetch;
33
- static create(ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (item: NetworkRequest) => void, isServiceUrl: (url: string) => boolean): typeof fetch;
34
+ static create(ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (item: NetworkRequest) => void, isServiceUrl: (url: string) => boolean, tokenUrlMatcher?: (url: string) => boolean): typeof fetch;
34
35
  }
@@ -102,12 +102,13 @@ export class ResponseProxyHandler {
102
102
  }
103
103
  }
104
104
  export class FetchProxyHandler {
105
- constructor(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl) {
105
+ constructor(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher) {
106
106
  this.ignoredHeaders = ignoredHeaders;
107
107
  this.setSessionTokenHeader = setSessionTokenHeader;
108
108
  this.sanitize = sanitize;
109
109
  this.sendMessage = sendMessage;
110
110
  this.isServiceUrl = isServiceUrl;
111
+ this.tokenUrlMatcher = tokenUrlMatcher;
111
112
  }
112
113
  apply(target, _, argsList) {
113
114
  const input = argsList[0];
@@ -121,12 +122,19 @@ export class FetchProxyHandler {
121
122
  const item = new NetworkMessage(this.ignoredHeaders, this.setSessionTokenHeader, this.sanitize);
122
123
  this.beforeFetch(item, input, init);
123
124
  this.setSessionTokenHeader((name, value) => {
125
+ if (this.tokenUrlMatcher !== undefined) {
126
+ if (!this.tokenUrlMatcher(item.url)) {
127
+ return;
128
+ }
129
+ }
124
130
  if (argsList[1] === undefined && argsList[0] instanceof Request) {
125
131
  return argsList[0].headers.append(name, value);
126
132
  }
127
133
  else {
134
+ if (!argsList[1])
135
+ argsList[1] = {};
128
136
  if (argsList[1].headers === undefined) {
129
- argsList[1].headers = {};
137
+ argsList[1] = Object.assign(Object.assign({}, argsList[1]), { headers: {} });
130
138
  }
131
139
  if (argsList[1].headers instanceof Headers) {
132
140
  argsList[1].headers.append(name, value);
@@ -135,6 +143,7 @@ export class FetchProxyHandler {
135
143
  argsList[1].headers.push([name, value]);
136
144
  }
137
145
  else {
146
+ // @ts-ignore
138
147
  argsList[1].headers[name] = value;
139
148
  }
140
149
  }
@@ -248,8 +257,8 @@ export class FetchProxyHandler {
248
257
  }
249
258
  }
250
259
  export default class FetchProxy {
251
- static create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl) {
252
- return new Proxy(fetch, new FetchProxyHandler(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl));
260
+ static create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher) {
261
+ return new Proxy(fetch, new FetchProxyHandler(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher));
253
262
  }
254
263
  }
255
264
  FetchProxy.origFetch = fetch;
@@ -1,3 +1,3 @@
1
1
  import { RequestResponseData } from './types.js';
2
2
  import { NetworkRequest } from '../../common/messages.gen.js';
3
- export default function setProxy(context: typeof globalThis, ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (message: NetworkRequest) => void, isServiceUrl: (url: string) => boolean): void;
3
+ export default function setProxy(context: typeof globalThis, ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (message: NetworkRequest) => void, isServiceUrl: (url: string) => boolean, tokenUrlMatcher?: (url: string) => boolean): void;
@@ -2,15 +2,15 @@ import FetchProxy from './fetchProxy.js';
2
2
  import XHRProxy from './xhrProxy.js';
3
3
  const getWarning = (api) => console.warn(`Openreplay: Can't find ${api} in global context.
4
4
  If you're using serverside rendering in your app, make sure that tracker is loaded dynamically, otherwise ${api} won't be tracked.`);
5
- export default function setProxy(context, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl) {
5
+ export default function setProxy(context, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher) {
6
6
  if (context.XMLHttpRequest) {
7
- context.XMLHttpRequest = XHRProxy.create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl);
7
+ context.XMLHttpRequest = XHRProxy.create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher);
8
8
  }
9
9
  else {
10
10
  getWarning('XMLHttpRequest');
11
11
  }
12
12
  if (context.fetch) {
13
- context.fetch = FetchProxy.create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl);
13
+ context.fetch = FetchProxy.create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher);
14
14
  }
15
15
  else {
16
16
  getWarning('fetch');
@@ -14,9 +14,10 @@ export declare class XHRProxyHandler<T extends XMLHttpRequest> implements ProxyH
14
14
  private readonly sanitize;
15
15
  private readonly sendMessage;
16
16
  private readonly isServiceUrl;
17
+ private readonly tokenUrlMatcher?;
17
18
  XMLReq: XMLHttpRequest;
18
19
  item: NetworkMessage;
19
- constructor(XMLReq: XMLHttpRequest, ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (message: NetworkRequest) => void, isServiceUrl: (url: string) => boolean);
20
+ constructor(XMLReq: XMLHttpRequest, ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (message: NetworkRequest) => void, isServiceUrl: (url: string) => boolean, tokenUrlMatcher?: ((url: string) => boolean) | undefined);
20
21
  get(target: T, key: string): any;
21
22
  set(target: T, key: string, value: (args: any[]) => any): boolean;
22
23
  onReadyStateChange(): void;
@@ -43,5 +44,5 @@ export default class XHRProxy {
43
44
  readonly OPENED: number;
44
45
  readonly UNSENT: number;
45
46
  };
46
- static create(ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (data: NetworkRequest) => void, isServiceUrl: (url: string) => boolean): any;
47
+ static create(ignoredHeaders: boolean | string[], setSessionTokenHeader: (cb: (name: string, value: string) => void) => void, sanitize: (data: RequestResponseData) => RequestResponseData, sendMessage: (data: NetworkRequest) => void, isServiceUrl: (url: string) => boolean, tokenUrlMatcher?: (url: string) => boolean): any;
47
48
  }
@@ -8,12 +8,13 @@
8
8
  import NetworkMessage, { RequestState } from './networkMessage.js';
9
9
  import { genGetDataByUrl, formatByteSize, genStringBody, getStringResponseByType } from './utils.js';
10
10
  export class XHRProxyHandler {
11
- constructor(XMLReq, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl) {
11
+ constructor(XMLReq, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher) {
12
12
  this.ignoredHeaders = ignoredHeaders;
13
13
  this.setSessionTokenHeader = setSessionTokenHeader;
14
14
  this.sanitize = sanitize;
15
15
  this.sendMessage = sendMessage;
16
16
  this.isServiceUrl = isServiceUrl;
17
+ this.tokenUrlMatcher = tokenUrlMatcher;
17
18
  this.XMLReq = XMLReq;
18
19
  this.XMLReq.onreadystatechange = () => {
19
20
  this.onReadyStateChange();
@@ -33,6 +34,11 @@ export class XHRProxyHandler {
33
34
  return this.getOpen(target);
34
35
  case 'send':
35
36
  this.setSessionTokenHeader((name, value) => {
37
+ if (this.tokenUrlMatcher !== undefined) {
38
+ if (!this.tokenUrlMatcher(this.item.url)) {
39
+ return;
40
+ }
41
+ }
36
42
  target.setRequestHeader(name, value);
37
43
  });
38
44
  return this.getSend(target);
@@ -195,11 +201,11 @@ export class XHRProxyHandler {
195
201
  }
196
202
  }
197
203
  export default class XHRProxy {
198
- static create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl) {
204
+ static create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher) {
199
205
  return new Proxy(XMLHttpRequest, {
200
206
  construct(original) {
201
207
  const XMLReq = new original();
202
- return new Proxy(XMLReq, new XHRProxyHandler(XMLReq, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl));
208
+ return new Proxy(XMLReq, new XHRProxyHandler(XMLReq, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher));
203
209
  },
204
210
  });
205
211
  }
@@ -25,6 +25,7 @@ export interface Options {
25
25
  sanitizer?: Sanitizer;
26
26
  axiosInstances?: Array<AxiosInstance>;
27
27
  useProxy?: boolean;
28
+ tokenUrlMatcher?: (url: string) => boolean;
28
29
  }
29
30
  export default function (app: App, opts?: Partial<Options>): void;
30
31
  export {};
@@ -74,7 +74,7 @@ export default function (app, opts = {}) {
74
74
  const patchWindow = (context) => {
75
75
  /* ====== modern way ====== */
76
76
  if (options.useProxy) {
77
- return setProxy(context, options.ignoreHeaders, setSessionTokenHeader, sanitize, (message) => app.send(message), (url) => app.isServiceURL(url));
77
+ return setProxy(context, options.ignoreHeaders, setSessionTokenHeader, sanitize, (message) => app.send(message), (url) => app.isServiceURL(url), options.tokenUrlMatcher);
78
78
  }
79
79
  /* ====== Fetch ====== */
80
80
  const origFetch = context.fetch.bind(context);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openreplay/tracker",
3
3
  "description": "The OpenReplay tracker main package",
4
- "version": "9.0.4",
4
+ "version": "9.0.6",
5
5
  "keywords": [
6
6
  "logging",
7
7
  "replay"