@sailfish-ai/recorder 1.0.0-beta-14 → 1.0.2

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.
@@ -30,1101 +30,1783 @@ function v4(options, buf, offset) {
30
30
  rnds[8] = rnds[8] & 63 | 128;
31
31
  return unsafeStringify(rnds);
32
32
  }
33
- let eventCache = [];
34
- function cacheEvents(event) {
35
- eventCache.push(event);
36
- }
37
- function sendRecordingEvents(webSocket, sessionId) {
38
- if (eventCache.length > 0) {
39
- const message = {
40
- type: "events",
41
- events: eventCache
42
- };
43
- webSocket.send(JSON.stringify(message));
44
- eventCache = [];
33
+ /*! *****************************************************************************
34
+ Copyright (c) Microsoft Corporation. All rights reserved.
35
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
36
+ this file except in compliance with the License. You may obtain a copy of the
37
+ License at http://www.apache.org/licenses/LICENSE-2.0
38
+
39
+ THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
40
+ KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
41
+ WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
42
+ MERCHANTABLITY OR NON-INFRINGEMENT.
43
+
44
+ See the Apache Version 2.0 License for specific language governing permissions
45
+ and limitations under the License.
46
+ ***************************************************************************** */
47
+ var extendStatics = function(d, b) {
48
+ extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {
49
+ d2.__proto__ = b2;
50
+ } || function(d2, b2) {
51
+ for (var p in b2) if (b2.hasOwnProperty(p)) d2[p] = b2[p];
52
+ };
53
+ return extendStatics(d, b);
54
+ };
55
+ function __extends(d, b) {
56
+ extendStatics(d, b);
57
+ function __() {
58
+ this.constructor = d;
45
59
  }
60
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
46
61
  }
47
- function sendGraphQLRequest(operationName, query, variables) {
48
- return fetch(
49
- `${variables["backendApi"]}/graphql/?apiKey=${variables["apiKey"]}`,
50
- {
51
- method: "POST",
52
- headers: {
53
- "Content-Type": "application/json"
54
- },
55
- body: JSON.stringify({ operationName, query, variables })
56
- }
57
- ).then((response) => response.json());
58
- }
59
- function fetchCaptureSettings(apiKey, backendApi) {
60
- return sendGraphQLRequest(
61
- "GetCaptureSettingsFromApiKey",
62
- `
63
- query GetCaptureSettingsFromApiKey($apiKey: String!) {
64
- captureSettingsFromApiKey(apiKey: $apiKey) {
65
- recordCanvas
66
- recordCrossOriginIframes
67
- collectFonts
68
- inlineImages
69
- recordPassword
70
- recordRealName
71
- recordCreditCardInfo
72
- recordSsn
73
- recordDob
74
- sampling
75
- }
76
- }
77
- `,
78
- { apiKey, backendApi }
79
- );
80
- }
81
- function startRecordingSession(apiKey, recordingId, backendApi) {
82
- return sendGraphQLRequest(
83
- "StartSession",
84
- `mutation StartSession($apiKey: UUID!, $recordingSessionId: UUID!) {
85
- startRecordingSession(companyApiKey: $apiKey, sessionId: $recordingSessionId) {
86
- id
87
- }
88
- }`,
89
- {
90
- apiKey,
91
- recordingSessionId: recordingId,
92
- backendApi
62
+ function __values(o) {
63
+ var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
64
+ if (m) return m.call(o);
65
+ return {
66
+ next: function() {
67
+ if (o && i >= o.length) o = void 0;
68
+ return { value: o && o[i++], done: !o };
93
69
  }
94
- );
95
- }
96
- var __defProp$2 = Object.defineProperty;
97
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
98
- var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
99
- var _a$1;
100
- var __defProp$1$1 = Object.defineProperty;
101
- var __defNormalProp$1$1 = (obj, key, value) => key in obj ? __defProp$1$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
102
- var __publicField$1$1 = (obj, key, value) => __defNormalProp$1$1(obj, typeof key !== "symbol" ? key + "" : key, value);
103
- var NodeType$2 = /* @__PURE__ */ ((NodeType2) => {
104
- NodeType2[NodeType2["Document"] = 0] = "Document";
105
- NodeType2[NodeType2["DocumentType"] = 1] = "DocumentType";
106
- NodeType2[NodeType2["Element"] = 2] = "Element";
107
- NodeType2[NodeType2["Text"] = 3] = "Text";
108
- NodeType2[NodeType2["CDATA"] = 4] = "CDATA";
109
- NodeType2[NodeType2["Comment"] = 5] = "Comment";
110
- return NodeType2;
111
- })(NodeType$2 || {});
112
- function isElement(n2) {
113
- return n2.nodeType === n2.ELEMENT_NODE;
114
- }
115
- function isShadowRoot$1(n2) {
116
- const host = n2 == null ? void 0 : n2.host;
117
- return Boolean((host == null ? void 0 : host.shadowRoot) === n2);
118
- }
119
- function isNativeShadowDom(shadowRoot) {
120
- return Object.prototype.toString.call(shadowRoot) === "[object ShadowRoot]";
121
- }
122
- function fixBrowserCompatibilityIssuesInCSS(cssText) {
123
- if (cssText.includes(" background-clip: text;") && !cssText.includes(" -webkit-background-clip: text;")) {
124
- cssText = cssText.replace(
125
- /\sbackground-clip:\s*text;/g,
126
- " -webkit-background-clip: text; background-clip: text;"
127
- );
128
- }
129
- return cssText;
130
- }
131
- function escapeImportStatement(rule2) {
132
- const { cssText } = rule2;
133
- if (cssText.split('"').length < 3) return cssText;
134
- const statement = ["@import", `url(${JSON.stringify(rule2.href)})`];
135
- if (rule2.layerName === "") {
136
- statement.push(`layer`);
137
- } else if (rule2.layerName) {
138
- statement.push(`layer(${rule2.layerName})`);
139
- }
140
- if (rule2.supportsText) {
141
- statement.push(`supports(${rule2.supportsText})`);
142
- }
143
- if (rule2.media.length) {
144
- statement.push(rule2.media.mediaText);
145
- }
146
- return statement.join(" ") + ";";
70
+ };
147
71
  }
148
- function stringifyStylesheet(s2) {
72
+ function __read(o, n2) {
73
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
74
+ if (!m) return o;
75
+ var i = m.call(o), r, ar = [], e;
149
76
  try {
150
- const rules2 = s2.rules || s2.cssRules;
151
- return rules2 ? fixBrowserCompatibilityIssuesInCSS(
152
- Array.from(rules2, stringifyRule).join("")
153
- ) : null;
77
+ while ((n2 === void 0 || n2-- > 0) && !(r = i.next()).done) ar.push(r.value);
154
78
  } catch (error) {
155
- return null;
156
- }
157
- }
158
- function stringifyRule(rule2) {
159
- let importStringified;
160
- if (isCSSImportRule(rule2)) {
79
+ e = { error };
80
+ } finally {
161
81
  try {
162
- importStringified = // for same-origin stylesheets,
163
- // we can access the imported stylesheet rules directly
164
- stringifyStylesheet(rule2.styleSheet) || // work around browser issues with the raw string `@import url(...)` statement
165
- escapeImportStatement(rule2);
166
- } catch (error) {
82
+ if (r && !r.done && (m = i["return"])) m.call(i);
83
+ } finally {
84
+ if (e) throw e.error;
167
85
  }
168
- } else if (isCSSStyleRule(rule2) && rule2.selectorText.includes(":")) {
169
- return fixSafariColons(rule2.cssText);
170
86
  }
171
- return importStringified || rule2.cssText;
172
- }
173
- function fixSafariColons(cssStringified) {
174
- const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
175
- return cssStringified.replace(regex, "$1\\$2");
176
- }
177
- function isCSSImportRule(rule2) {
178
- return "styleSheet" in rule2;
87
+ return ar;
179
88
  }
180
- function isCSSStyleRule(rule2) {
181
- return "selectorText" in rule2;
89
+ function __spread() {
90
+ for (var ar = [], i = 0; i < arguments.length; i++)
91
+ ar = ar.concat(__read(arguments[i]));
92
+ return ar;
182
93
  }
183
- let Mirror$1 = class Mirror {
184
- constructor() {
185
- __publicField$1$1(this, "idNodeMap", /* @__PURE__ */ new Map());
186
- __publicField$1$1(this, "nodeMetaMap", /* @__PURE__ */ new WeakMap());
187
- }
188
- getId(n2) {
189
- var _a2;
190
- if (!n2) return -1;
191
- const id = (_a2 = this.getMeta(n2)) == null ? void 0 : _a2.id;
192
- return id ?? -1;
193
- }
194
- getNode(id) {
195
- return this.idNodeMap.get(id) || null;
196
- }
197
- getIds() {
198
- return Array.from(this.idNodeMap.keys());
199
- }
200
- getMeta(n2) {
201
- return this.nodeMetaMap.get(n2) || null;
202
- }
203
- // removes the node from idNodeMap
204
- // doesn't remove the node from nodeMetaMap
205
- removeNodeFromMap(n2) {
206
- const id = this.getId(n2);
207
- this.idNodeMap.delete(id);
208
- if (n2.childNodes) {
209
- n2.childNodes.forEach(
210
- (childNode) => this.removeNodeFromMap(childNode)
211
- );
94
+ var Event$1 = (
95
+ /** @class */
96
+ /* @__PURE__ */ function() {
97
+ function Event2(type, target) {
98
+ this.target = target;
99
+ this.type = type;
212
100
  }
213
- }
214
- has(id) {
215
- return this.idNodeMap.has(id);
216
- }
217
- hasNode(node2) {
218
- return this.nodeMetaMap.has(node2);
219
- }
220
- add(n2, meta) {
221
- const id = meta.id;
222
- this.idNodeMap.set(id, n2);
223
- this.nodeMetaMap.set(n2, meta);
224
- }
225
- replace(id, n2) {
226
- const oldNode = this.getNode(id);
227
- if (oldNode) {
228
- const meta = this.nodeMetaMap.get(oldNode);
229
- if (meta) this.nodeMetaMap.set(n2, meta);
101
+ return Event2;
102
+ }()
103
+ );
104
+ var ErrorEvent = (
105
+ /** @class */
106
+ function(_super) {
107
+ __extends(ErrorEvent2, _super);
108
+ function ErrorEvent2(error, target) {
109
+ var _this = _super.call(this, "error", target) || this;
110
+ _this.message = error.message;
111
+ _this.error = error;
112
+ return _this;
230
113
  }
231
- this.idNodeMap.set(id, n2);
232
- }
233
- reset() {
234
- this.idNodeMap = /* @__PURE__ */ new Map();
235
- this.nodeMetaMap = /* @__PURE__ */ new WeakMap();
236
- }
237
- };
238
- function createMirror$2$1() {
239
- return new Mirror$1();
240
- }
241
- function maskInputValue({
242
- element,
243
- maskInputOptions,
244
- tagName,
245
- type,
246
- value,
247
- maskInputFn: maskInputFn2
248
- }) {
249
- let text = value || "";
250
- let returnText = "";
251
- const actualType = type && toLowerCase(type);
252
- let masked = false;
253
- if (maskInputOptions[tagName.toLowerCase()] || actualType && maskInputOptions[actualType]) {
254
- if (maskInputFn2) {
255
- returnText = maskInputFn2(text, element);
256
- } else {
257
- returnText = "*".repeat(text.length);
258
- }
259
- masked = text !== returnText;
260
- }
261
- return { value: returnText, masked };
262
- }
263
- function toLowerCase(str) {
264
- return str.toLowerCase();
265
- }
266
- const ORIGINAL_ATTRIBUTE_NAME = "__rrweb_original__";
267
- function is2DCanvasBlank(canvas) {
268
- const ctx = canvas.getContext("2d");
269
- if (!ctx) return true;
270
- const chunkSize = 50;
271
- for (let x2 = 0; x2 < canvas.width; x2 += chunkSize) {
272
- for (let y = 0; y < canvas.height; y += chunkSize) {
273
- const getImageData = ctx.getImageData;
274
- const originalGetImageData = ORIGINAL_ATTRIBUTE_NAME in getImageData ? getImageData[ORIGINAL_ATTRIBUTE_NAME] : getImageData;
275
- const pixelBuffer = new Uint32Array(
276
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
277
- originalGetImageData.call(
278
- ctx,
279
- x2,
280
- y,
281
- Math.min(chunkSize, canvas.width - x2),
282
- Math.min(chunkSize, canvas.height - y)
283
- ).data.buffer
284
- );
285
- if (pixelBuffer.some((pixel) => pixel !== 0)) return false;
286
- }
287
- }
288
- return true;
289
- }
290
- function getInputType(element) {
291
- const type = element.type;
292
- return element.hasAttribute("data-rr-is-password") ? "password" : type ? (
293
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
294
- toLowerCase(type)
295
- ) : null;
296
- }
297
- function extractFileExtension(path, baseURL) {
298
- let url;
299
- try {
300
- url = new URL(path, baseURL ?? window.location.href);
301
- } catch (err) {
302
- return null;
303
- }
304
- const regex = /\.([0-9a-z]+)(?:$)/i;
305
- const match = url.pathname.match(regex);
306
- return (match == null ? void 0 : match[1]) ?? null;
307
- }
308
- let _id = 1;
309
- const tagNameRegex = new RegExp("[^a-z0-9-_:]");
310
- const IGNORED_NODE$1 = -2;
311
- function genId() {
312
- return _id++;
313
- }
314
- function getValidTagName$1(element) {
315
- if (element instanceof HTMLFormElement) {
316
- return "form";
317
- }
318
- const processedTagName = toLowerCase(element.tagName);
319
- if (tagNameRegex.test(processedTagName)) {
320
- return "div";
321
- }
322
- return processedTagName;
323
- }
324
- function extractOrigin(url) {
325
- let origin = "";
326
- if (url.indexOf("//") > -1) {
327
- origin = url.split("/").slice(0, 3).join("/");
328
- } else {
329
- origin = url.split("/")[0];
330
- }
331
- origin = origin.split("?")[0];
332
- return origin;
333
- }
334
- let canvasService;
335
- let canvasCtx;
336
- const URL_IN_CSS_REF = /url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm;
337
- const URL_PROTOCOL_MATCH = /^(?:[a-z+]+:)?\/\//i;
338
- const URL_WWW_MATCH = /^www\..*/i;
339
- const DATA_URI = /^(data:)([^,]*),(.*)/i;
340
- function absoluteToStylesheet(cssText, href) {
341
- return (cssText || "").replace(
342
- URL_IN_CSS_REF,
343
- (origin, quote1, path1, quote2, path2, path3) => {
344
- const filePath = path1 || path2 || path3;
345
- const maybeQuote = quote1 || quote2 || "";
346
- if (!filePath) {
347
- return origin;
348
- }
349
- if (URL_PROTOCOL_MATCH.test(filePath) || URL_WWW_MATCH.test(filePath)) {
350
- return `url(${maybeQuote}${filePath}${maybeQuote})`;
114
+ return ErrorEvent2;
115
+ }(Event$1)
116
+ );
117
+ var CloseEvent = (
118
+ /** @class */
119
+ function(_super) {
120
+ __extends(CloseEvent2, _super);
121
+ function CloseEvent2(code, reason, target) {
122
+ if (code === void 0) {
123
+ code = 1e3;
351
124
  }
352
- if (DATA_URI.test(filePath)) {
353
- return `url(${maybeQuote}${filePath}${maybeQuote})`;
125
+ if (reason === void 0) {
126
+ reason = "";
354
127
  }
355
- if (filePath[0] === "/") {
356
- return `url(${maybeQuote}${extractOrigin(href) + filePath}${maybeQuote})`;
128
+ var _this = _super.call(this, "close", target) || this;
129
+ _this.wasClean = true;
130
+ _this.code = code;
131
+ _this.reason = reason;
132
+ return _this;
133
+ }
134
+ return CloseEvent2;
135
+ }(Event$1)
136
+ );
137
+ /*!
138
+ * Reconnecting WebSocket
139
+ * by Pedro Ladaria <pedro.ladaria@gmail.com>
140
+ * https://github.com/pladaria/reconnecting-websocket
141
+ * License MIT
142
+ */
143
+ var getGlobalWebSocket = function() {
144
+ if (typeof WebSocket !== "undefined") {
145
+ return WebSocket;
146
+ }
147
+ };
148
+ var isWebSocket = function(w) {
149
+ return typeof w !== "undefined" && !!w && w.CLOSING === 2;
150
+ };
151
+ var DEFAULT = {
152
+ maxReconnectionDelay: 1e4,
153
+ minReconnectionDelay: 1e3 + Math.random() * 4e3,
154
+ minUptime: 5e3,
155
+ reconnectionDelayGrowFactor: 1.3,
156
+ connectionTimeout: 4e3,
157
+ maxRetries: Infinity,
158
+ maxEnqueuedMessages: Infinity,
159
+ startClosed: false,
160
+ debug: false
161
+ };
162
+ var ReconnectingWebSocket = (
163
+ /** @class */
164
+ function() {
165
+ function ReconnectingWebSocket2(url, protocols, options) {
166
+ var _this = this;
167
+ if (options === void 0) {
168
+ options = {};
357
169
  }
358
- const stack = href.split("/");
359
- const parts = filePath.split("/");
360
- stack.pop();
361
- for (const part of parts) {
362
- if (part === ".") {
363
- continue;
364
- } else if (part === "..") {
365
- stack.pop();
366
- } else {
367
- stack.push(part);
170
+ this._listeners = {
171
+ error: [],
172
+ message: [],
173
+ open: [],
174
+ close: []
175
+ };
176
+ this._retryCount = -1;
177
+ this._shouldReconnect = true;
178
+ this._connectLock = false;
179
+ this._binaryType = "blob";
180
+ this._closeCalled = false;
181
+ this._messageQueue = [];
182
+ this.onclose = null;
183
+ this.onerror = null;
184
+ this.onmessage = null;
185
+ this.onopen = null;
186
+ this._handleOpen = function(event) {
187
+ _this._debug("open event");
188
+ var _a2 = _this._options.minUptime, minUptime = _a2 === void 0 ? DEFAULT.minUptime : _a2;
189
+ clearTimeout(_this._connectTimeout);
190
+ _this._uptimeTimeout = setTimeout(function() {
191
+ return _this._acceptOpen();
192
+ }, minUptime);
193
+ _this._ws.binaryType = _this._binaryType;
194
+ _this._messageQueue.forEach(function(message) {
195
+ return _this._ws.send(message);
196
+ });
197
+ _this._messageQueue = [];
198
+ if (_this.onopen) {
199
+ _this.onopen(event);
200
+ }
201
+ _this._listeners.open.forEach(function(listener) {
202
+ return _this._callEventListener(event, listener);
203
+ });
204
+ };
205
+ this._handleMessage = function(event) {
206
+ _this._debug("message event");
207
+ if (_this.onmessage) {
208
+ _this.onmessage(event);
209
+ }
210
+ _this._listeners.message.forEach(function(listener) {
211
+ return _this._callEventListener(event, listener);
212
+ });
213
+ };
214
+ this._handleError = function(event) {
215
+ _this._debug("error event", event.message);
216
+ _this._disconnect(void 0, event.message === "TIMEOUT" ? "timeout" : void 0);
217
+ if (_this.onerror) {
218
+ _this.onerror(event);
219
+ }
220
+ _this._debug("exec error listeners");
221
+ _this._listeners.error.forEach(function(listener) {
222
+ return _this._callEventListener(event, listener);
223
+ });
224
+ _this._connect();
225
+ };
226
+ this._handleClose = function(event) {
227
+ _this._debug("close event");
228
+ _this._clearTimeouts();
229
+ if (_this._shouldReconnect) {
230
+ _this._connect();
231
+ }
232
+ if (_this.onclose) {
233
+ _this.onclose(event);
368
234
  }
235
+ _this._listeners.close.forEach(function(listener) {
236
+ return _this._callEventListener(event, listener);
237
+ });
238
+ };
239
+ this._url = url;
240
+ this._protocols = protocols;
241
+ this._options = options;
242
+ if (this._options.startClosed) {
243
+ this._shouldReconnect = false;
369
244
  }
370
- return `url(${maybeQuote}${stack.join("/")}${maybeQuote})`;
245
+ this._connect();
371
246
  }
372
- );
373
- }
374
- const SRCSET_NOT_SPACES = /^[^ \t\n\r\u000c]+/;
375
- const SRCSET_COMMAS_OR_SPACES = /^[, \t\n\r\u000c]+/;
376
- function getAbsoluteSrcsetString(doc, attributeValue) {
377
- if (attributeValue.trim() === "") {
378
- return attributeValue;
379
- }
380
- let pos = 0;
381
- function collectCharacters(regEx) {
382
- let chars2;
383
- const match = regEx.exec(attributeValue.substring(pos));
384
- if (match) {
385
- chars2 = match[0];
386
- pos += chars2.length;
387
- return chars2;
388
- }
389
- return "";
390
- }
391
- const output = [];
392
- while (true) {
393
- collectCharacters(SRCSET_COMMAS_OR_SPACES);
394
- if (pos >= attributeValue.length) {
395
- break;
396
- }
397
- let url = collectCharacters(SRCSET_NOT_SPACES);
398
- if (url.slice(-1) === ",") {
399
- url = absoluteToDoc(doc, url.substring(0, url.length - 1));
400
- output.push(url);
401
- } else {
402
- let descriptorsStr = "";
403
- url = absoluteToDoc(doc, url);
404
- let inParens = false;
405
- while (true) {
406
- const c2 = attributeValue.charAt(pos);
407
- if (c2 === "") {
408
- output.push((url + descriptorsStr).trim());
409
- break;
410
- } else if (!inParens) {
411
- if (c2 === ",") {
412
- pos += 1;
413
- output.push((url + descriptorsStr).trim());
414
- break;
415
- } else if (c2 === "(") {
416
- inParens = true;
417
- }
418
- } else {
419
- if (c2 === ")") {
420
- inParens = false;
247
+ Object.defineProperty(ReconnectingWebSocket2, "CONNECTING", {
248
+ get: function() {
249
+ return 0;
250
+ },
251
+ enumerable: true,
252
+ configurable: true
253
+ });
254
+ Object.defineProperty(ReconnectingWebSocket2, "OPEN", {
255
+ get: function() {
256
+ return 1;
257
+ },
258
+ enumerable: true,
259
+ configurable: true
260
+ });
261
+ Object.defineProperty(ReconnectingWebSocket2, "CLOSING", {
262
+ get: function() {
263
+ return 2;
264
+ },
265
+ enumerable: true,
266
+ configurable: true
267
+ });
268
+ Object.defineProperty(ReconnectingWebSocket2, "CLOSED", {
269
+ get: function() {
270
+ return 3;
271
+ },
272
+ enumerable: true,
273
+ configurable: true
274
+ });
275
+ Object.defineProperty(ReconnectingWebSocket2.prototype, "CONNECTING", {
276
+ get: function() {
277
+ return ReconnectingWebSocket2.CONNECTING;
278
+ },
279
+ enumerable: true,
280
+ configurable: true
281
+ });
282
+ Object.defineProperty(ReconnectingWebSocket2.prototype, "OPEN", {
283
+ get: function() {
284
+ return ReconnectingWebSocket2.OPEN;
285
+ },
286
+ enumerable: true,
287
+ configurable: true
288
+ });
289
+ Object.defineProperty(ReconnectingWebSocket2.prototype, "CLOSING", {
290
+ get: function() {
291
+ return ReconnectingWebSocket2.CLOSING;
292
+ },
293
+ enumerable: true,
294
+ configurable: true
295
+ });
296
+ Object.defineProperty(ReconnectingWebSocket2.prototype, "CLOSED", {
297
+ get: function() {
298
+ return ReconnectingWebSocket2.CLOSED;
299
+ },
300
+ enumerable: true,
301
+ configurable: true
302
+ });
303
+ Object.defineProperty(ReconnectingWebSocket2.prototype, "binaryType", {
304
+ get: function() {
305
+ return this._ws ? this._ws.binaryType : this._binaryType;
306
+ },
307
+ set: function(value) {
308
+ this._binaryType = value;
309
+ if (this._ws) {
310
+ this._ws.binaryType = value;
311
+ }
312
+ },
313
+ enumerable: true,
314
+ configurable: true
315
+ });
316
+ Object.defineProperty(ReconnectingWebSocket2.prototype, "retryCount", {
317
+ /**
318
+ * Returns the number or connection retries
319
+ */
320
+ get: function() {
321
+ return Math.max(this._retryCount, 0);
322
+ },
323
+ enumerable: true,
324
+ configurable: true
325
+ });
326
+ Object.defineProperty(ReconnectingWebSocket2.prototype, "bufferedAmount", {
327
+ /**
328
+ * The number of bytes of data that have been queued using calls to send() but not yet
329
+ * transmitted to the network. This value resets to zero once all queued data has been sent.
330
+ * This value does not reset to zero when the connection is closed; if you keep calling send(),
331
+ * this will continue to climb. Read only
332
+ */
333
+ get: function() {
334
+ var bytes = this._messageQueue.reduce(function(acc, message) {
335
+ if (typeof message === "string") {
336
+ acc += message.length;
337
+ } else if (message instanceof Blob) {
338
+ acc += message.size;
339
+ } else {
340
+ acc += message.byteLength;
421
341
  }
342
+ return acc;
343
+ }, 0);
344
+ return bytes + (this._ws ? this._ws.bufferedAmount : 0);
345
+ },
346
+ enumerable: true,
347
+ configurable: true
348
+ });
349
+ Object.defineProperty(ReconnectingWebSocket2.prototype, "extensions", {
350
+ /**
351
+ * The extensions selected by the server. This is currently only the empty string or a list of
352
+ * extensions as negotiated by the connection
353
+ */
354
+ get: function() {
355
+ return this._ws ? this._ws.extensions : "";
356
+ },
357
+ enumerable: true,
358
+ configurable: true
359
+ });
360
+ Object.defineProperty(ReconnectingWebSocket2.prototype, "protocol", {
361
+ /**
362
+ * A string indicating the name of the sub-protocol the server selected;
363
+ * this will be one of the strings specified in the protocols parameter when creating the
364
+ * WebSocket object
365
+ */
366
+ get: function() {
367
+ return this._ws ? this._ws.protocol : "";
368
+ },
369
+ enumerable: true,
370
+ configurable: true
371
+ });
372
+ Object.defineProperty(ReconnectingWebSocket2.prototype, "readyState", {
373
+ /**
374
+ * The current state of the connection; this is one of the Ready state constants
375
+ */
376
+ get: function() {
377
+ if (this._ws) {
378
+ return this._ws.readyState;
422
379
  }
423
- descriptorsStr += c2;
424
- pos += 1;
380
+ return this._options.startClosed ? ReconnectingWebSocket2.CLOSED : ReconnectingWebSocket2.CONNECTING;
381
+ },
382
+ enumerable: true,
383
+ configurable: true
384
+ });
385
+ Object.defineProperty(ReconnectingWebSocket2.prototype, "url", {
386
+ /**
387
+ * The URL as resolved by the constructor
388
+ */
389
+ get: function() {
390
+ return this._ws ? this._ws.url : "";
391
+ },
392
+ enumerable: true,
393
+ configurable: true
394
+ });
395
+ ReconnectingWebSocket2.prototype.close = function(code, reason) {
396
+ if (code === void 0) {
397
+ code = 1e3;
425
398
  }
426
- }
427
- }
428
- return output.join(", ");
429
- }
430
- const cachedDocument = /* @__PURE__ */ new WeakMap();
431
- function absoluteToDoc(doc, attributeValue) {
432
- if (!attributeValue || attributeValue.trim() === "") {
433
- return attributeValue;
434
- }
435
- return getHref(doc, attributeValue);
436
- }
437
- function isSVGElement(el) {
438
- return Boolean(el.tagName === "svg" || el.ownerSVGElement);
439
- }
440
- function getHref(doc, customHref) {
441
- let a2 = cachedDocument.get(doc);
442
- if (!a2) {
443
- a2 = doc.createElement("a");
444
- cachedDocument.set(doc, a2);
445
- }
446
- if (!customHref) {
447
- customHref = "";
448
- } else if (customHref.startsWith("blob:") || customHref.startsWith("data:")) {
449
- return customHref;
450
- }
451
- a2.setAttribute("href", customHref);
452
- return a2.href;
453
- }
454
- function transformAttribute(doc, tagName, name, value) {
455
- if (!value) {
456
- return value;
457
- }
458
- if (name === "src" || name === "href" && !(tagName === "use" && value[0] === "#")) {
459
- return absoluteToDoc(doc, value);
460
- } else if (name === "xlink:href" && value[0] !== "#") {
461
- return absoluteToDoc(doc, value);
462
- } else if (name === "background" && (tagName === "table" || tagName === "td" || tagName === "th")) {
463
- return absoluteToDoc(doc, value);
464
- } else if (name === "srcset") {
465
- return getAbsoluteSrcsetString(doc, value);
466
- } else if (name === "style") {
467
- return absoluteToStylesheet(value, getHref(doc));
468
- } else if (tagName === "object" && name === "data") {
469
- return absoluteToDoc(doc, value);
470
- }
471
- return value;
472
- }
473
- function ignoreAttribute(tagName, name, _value) {
474
- return (tagName === "video" || tagName === "audio") && name === "autoplay";
475
- }
476
- function _isBlockedElement(element, blockClass, blockSelector) {
477
- try {
478
- if (typeof blockClass === "string") {
479
- if (element.classList.contains(blockClass)) {
480
- return true;
399
+ this._closeCalled = true;
400
+ this._shouldReconnect = false;
401
+ this._clearTimeouts();
402
+ if (!this._ws) {
403
+ this._debug("close enqueued: no ws instance");
404
+ return;
481
405
  }
482
- } else {
483
- for (let eIndex = element.classList.length; eIndex--; ) {
484
- const className = element.classList[eIndex];
485
- if (blockClass.test(className)) {
486
- return true;
406
+ if (this._ws.readyState === this.CLOSED) {
407
+ this._debug("close: already closed");
408
+ return;
409
+ }
410
+ this._ws.close(code, reason);
411
+ };
412
+ ReconnectingWebSocket2.prototype.reconnect = function(code, reason) {
413
+ this._shouldReconnect = true;
414
+ this._closeCalled = false;
415
+ this._retryCount = -1;
416
+ if (!this._ws || this._ws.readyState === this.CLOSED) {
417
+ this._connect();
418
+ } else {
419
+ this._disconnect(code, reason);
420
+ this._connect();
421
+ }
422
+ };
423
+ ReconnectingWebSocket2.prototype.send = function(data) {
424
+ if (this._ws && this._ws.readyState === this.OPEN) {
425
+ this._debug("send", data);
426
+ this._ws.send(data);
427
+ } else {
428
+ var _a2 = this._options.maxEnqueuedMessages, maxEnqueuedMessages = _a2 === void 0 ? DEFAULT.maxEnqueuedMessages : _a2;
429
+ if (this._messageQueue.length < maxEnqueuedMessages) {
430
+ this._debug("enqueue", data);
431
+ this._messageQueue.push(data);
487
432
  }
488
433
  }
434
+ };
435
+ ReconnectingWebSocket2.prototype.addEventListener = function(type, listener) {
436
+ if (this._listeners[type]) {
437
+ this._listeners[type].push(listener);
438
+ }
439
+ };
440
+ ReconnectingWebSocket2.prototype.dispatchEvent = function(event) {
441
+ var e_1, _a2;
442
+ var listeners = this._listeners[event.type];
443
+ if (listeners) {
444
+ try {
445
+ for (var listeners_1 = __values(listeners), listeners_1_1 = listeners_1.next(); !listeners_1_1.done; listeners_1_1 = listeners_1.next()) {
446
+ var listener = listeners_1_1.value;
447
+ this._callEventListener(event, listener);
448
+ }
449
+ } catch (e_1_1) {
450
+ e_1 = { error: e_1_1 };
451
+ } finally {
452
+ try {
453
+ if (listeners_1_1 && !listeners_1_1.done && (_a2 = listeners_1.return)) _a2.call(listeners_1);
454
+ } finally {
455
+ if (e_1) throw e_1.error;
456
+ }
457
+ }
458
+ }
459
+ return true;
460
+ };
461
+ ReconnectingWebSocket2.prototype.removeEventListener = function(type, listener) {
462
+ if (this._listeners[type]) {
463
+ this._listeners[type] = this._listeners[type].filter(function(l) {
464
+ return l !== listener;
465
+ });
466
+ }
467
+ };
468
+ ReconnectingWebSocket2.prototype._debug = function() {
469
+ var args = [];
470
+ for (var _i = 0; _i < arguments.length; _i++) {
471
+ args[_i] = arguments[_i];
472
+ }
473
+ if (this._options.debug) {
474
+ console.log.apply(console, __spread(["RWS>"], args));
475
+ }
476
+ };
477
+ ReconnectingWebSocket2.prototype._getNextDelay = function() {
478
+ var _a2 = this._options, _b = _a2.reconnectionDelayGrowFactor, reconnectionDelayGrowFactor = _b === void 0 ? DEFAULT.reconnectionDelayGrowFactor : _b, _c = _a2.minReconnectionDelay, minReconnectionDelay = _c === void 0 ? DEFAULT.minReconnectionDelay : _c, _d = _a2.maxReconnectionDelay, maxReconnectionDelay = _d === void 0 ? DEFAULT.maxReconnectionDelay : _d;
479
+ var delay = 0;
480
+ if (this._retryCount > 0) {
481
+ delay = minReconnectionDelay * Math.pow(reconnectionDelayGrowFactor, this._retryCount - 1);
482
+ if (delay > maxReconnectionDelay) {
483
+ delay = maxReconnectionDelay;
484
+ }
485
+ }
486
+ this._debug("next delay", delay);
487
+ return delay;
488
+ };
489
+ ReconnectingWebSocket2.prototype._wait = function() {
490
+ var _this = this;
491
+ return new Promise(function(resolve2) {
492
+ setTimeout(resolve2, _this._getNextDelay());
493
+ });
494
+ };
495
+ ReconnectingWebSocket2.prototype._getNextUrl = function(urlProvider) {
496
+ if (typeof urlProvider === "string") {
497
+ return Promise.resolve(urlProvider);
498
+ }
499
+ if (typeof urlProvider === "function") {
500
+ var url = urlProvider();
501
+ if (typeof url === "string") {
502
+ return Promise.resolve(url);
503
+ }
504
+ if (!!url.then) {
505
+ return url;
506
+ }
507
+ }
508
+ throw Error("Invalid URL");
509
+ };
510
+ ReconnectingWebSocket2.prototype._connect = function() {
511
+ var _this = this;
512
+ if (this._connectLock || !this._shouldReconnect) {
513
+ return;
514
+ }
515
+ this._connectLock = true;
516
+ var _a2 = this._options, _b = _a2.maxRetries, maxRetries = _b === void 0 ? DEFAULT.maxRetries : _b, _c = _a2.connectionTimeout, connectionTimeout = _c === void 0 ? DEFAULT.connectionTimeout : _c, _d = _a2.WebSocket, WebSocket2 = _d === void 0 ? getGlobalWebSocket() : _d;
517
+ if (this._retryCount >= maxRetries) {
518
+ this._debug("max retries reached", this._retryCount, ">=", maxRetries);
519
+ return;
520
+ }
521
+ this._retryCount++;
522
+ this._debug("connect", this._retryCount);
523
+ this._removeListeners();
524
+ if (!isWebSocket(WebSocket2)) {
525
+ throw Error("No valid WebSocket class provided");
526
+ }
527
+ this._wait().then(function() {
528
+ return _this._getNextUrl(_this._url);
529
+ }).then(function(url) {
530
+ if (_this._closeCalled) {
531
+ return;
532
+ }
533
+ _this._debug("connect", { url, protocols: _this._protocols });
534
+ _this._ws = _this._protocols ? new WebSocket2(url, _this._protocols) : new WebSocket2(url);
535
+ _this._ws.binaryType = _this._binaryType;
536
+ _this._connectLock = false;
537
+ _this._addListeners();
538
+ _this._connectTimeout = setTimeout(function() {
539
+ return _this._handleTimeout();
540
+ }, connectionTimeout);
541
+ });
542
+ };
543
+ ReconnectingWebSocket2.prototype._handleTimeout = function() {
544
+ this._debug("timeout event");
545
+ this._handleError(new ErrorEvent(Error("TIMEOUT"), this));
546
+ };
547
+ ReconnectingWebSocket2.prototype._disconnect = function(code, reason) {
548
+ if (code === void 0) {
549
+ code = 1e3;
550
+ }
551
+ this._clearTimeouts();
552
+ if (!this._ws) {
553
+ return;
554
+ }
555
+ this._removeListeners();
556
+ try {
557
+ this._ws.close(code, reason);
558
+ this._handleClose(new CloseEvent(code, reason, this));
559
+ } catch (error) {
560
+ }
561
+ };
562
+ ReconnectingWebSocket2.prototype._acceptOpen = function() {
563
+ this._debug("accept open");
564
+ this._retryCount = 0;
565
+ };
566
+ ReconnectingWebSocket2.prototype._callEventListener = function(event, listener) {
567
+ if ("handleEvent" in listener) {
568
+ listener.handleEvent(event);
569
+ } else {
570
+ listener(event);
571
+ }
572
+ };
573
+ ReconnectingWebSocket2.prototype._removeListeners = function() {
574
+ if (!this._ws) {
575
+ return;
576
+ }
577
+ this._debug("removeListeners");
578
+ this._ws.removeEventListener("open", this._handleOpen);
579
+ this._ws.removeEventListener("close", this._handleClose);
580
+ this._ws.removeEventListener("message", this._handleMessage);
581
+ this._ws.removeEventListener("error", this._handleError);
582
+ };
583
+ ReconnectingWebSocket2.prototype._addListeners = function() {
584
+ if (!this._ws) {
585
+ return;
586
+ }
587
+ this._debug("addListeners");
588
+ this._ws.addEventListener("open", this._handleOpen);
589
+ this._ws.addEventListener("close", this._handleClose);
590
+ this._ws.addEventListener("message", this._handleMessage);
591
+ this._ws.addEventListener("error", this._handleError);
592
+ };
593
+ ReconnectingWebSocket2.prototype._clearTimeouts = function() {
594
+ clearTimeout(this._connectTimeout);
595
+ clearTimeout(this._uptimeTimeout);
596
+ };
597
+ return ReconnectingWebSocket2;
598
+ }()
599
+ );
600
+ const version = "1.0.2";
601
+ let webSocket = null;
602
+ const messageQueue = [];
603
+ function flushMessageQueue() {
604
+ if (webSocket && webSocket.readyState === WebSocket.OPEN) {
605
+ while (messageQueue.length > 0) {
606
+ const message = messageQueue.shift();
607
+ if (message) {
608
+ webSocket.send(message);
609
+ }
489
610
  }
490
- if (blockSelector) {
491
- return element.matches(blockSelector);
492
- }
493
- } catch (e2) {
494
611
  }
495
- return false;
496
612
  }
497
- function classMatchesRegex$1(node2, regex, checkAncestors) {
498
- if (!node2) return false;
499
- if (node2.nodeType !== node2.ELEMENT_NODE) {
500
- if (!checkAncestors) return false;
501
- return classMatchesRegex$1(node2.parentNode, regex, checkAncestors);
613
+ function initializeWebSocket(backendApi, apiKey, sessionId) {
614
+ const wsHost = getWebSocketHost(backendApi);
615
+ const wsScheme = window.location.protocol === "https:" ? "wss" : "ws";
616
+ const wsUrl = `${wsScheme}://${wsHost}/ws/notify/?apiKey=${apiKey}&sessionId=${sessionId}&sender=JS%2FTS&version=${version}`;
617
+ const options = {
618
+ connectionTimeout: 1e4
619
+ };
620
+ webSocket = new ReconnectingWebSocket(wsUrl, [], options);
621
+ webSocket.addEventListener("open", () => {
622
+ flushMessageQueue();
623
+ });
624
+ webSocket.addEventListener("close", () => {
625
+ webSocket = null;
626
+ });
627
+ return webSocket;
628
+ }
629
+ function sendMessage(message) {
630
+ const messageString = JSON.stringify(message);
631
+ if (webSocket && webSocket.readyState === WebSocket.OPEN) {
632
+ webSocket.send(messageString);
633
+ } else {
634
+ messageQueue.push(messageString);
502
635
  }
503
- for (let eIndex = node2.classList.length; eIndex--; ) {
504
- const className = node2.classList[eIndex];
505
- if (regex.test(className)) {
506
- return true;
636
+ }
637
+ function getWebSocketHost(url) {
638
+ const parser2 = document.createElement("a");
639
+ parser2.href = url;
640
+ return `${parser2.hostname}${parser2.port ? `:${parser2.port}` : ""}`;
641
+ }
642
+ async function gatherAndCacheDeviceInfo() {
643
+ const geolocation = await getGeolocation();
644
+ const info = {
645
+ // connection: {
646
+ // downlink: connection.downlink,
647
+ // downlinkMax: connection.downlinkMax,
648
+ // effectiveType: connection.effectiveType,
649
+ // rtt: connection.rtt,
650
+ // },
651
+ // deviceMemory: navigator.deviceMemory,
652
+ language: navigator.language,
653
+ userAgent: navigator.userAgent,
654
+ geolocation
655
+ };
656
+ sendMessage({ type: "deviceInfo", data: { deviceInfo: info } });
657
+ }
658
+ function getGeolocation() {
659
+ return new Promise((resolve2) => {
660
+ if ("geolocation" in navigator) {
661
+ navigator.geolocation.getCurrentPosition(
662
+ (position) => {
663
+ resolve2({
664
+ latitude: position.coords.latitude,
665
+ longitude: position.coords.longitude
666
+ });
667
+ },
668
+ (error) => {
669
+ console.error("Error getting geolocation:", error);
670
+ resolve2(void 0);
671
+ }
672
+ );
673
+ } else {
674
+ console.warn("Geolocation is not supported by this browser.");
675
+ resolve2(void 0);
507
676
  }
508
- }
509
- if (!checkAncestors) return false;
510
- return classMatchesRegex$1(node2.parentNode, regex, checkAncestors);
677
+ });
511
678
  }
512
- function needMaskingText(node2, maskTextClass, maskTextSelector, checkAncestors) {
513
- let el;
514
- if (isElement(node2)) {
515
- el = node2;
516
- if (!el.childNodes.length) {
517
- return false;
679
+ let eventCache = [];
680
+ function cacheEvents(event) {
681
+ eventCache.push(event);
682
+ }
683
+ function sendRecordingEvents(webSocket2) {
684
+ if (webSocket2 && webSocket2.readyState === WebSocket.OPEN) {
685
+ if (eventCache.length > 0) {
686
+ const message = {
687
+ type: "events",
688
+ events: eventCache
689
+ };
690
+ webSocket2.send(JSON.stringify(message));
691
+ eventCache = [];
518
692
  }
519
- } else if (node2.parentElement === null) {
520
- return false;
521
693
  } else {
522
- el = node2.parentElement;
694
+ eventCache.push(...eventCache);
523
695
  }
524
- try {
525
- if (typeof maskTextClass === "string") {
526
- if (checkAncestors) {
527
- if (el.closest(`.${maskTextClass}`)) return true;
528
- } else {
529
- if (el.classList.contains(maskTextClass)) return true;
696
+ }
697
+ function exponentialBackoff(fn, action, retries = 5, initialDelay = 2e3, backoffFactor = 2) {
698
+ let attempt = 0;
699
+ const attemptRequest = async () => {
700
+ try {
701
+ return await fn();
702
+ } catch (error) {
703
+ attempt++;
704
+ if (attempt > retries) {
705
+ throw error;
530
706
  }
531
- } else {
532
- if (classMatchesRegex$1(el, maskTextClass, checkAncestors)) return true;
707
+ const delay = initialDelay * Math.pow(backoffFactor, attempt - 1);
708
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
709
+ return attemptRequest();
533
710
  }
534
- if (maskTextSelector) {
535
- if (checkAncestors) {
536
- if (el.closest(maskTextSelector)) return true;
537
- } else {
538
- if (el.matches(maskTextSelector)) return true;
711
+ };
712
+ return attemptRequest();
713
+ }
714
+ const DEBUG = false;
715
+ function sendGraphQLRequest(operationName, query, variables, retries = 5, initialBackoff = 2e3, backoffFactor = 2) {
716
+ const apiEndpoint = `${variables["backendApi"]}/graphql/?apiKey=${variables["apiKey"]}`;
717
+ const action = "Sending GraphQL request to Sailfish AI";
718
+ return exponentialBackoff(
719
+ () => fetch(apiEndpoint, {
720
+ method: "POST",
721
+ headers: {
722
+ "Content-Type": "application/json"
723
+ },
724
+ body: JSON.stringify({ operationName, query, variables })
725
+ }).then((response) => {
726
+ if (DEBUG)
727
+ ;
728
+ if (!response.ok) {
729
+ throw new Error(
730
+ `GraphQL request failed with status ${response.status}`
731
+ );
732
+ }
733
+ return response.json();
734
+ }),
735
+ action,
736
+ retries,
737
+ initialBackoff,
738
+ backoffFactor
739
+ );
740
+ }
741
+ function fetchCaptureSettings(apiKey, backendApi) {
742
+ return sendGraphQLRequest(
743
+ "GetCaptureSettingsFromApiKey",
744
+ `
745
+ query GetCaptureSettingsFromApiKey($apiKey: String!) {
746
+ captureSettingsFromApiKey(apiKey: $apiKey) {
747
+ recordCanvas
748
+ recordCrossOriginIframes
749
+ collectFonts
750
+ inlineImages
751
+ recordPassword
752
+ recordRealName
753
+ recordCreditCardInfo
754
+ recordSsn
755
+ recordDob
756
+ sampling
539
757
  }
540
758
  }
541
- } catch (e2) {
542
- }
543
- return false;
759
+ `,
760
+ { apiKey, backendApi }
761
+ );
544
762
  }
545
- function onceIframeLoaded(iframeEl, listener, iframeLoadTimeout) {
546
- const win = iframeEl.contentWindow;
547
- if (!win) {
548
- return;
763
+ function startRecordingSession(apiKey, recordingId, backendApi) {
764
+ return sendGraphQLRequest(
765
+ "StartSession",
766
+ `mutation StartSession($apiKey: UUID!, $recordingSessionId: UUID!) {
767
+ startRecordingSession(companyApiKey: $apiKey, sessionId: $recordingSessionId) {
768
+ id
769
+ }
770
+ }`,
771
+ {
772
+ apiKey,
773
+ recordingSessionId: recordingId,
774
+ backendApi
775
+ }
776
+ );
777
+ }
778
+ var __defProp$2 = Object.defineProperty;
779
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
780
+ var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
781
+ var _a$1;
782
+ var __defProp$1$1 = Object.defineProperty;
783
+ var __defNormalProp$1$1 = (obj, key, value) => key in obj ? __defProp$1$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
784
+ var __publicField$1$1 = (obj, key, value) => __defNormalProp$1$1(obj, typeof key !== "symbol" ? key + "" : key, value);
785
+ var NodeType$2 = /* @__PURE__ */ ((NodeType2) => {
786
+ NodeType2[NodeType2["Document"] = 0] = "Document";
787
+ NodeType2[NodeType2["DocumentType"] = 1] = "DocumentType";
788
+ NodeType2[NodeType2["Element"] = 2] = "Element";
789
+ NodeType2[NodeType2["Text"] = 3] = "Text";
790
+ NodeType2[NodeType2["CDATA"] = 4] = "CDATA";
791
+ NodeType2[NodeType2["Comment"] = 5] = "Comment";
792
+ return NodeType2;
793
+ })(NodeType$2 || {});
794
+ function isElement(n2) {
795
+ return n2.nodeType === n2.ELEMENT_NODE;
796
+ }
797
+ function isShadowRoot$1(n2) {
798
+ const host = n2 == null ? void 0 : n2.host;
799
+ return Boolean((host == null ? void 0 : host.shadowRoot) === n2);
800
+ }
801
+ function isNativeShadowDom(shadowRoot) {
802
+ return Object.prototype.toString.call(shadowRoot) === "[object ShadowRoot]";
803
+ }
804
+ function fixBrowserCompatibilityIssuesInCSS(cssText) {
805
+ if (cssText.includes(" background-clip: text;") && !cssText.includes(" -webkit-background-clip: text;")) {
806
+ cssText = cssText.replace(
807
+ /\sbackground-clip:\s*text;/g,
808
+ " -webkit-background-clip: text; background-clip: text;"
809
+ );
549
810
  }
550
- let fired = false;
551
- let readyState;
552
- try {
553
- readyState = win.document.readyState;
554
- } catch (error) {
555
- return;
811
+ return cssText;
812
+ }
813
+ function escapeImportStatement(rule2) {
814
+ const { cssText } = rule2;
815
+ if (cssText.split('"').length < 3) return cssText;
816
+ const statement = ["@import", `url(${JSON.stringify(rule2.href)})`];
817
+ if (rule2.layerName === "") {
818
+ statement.push(`layer`);
819
+ } else if (rule2.layerName) {
820
+ statement.push(`layer(${rule2.layerName})`);
556
821
  }
557
- if (readyState !== "complete") {
558
- const timer = setTimeout(() => {
559
- if (!fired) {
560
- listener();
561
- fired = true;
562
- }
563
- }, iframeLoadTimeout);
564
- iframeEl.addEventListener("load", () => {
565
- clearTimeout(timer);
566
- fired = true;
567
- listener();
568
- });
569
- return;
822
+ if (rule2.supportsText) {
823
+ statement.push(`supports(${rule2.supportsText})`);
570
824
  }
571
- const blankUrl = "about:blank";
572
- if (win.location.href !== blankUrl || iframeEl.src === blankUrl || iframeEl.src === "") {
573
- setTimeout(listener, 0);
574
- return iframeEl.addEventListener("load", listener);
825
+ if (rule2.media.length) {
826
+ statement.push(rule2.media.mediaText);
575
827
  }
576
- iframeEl.addEventListener("load", listener);
828
+ return statement.join(" ") + ";";
577
829
  }
578
- function onceStylesheetLoaded(link, listener, styleSheetLoadTimeout) {
579
- let fired = false;
580
- let styleSheetLoaded;
830
+ function stringifyStylesheet(s2) {
581
831
  try {
582
- styleSheetLoaded = link.sheet;
832
+ const rules2 = s2.rules || s2.cssRules;
833
+ return rules2 ? fixBrowserCompatibilityIssuesInCSS(
834
+ Array.from(rules2, stringifyRule).join("")
835
+ ) : null;
583
836
  } catch (error) {
584
- return;
837
+ return null;
585
838
  }
586
- if (styleSheetLoaded) return;
587
- const timer = setTimeout(() => {
588
- if (!fired) {
589
- listener();
590
- fired = true;
591
- }
592
- }, styleSheetLoadTimeout);
593
- link.addEventListener("load", () => {
594
- clearTimeout(timer);
595
- fired = true;
596
- listener();
597
- });
598
839
  }
599
- function serializeNode(n2, options) {
600
- const {
601
- doc,
602
- mirror: mirror2,
603
- blockClass,
604
- blockSelector,
605
- needsMask,
606
- inlineStylesheet,
607
- maskInputOptions = {},
608
- maskTextFn,
609
- maskInputFn: maskInputFn2,
610
- dataURLOptions = {},
611
- inlineImages,
612
- recordCanvas,
613
- keepIframeSrcFn,
614
- newlyAddedElement = false
615
- } = options;
616
- const rootId = getRootId(doc, mirror2);
617
- switch (n2.nodeType) {
618
- case n2.DOCUMENT_NODE:
619
- if (n2.compatMode !== "CSS1Compat") {
620
- return {
621
- type: NodeType$2.Document,
622
- childNodes: [],
623
- compatMode: n2.compatMode
624
- // probably "BackCompat"
625
- };
626
- } else {
627
- return {
628
- type: NodeType$2.Document,
629
- childNodes: []
630
- };
631
- }
632
- case n2.DOCUMENT_TYPE_NODE:
633
- return {
634
- type: NodeType$2.DocumentType,
635
- name: n2.name,
636
- publicId: n2.publicId,
637
- systemId: n2.systemId,
638
- rootId
639
- };
640
- case n2.ELEMENT_NODE:
641
- return serializeElementNode(n2, {
642
- doc,
643
- blockClass,
644
- blockSelector,
645
- inlineStylesheet,
646
- maskInputOptions,
647
- maskInputFn: maskInputFn2,
648
- dataURLOptions,
649
- inlineImages,
650
- recordCanvas,
651
- keepIframeSrcFn,
652
- newlyAddedElement,
653
- rootId
654
- });
655
- case n2.TEXT_NODE:
656
- return serializeTextNode(n2, {
657
- doc,
658
- needsMask,
659
- maskTextFn,
660
- rootId
661
- });
662
- case n2.CDATA_SECTION_NODE:
663
- return {
664
- type: NodeType$2.CDATA,
665
- textContent: "",
666
- rootId
667
- };
668
- case n2.COMMENT_NODE:
669
- return {
670
- type: NodeType$2.Comment,
671
- textContent: n2.textContent || "",
672
- rootId
673
- };
674
- default:
675
- return false;
840
+ function stringifyRule(rule2) {
841
+ let importStringified;
842
+ if (isCSSImportRule(rule2)) {
843
+ try {
844
+ importStringified = // for same-origin stylesheets,
845
+ // we can access the imported stylesheet rules directly
846
+ stringifyStylesheet(rule2.styleSheet) || // work around browser issues with the raw string `@import url(...)` statement
847
+ escapeImportStatement(rule2);
848
+ } catch (error) {
849
+ }
850
+ } else if (isCSSStyleRule(rule2) && rule2.selectorText.includes(":")) {
851
+ return fixSafariColons(rule2.cssText);
676
852
  }
853
+ return importStringified || rule2.cssText;
677
854
  }
678
- function getRootId(doc, mirror2) {
679
- if (!mirror2.hasNode(doc)) return void 0;
680
- const docId = mirror2.getId(doc);
681
- return docId === 1 ? void 0 : docId;
682
- }
683
- function serializeTextNode(n2, options) {
684
- var _a2;
685
- const { needsMask, maskTextFn, rootId } = options;
686
- const parentTagName = n2.parentNode && n2.parentNode.tagName;
687
- let textContent = n2.textContent;
688
- const isStyle = parentTagName === "STYLE" ? true : void 0;
689
- const isScript = parentTagName === "SCRIPT" ? true : void 0;
690
- if (isStyle && textContent) {
691
- try {
692
- if (n2.nextSibling || n2.previousSibling) {
693
- } else if ((_a2 = n2.parentNode.sheet) == null ? void 0 : _a2.cssRules) {
694
- textContent = stringifyStylesheet(
695
- n2.parentNode.sheet
696
- );
697
- }
698
- } catch (err) {
699
- console.warn(
700
- `Cannot get CSS styles from text's parentNode. Error: ${err}`,
701
- n2
702
- );
703
- }
704
- textContent = absoluteToStylesheet(textContent, getHref(options.doc));
855
+ function fixSafariColons(cssStringified) {
856
+ const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
857
+ return cssStringified.replace(regex, "$1\\$2");
858
+ }
859
+ function isCSSImportRule(rule2) {
860
+ return "styleSheet" in rule2;
861
+ }
862
+ function isCSSStyleRule(rule2) {
863
+ return "selectorText" in rule2;
864
+ }
865
+ let Mirror$1 = class Mirror {
866
+ constructor() {
867
+ __publicField$1$1(this, "idNodeMap", /* @__PURE__ */ new Map());
868
+ __publicField$1$1(this, "nodeMetaMap", /* @__PURE__ */ new WeakMap());
705
869
  }
706
- if (isScript) {
707
- textContent = "SCRIPT_PLACEHOLDER";
870
+ getId(n2) {
871
+ var _a2;
872
+ if (!n2) return -1;
873
+ const id = (_a2 = this.getMeta(n2)) == null ? void 0 : _a2.id;
874
+ return id ?? -1;
708
875
  }
709
- if (!isStyle && !isScript && textContent && needsMask) {
710
- textContent = maskTextFn ? maskTextFn(textContent, n2.parentElement) : textContent.replace(/[\S]/g, "*");
876
+ getNode(id) {
877
+ return this.idNodeMap.get(id) || null;
711
878
  }
712
- return {
713
- type: NodeType$2.Text,
714
- textContent: textContent || "",
715
- isStyle,
716
- rootId
717
- };
718
- }
719
- function serializeElementNode(n2, options) {
720
- const {
721
- doc,
722
- blockClass,
723
- blockSelector,
724
- inlineStylesheet,
725
- maskInputOptions = {},
726
- maskInputFn: maskInputFn2,
727
- dataURLOptions = {},
728
- inlineImages,
729
- recordCanvas,
730
- keepIframeSrcFn,
731
- newlyAddedElement = false,
732
- rootId
733
- } = options;
734
- const needBlock = _isBlockedElement(n2, blockClass, blockSelector);
735
- const tagName = getValidTagName$1(n2);
736
- let attributes = {};
737
- const len = n2.attributes.length;
738
- for (let i2 = 0; i2 < len; i2++) {
739
- const attr = n2.attributes[i2];
740
- if (!ignoreAttribute(tagName, attr.name, attr.value)) {
741
- attributes[attr.name] = transformAttribute(
742
- doc,
743
- tagName,
744
- toLowerCase(attr.name),
745
- attr.value
879
+ getIds() {
880
+ return Array.from(this.idNodeMap.keys());
881
+ }
882
+ getMeta(n2) {
883
+ return this.nodeMetaMap.get(n2) || null;
884
+ }
885
+ // removes the node from idNodeMap
886
+ // doesn't remove the node from nodeMetaMap
887
+ removeNodeFromMap(n2) {
888
+ const id = this.getId(n2);
889
+ this.idNodeMap.delete(id);
890
+ if (n2.childNodes) {
891
+ n2.childNodes.forEach(
892
+ (childNode) => this.removeNodeFromMap(childNode)
746
893
  );
747
894
  }
748
895
  }
749
- if (tagName === "link" && inlineStylesheet) {
750
- const stylesheet = Array.from(doc.styleSheets).find((s2) => {
751
- return s2.href === n2.href;
752
- });
753
- let cssText = null;
754
- if (stylesheet) {
755
- cssText = stringifyStylesheet(stylesheet);
756
- }
757
- if (cssText) {
758
- delete attributes.rel;
759
- delete attributes.href;
760
- attributes._cssText = absoluteToStylesheet(cssText, stylesheet.href);
761
- }
896
+ has(id) {
897
+ return this.idNodeMap.has(id);
762
898
  }
763
- if (tagName === "style" && n2.sheet && // TODO: Currently we only try to get dynamic stylesheet when it is an empty style element
764
- !(n2.innerText || n2.textContent || "").trim().length) {
765
- const cssText = stringifyStylesheet(
766
- n2.sheet
767
- );
768
- if (cssText) {
769
- attributes._cssText = absoluteToStylesheet(cssText, getHref(doc));
770
- }
899
+ hasNode(node2) {
900
+ return this.nodeMetaMap.has(node2);
771
901
  }
772
- if (tagName === "input" || tagName === "textarea" || tagName === "select") {
773
- const value = n2.value;
774
- const checked = n2.checked;
775
- if (attributes.type !== "radio" && attributes.type !== "checkbox" && attributes.type !== "submit" && attributes.type !== "button" && value) {
776
- const maskResult = maskInputValue({
777
- element: n2,
778
- type: getInputType(n2),
779
- tagName,
780
- value,
781
- maskInputOptions,
782
- maskInputFn: maskInputFn2
783
- });
784
- attributes.value = maskResult.value;
785
- if (maskResult.masked) {
786
- attributes.masked = true;
787
- }
788
- } else if (checked) {
789
- attributes.checked = checked;
902
+ add(n2, meta) {
903
+ const id = meta.id;
904
+ this.idNodeMap.set(id, n2);
905
+ this.nodeMetaMap.set(n2, meta);
906
+ }
907
+ replace(id, n2) {
908
+ const oldNode = this.getNode(id);
909
+ if (oldNode) {
910
+ const meta = this.nodeMetaMap.get(oldNode);
911
+ if (meta) this.nodeMetaMap.set(n2, meta);
790
912
  }
913
+ this.idNodeMap.set(id, n2);
791
914
  }
792
- if (tagName === "option") {
793
- if (n2.selected && !maskInputOptions["select"]) {
794
- attributes.selected = true;
915
+ reset() {
916
+ this.idNodeMap = /* @__PURE__ */ new Map();
917
+ this.nodeMetaMap = /* @__PURE__ */ new WeakMap();
918
+ }
919
+ };
920
+ function createMirror$2$1() {
921
+ return new Mirror$1();
922
+ }
923
+ function maskInputValue({
924
+ element,
925
+ maskInputOptions,
926
+ tagName,
927
+ type,
928
+ value,
929
+ maskInputFn: maskInputFn2
930
+ }) {
931
+ let text = value || "";
932
+ let returnText = "";
933
+ const actualType = type && toLowerCase(type);
934
+ let masked = false;
935
+ if (maskInputOptions[tagName.toLowerCase()] || actualType && maskInputOptions[actualType]) {
936
+ if (maskInputFn2) {
937
+ returnText = maskInputFn2(text, element);
795
938
  } else {
796
- delete attributes.selected;
939
+ returnText = "*".repeat(text.length);
797
940
  }
941
+ masked = text !== returnText;
798
942
  }
799
- if (tagName === "canvas" && recordCanvas) {
800
- if (n2.__context === "2d") {
801
- if (!is2DCanvasBlank(n2)) {
802
- attributes.rr_dataURL = n2.toDataURL(
803
- dataURLOptions.type,
804
- dataURLOptions.quality
805
- );
806
- }
807
- } else if (!("__context" in n2)) {
808
- const canvasDataURL = n2.toDataURL(
809
- dataURLOptions.type,
810
- dataURLOptions.quality
811
- );
812
- const blankCanvas = doc.createElement("canvas");
813
- blankCanvas.width = n2.width;
814
- blankCanvas.height = n2.height;
815
- const blankCanvasDataURL = blankCanvas.toDataURL(
816
- dataURLOptions.type,
817
- dataURLOptions.quality
943
+ return { value: returnText, masked };
944
+ }
945
+ function toLowerCase(str) {
946
+ return str.toLowerCase();
947
+ }
948
+ const ORIGINAL_ATTRIBUTE_NAME = "__rrweb_original__";
949
+ function is2DCanvasBlank(canvas) {
950
+ const ctx = canvas.getContext("2d");
951
+ if (!ctx) return true;
952
+ const chunkSize = 50;
953
+ for (let x2 = 0; x2 < canvas.width; x2 += chunkSize) {
954
+ for (let y = 0; y < canvas.height; y += chunkSize) {
955
+ const getImageData = ctx.getImageData;
956
+ const originalGetImageData = ORIGINAL_ATTRIBUTE_NAME in getImageData ? getImageData[ORIGINAL_ATTRIBUTE_NAME] : getImageData;
957
+ const pixelBuffer = new Uint32Array(
958
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
959
+ originalGetImageData.call(
960
+ ctx,
961
+ x2,
962
+ y,
963
+ Math.min(chunkSize, canvas.width - x2),
964
+ Math.min(chunkSize, canvas.height - y)
965
+ ).data.buffer
818
966
  );
819
- if (canvasDataURL !== blankCanvasDataURL) {
820
- attributes.rr_dataURL = canvasDataURL;
821
- }
967
+ if (pixelBuffer.some((pixel) => pixel !== 0)) return false;
822
968
  }
823
969
  }
824
- if (tagName === "img" && inlineImages) {
825
- if (!canvasService) {
826
- canvasService = doc.createElement("canvas");
827
- canvasCtx = canvasService.getContext("2d");
828
- }
829
- const image = n2;
830
- const imageSrc = image.currentSrc || image.getAttribute("src") || "<unknown-src>";
831
- const priorCrossOrigin = image.crossOrigin;
832
- const recordInlineImage = () => {
833
- image.removeEventListener("load", recordInlineImage);
834
- try {
835
- canvasService.width = image.naturalWidth;
836
- canvasService.height = image.naturalHeight;
837
- canvasCtx.drawImage(image, 0, 0);
838
- attributes.rr_dataURL = canvasService.toDataURL(
839
- dataURLOptions.type,
840
- dataURLOptions.quality
841
- );
842
- } catch (err) {
843
- if (image.crossOrigin !== "anonymous") {
844
- image.crossOrigin = "anonymous";
845
- if (image.complete && image.naturalWidth !== 0)
846
- recordInlineImage();
847
- else image.addEventListener("load", recordInlineImage);
848
- return;
849
- } else {
850
- console.warn(
851
- `Cannot inline img src=${imageSrc}! Error: ${err}`
852
- );
853
- }
854
- }
855
- if (image.crossOrigin === "anonymous") {
856
- priorCrossOrigin ? attributes.crossOrigin = priorCrossOrigin : image.removeAttribute("crossorigin");
970
+ return true;
971
+ }
972
+ function getInputType(element) {
973
+ const type = element.type;
974
+ return element.hasAttribute("data-rr-is-password") ? "password" : type ? (
975
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
976
+ toLowerCase(type)
977
+ ) : null;
978
+ }
979
+ function extractFileExtension(path, baseURL) {
980
+ let url;
981
+ try {
982
+ url = new URL(path, baseURL ?? window.location.href);
983
+ } catch (err) {
984
+ return null;
985
+ }
986
+ const regex = /\.([0-9a-z]+)(?:$)/i;
987
+ const match = url.pathname.match(regex);
988
+ return (match == null ? void 0 : match[1]) ?? null;
989
+ }
990
+ let _id = 1;
991
+ const tagNameRegex = new RegExp("[^a-z0-9-_:]");
992
+ const IGNORED_NODE$1 = -2;
993
+ function genId() {
994
+ return _id++;
995
+ }
996
+ function getValidTagName$1(element) {
997
+ if (element instanceof HTMLFormElement) {
998
+ return "form";
999
+ }
1000
+ const processedTagName = toLowerCase(element.tagName);
1001
+ if (tagNameRegex.test(processedTagName)) {
1002
+ return "div";
1003
+ }
1004
+ return processedTagName;
1005
+ }
1006
+ function extractOrigin(url) {
1007
+ let origin = "";
1008
+ if (url.indexOf("//") > -1) {
1009
+ origin = url.split("/").slice(0, 3).join("/");
1010
+ } else {
1011
+ origin = url.split("/")[0];
1012
+ }
1013
+ origin = origin.split("?")[0];
1014
+ return origin;
1015
+ }
1016
+ let canvasService;
1017
+ let canvasCtx;
1018
+ const URL_IN_CSS_REF = /url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm;
1019
+ const URL_PROTOCOL_MATCH = /^(?:[a-z+]+:)?\/\//i;
1020
+ const URL_WWW_MATCH = /^www\..*/i;
1021
+ const DATA_URI = /^(data:)([^,]*),(.*)/i;
1022
+ function absoluteToStylesheet(cssText, href) {
1023
+ return (cssText || "").replace(
1024
+ URL_IN_CSS_REF,
1025
+ (origin, quote1, path1, quote2, path2, path3) => {
1026
+ const filePath = path1 || path2 || path3;
1027
+ const maybeQuote = quote1 || quote2 || "";
1028
+ if (!filePath) {
1029
+ return origin;
857
1030
  }
858
- };
859
- if (image.complete && image.naturalWidth !== 0) recordInlineImage();
860
- else image.addEventListener("load", recordInlineImage);
1031
+ if (URL_PROTOCOL_MATCH.test(filePath) || URL_WWW_MATCH.test(filePath)) {
1032
+ return `url(${maybeQuote}${filePath}${maybeQuote})`;
1033
+ }
1034
+ if (DATA_URI.test(filePath)) {
1035
+ return `url(${maybeQuote}${filePath}${maybeQuote})`;
1036
+ }
1037
+ if (filePath[0] === "/") {
1038
+ return `url(${maybeQuote}${extractOrigin(href) + filePath}${maybeQuote})`;
1039
+ }
1040
+ const stack = href.split("/");
1041
+ const parts = filePath.split("/");
1042
+ stack.pop();
1043
+ for (const part of parts) {
1044
+ if (part === ".") {
1045
+ continue;
1046
+ } else if (part === "..") {
1047
+ stack.pop();
1048
+ } else {
1049
+ stack.push(part);
1050
+ }
1051
+ }
1052
+ return `url(${maybeQuote}${stack.join("/")}${maybeQuote})`;
1053
+ }
1054
+ );
1055
+ }
1056
+ const SRCSET_NOT_SPACES = /^[^ \t\n\r\u000c]+/;
1057
+ const SRCSET_COMMAS_OR_SPACES = /^[, \t\n\r\u000c]+/;
1058
+ function getAbsoluteSrcsetString(doc, attributeValue) {
1059
+ if (attributeValue.trim() === "") {
1060
+ return attributeValue;
861
1061
  }
862
- if (tagName === "audio" || tagName === "video") {
863
- const mediaAttributes = attributes;
864
- mediaAttributes.rr_mediaState = n2.paused ? "paused" : "played";
865
- mediaAttributes.rr_mediaCurrentTime = n2.currentTime;
866
- mediaAttributes.rr_mediaPlaybackRate = n2.playbackRate;
867
- mediaAttributes.rr_mediaMuted = n2.muted;
868
- mediaAttributes.rr_mediaLoop = n2.loop;
869
- mediaAttributes.rr_mediaVolume = n2.volume;
1062
+ let pos = 0;
1063
+ function collectCharacters(regEx) {
1064
+ let chars2;
1065
+ const match = regEx.exec(attributeValue.substring(pos));
1066
+ if (match) {
1067
+ chars2 = match[0];
1068
+ pos += chars2.length;
1069
+ return chars2;
1070
+ }
1071
+ return "";
870
1072
  }
871
- if (!newlyAddedElement) {
872
- if (n2.scrollLeft) {
873
- attributes.rr_scrollLeft = n2.scrollLeft;
1073
+ const output = [];
1074
+ while (true) {
1075
+ collectCharacters(SRCSET_COMMAS_OR_SPACES);
1076
+ if (pos >= attributeValue.length) {
1077
+ break;
874
1078
  }
875
- if (n2.scrollTop) {
876
- attributes.rr_scrollTop = n2.scrollTop;
1079
+ let url = collectCharacters(SRCSET_NOT_SPACES);
1080
+ if (url.slice(-1) === ",") {
1081
+ url = absoluteToDoc(doc, url.substring(0, url.length - 1));
1082
+ output.push(url);
1083
+ } else {
1084
+ let descriptorsStr = "";
1085
+ url = absoluteToDoc(doc, url);
1086
+ let inParens = false;
1087
+ while (true) {
1088
+ const c2 = attributeValue.charAt(pos);
1089
+ if (c2 === "") {
1090
+ output.push((url + descriptorsStr).trim());
1091
+ break;
1092
+ } else if (!inParens) {
1093
+ if (c2 === ",") {
1094
+ pos += 1;
1095
+ output.push((url + descriptorsStr).trim());
1096
+ break;
1097
+ } else if (c2 === "(") {
1098
+ inParens = true;
1099
+ }
1100
+ } else {
1101
+ if (c2 === ")") {
1102
+ inParens = false;
1103
+ }
1104
+ }
1105
+ descriptorsStr += c2;
1106
+ pos += 1;
1107
+ }
877
1108
  }
878
1109
  }
879
- if (needBlock) {
880
- const { width, height } = n2.getBoundingClientRect();
881
- attributes = {
882
- class: attributes.class,
883
- rr_width: `${width}px`,
884
- rr_height: `${height}px`
885
- };
1110
+ return output.join(", ");
1111
+ }
1112
+ const cachedDocument = /* @__PURE__ */ new WeakMap();
1113
+ function absoluteToDoc(doc, attributeValue) {
1114
+ if (!attributeValue || attributeValue.trim() === "") {
1115
+ return attributeValue;
886
1116
  }
887
- if (tagName === "iframe" && !keepIframeSrcFn(attributes.src)) {
888
- if (!n2.contentDocument) {
889
- attributes.rr_src = attributes.src;
890
- }
891
- delete attributes.src;
1117
+ return getHref(doc, attributeValue);
1118
+ }
1119
+ function isSVGElement(el) {
1120
+ return Boolean(el.tagName === "svg" || el.ownerSVGElement);
1121
+ }
1122
+ function getHref(doc, customHref) {
1123
+ let a2 = cachedDocument.get(doc);
1124
+ if (!a2) {
1125
+ a2 = doc.createElement("a");
1126
+ cachedDocument.set(doc, a2);
892
1127
  }
893
- let isCustomElement;
894
- try {
895
- if (customElements.get(tagName)) isCustomElement = true;
896
- } catch (e2) {
1128
+ if (!customHref) {
1129
+ customHref = "";
1130
+ } else if (customHref.startsWith("blob:") || customHref.startsWith("data:")) {
1131
+ return customHref;
897
1132
  }
898
- return {
899
- type: NodeType$2.Element,
900
- tagName,
901
- attributes,
902
- childNodes: [],
903
- isSVG: isSVGElement(n2) || void 0,
904
- needBlock,
905
- rootId,
906
- isCustom: isCustomElement
907
- };
1133
+ a2.setAttribute("href", customHref);
1134
+ return a2.href;
908
1135
  }
909
- function lowerIfExists(maybeAttr) {
910
- if (maybeAttr === void 0 || maybeAttr === null) {
911
- return "";
912
- } else {
913
- return maybeAttr.toLowerCase();
1136
+ function transformAttribute(doc, tagName, name, value) {
1137
+ if (!value) {
1138
+ return value;
1139
+ }
1140
+ if (name === "src" || name === "href" && !(tagName === "use" && value[0] === "#")) {
1141
+ return absoluteToDoc(doc, value);
1142
+ } else if (name === "xlink:href" && value[0] !== "#") {
1143
+ return absoluteToDoc(doc, value);
1144
+ } else if (name === "background" && (tagName === "table" || tagName === "td" || tagName === "th")) {
1145
+ return absoluteToDoc(doc, value);
1146
+ } else if (name === "srcset") {
1147
+ return getAbsoluteSrcsetString(doc, value);
1148
+ } else if (name === "style") {
1149
+ return absoluteToStylesheet(value, getHref(doc));
1150
+ } else if (tagName === "object" && name === "data") {
1151
+ return absoluteToDoc(doc, value);
914
1152
  }
1153
+ return value;
915
1154
  }
916
- function slimDOMExcluded(sn, slimDOMOptions) {
917
- if (slimDOMOptions.comment && sn.type === NodeType$2.Comment) {
918
- return true;
919
- } else if (sn.type === NodeType$2.Element) {
920
- if (slimDOMOptions.script && // script tag
921
- (sn.tagName === "script" || // (module)preload link
922
- sn.tagName === "link" && (sn.attributes.rel === "preload" || sn.attributes.rel === "modulepreload") && sn.attributes.as === "script" || // prefetch link
923
- sn.tagName === "link" && sn.attributes.rel === "prefetch" && typeof sn.attributes.href === "string" && extractFileExtension(sn.attributes.href) === "js")) {
924
- return true;
925
- } else if (slimDOMOptions.headFavicon && (sn.tagName === "link" && sn.attributes.rel === "shortcut icon" || sn.tagName === "meta" && (lowerIfExists(sn.attributes.name).match(
926
- /^msapplication-tile(image|color)$/
927
- ) || lowerIfExists(sn.attributes.name) === "application-name" || lowerIfExists(sn.attributes.rel) === "icon" || lowerIfExists(sn.attributes.rel) === "apple-touch-icon" || lowerIfExists(sn.attributes.rel) === "shortcut icon"))) {
928
- return true;
929
- } else if (sn.tagName === "meta") {
930
- if (slimDOMOptions.headMetaDescKeywords && lowerIfExists(sn.attributes.name).match(/^description|keywords$/)) {
931
- return true;
932
- } else if (slimDOMOptions.headMetaSocial && (lowerIfExists(sn.attributes.property).match(/^(og|twitter|fb):/) || // og = opengraph (facebook)
933
- lowerIfExists(sn.attributes.name).match(/^(og|twitter):/) || lowerIfExists(sn.attributes.name) === "pinterest")) {
934
- return true;
935
- } else if (slimDOMOptions.headMetaRobots && (lowerIfExists(sn.attributes.name) === "robots" || lowerIfExists(sn.attributes.name) === "googlebot" || lowerIfExists(sn.attributes.name) === "bingbot")) {
936
- return true;
937
- } else if (slimDOMOptions.headMetaHttpEquiv && sn.attributes["http-equiv"] !== void 0) {
938
- return true;
939
- } else if (slimDOMOptions.headMetaAuthorship && (lowerIfExists(sn.attributes.name) === "author" || lowerIfExists(sn.attributes.name) === "generator" || lowerIfExists(sn.attributes.name) === "framework" || lowerIfExists(sn.attributes.name) === "publisher" || lowerIfExists(sn.attributes.name) === "progid" || lowerIfExists(sn.attributes.property).match(/^article:/) || lowerIfExists(sn.attributes.property).match(/^product:/))) {
940
- return true;
941
- } else if (slimDOMOptions.headMetaVerification && (lowerIfExists(sn.attributes.name) === "google-site-verification" || lowerIfExists(sn.attributes.name) === "yandex-verification" || lowerIfExists(sn.attributes.name) === "csrf-token" || lowerIfExists(sn.attributes.name) === "p:domain_verify" || lowerIfExists(sn.attributes.name) === "verify-v1" || lowerIfExists(sn.attributes.name) === "verification" || lowerIfExists(sn.attributes.name) === "shopify-checkout-api-token")) {
1155
+ function ignoreAttribute(tagName, name, _value) {
1156
+ return (tagName === "video" || tagName === "audio") && name === "autoplay";
1157
+ }
1158
+ function _isBlockedElement(element, blockClass, blockSelector) {
1159
+ try {
1160
+ if (typeof blockClass === "string") {
1161
+ if (element.classList.contains(blockClass)) {
942
1162
  return true;
943
1163
  }
944
- }
945
- }
946
- return false;
1164
+ } else {
1165
+ for (let eIndex = element.classList.length; eIndex--; ) {
1166
+ const className = element.classList[eIndex];
1167
+ if (blockClass.test(className)) {
1168
+ return true;
1169
+ }
1170
+ }
1171
+ }
1172
+ if (blockSelector) {
1173
+ return element.matches(blockSelector);
1174
+ }
1175
+ } catch (e2) {
1176
+ }
1177
+ return false;
947
1178
  }
948
- function serializeNodeWithId(n2, options) {
1179
+ function classMatchesRegex$1(node2, regex, checkAncestors) {
1180
+ if (!node2) return false;
1181
+ if (node2.nodeType !== node2.ELEMENT_NODE) {
1182
+ if (!checkAncestors) return false;
1183
+ return classMatchesRegex$1(node2.parentNode, regex, checkAncestors);
1184
+ }
1185
+ for (let eIndex = node2.classList.length; eIndex--; ) {
1186
+ const className = node2.classList[eIndex];
1187
+ if (regex.test(className)) {
1188
+ return true;
1189
+ }
1190
+ }
1191
+ if (!checkAncestors) return false;
1192
+ return classMatchesRegex$1(node2.parentNode, regex, checkAncestors);
1193
+ }
1194
+ function needMaskingText(node2, maskTextClass, maskTextSelector, checkAncestors) {
1195
+ let el;
1196
+ if (isElement(node2)) {
1197
+ el = node2;
1198
+ if (!el.childNodes.length) {
1199
+ return false;
1200
+ }
1201
+ } else if (node2.parentElement === null) {
1202
+ return false;
1203
+ } else {
1204
+ el = node2.parentElement;
1205
+ }
1206
+ try {
1207
+ if (typeof maskTextClass === "string") {
1208
+ if (checkAncestors) {
1209
+ if (el.closest(`.${maskTextClass}`)) return true;
1210
+ } else {
1211
+ if (el.classList.contains(maskTextClass)) return true;
1212
+ }
1213
+ } else {
1214
+ if (classMatchesRegex$1(el, maskTextClass, checkAncestors)) return true;
1215
+ }
1216
+ if (maskTextSelector) {
1217
+ if (checkAncestors) {
1218
+ if (el.closest(maskTextSelector)) return true;
1219
+ } else {
1220
+ if (el.matches(maskTextSelector)) return true;
1221
+ }
1222
+ }
1223
+ } catch (e2) {
1224
+ }
1225
+ return false;
1226
+ }
1227
+ function onceIframeLoaded(iframeEl, listener, iframeLoadTimeout) {
1228
+ const win = iframeEl.contentWindow;
1229
+ if (!win) {
1230
+ return;
1231
+ }
1232
+ let fired = false;
1233
+ let readyState;
1234
+ try {
1235
+ readyState = win.document.readyState;
1236
+ } catch (error) {
1237
+ return;
1238
+ }
1239
+ if (readyState !== "complete") {
1240
+ const timer = setTimeout(() => {
1241
+ if (!fired) {
1242
+ listener();
1243
+ fired = true;
1244
+ }
1245
+ }, iframeLoadTimeout);
1246
+ iframeEl.addEventListener("load", () => {
1247
+ clearTimeout(timer);
1248
+ fired = true;
1249
+ listener();
1250
+ });
1251
+ return;
1252
+ }
1253
+ const blankUrl = "about:blank";
1254
+ if (win.location.href !== blankUrl || iframeEl.src === blankUrl || iframeEl.src === "") {
1255
+ setTimeout(listener, 0);
1256
+ return iframeEl.addEventListener("load", listener);
1257
+ }
1258
+ iframeEl.addEventListener("load", listener);
1259
+ }
1260
+ function onceStylesheetLoaded(link, listener, styleSheetLoadTimeout) {
1261
+ let fired = false;
1262
+ let styleSheetLoaded;
1263
+ try {
1264
+ styleSheetLoaded = link.sheet;
1265
+ } catch (error) {
1266
+ return;
1267
+ }
1268
+ if (styleSheetLoaded) return;
1269
+ const timer = setTimeout(() => {
1270
+ if (!fired) {
1271
+ listener();
1272
+ fired = true;
1273
+ }
1274
+ }, styleSheetLoadTimeout);
1275
+ link.addEventListener("load", () => {
1276
+ clearTimeout(timer);
1277
+ fired = true;
1278
+ listener();
1279
+ });
1280
+ }
1281
+ function serializeNode(n2, options) {
949
1282
  const {
950
1283
  doc,
951
1284
  mirror: mirror2,
952
1285
  blockClass,
953
1286
  blockSelector,
954
- maskTextClass,
955
- maskTextSelector,
956
- skipChild = false,
957
- inlineStylesheet = true,
1287
+ needsMask,
1288
+ inlineStylesheet,
958
1289
  maskInputOptions = {},
959
1290
  maskTextFn,
960
1291
  maskInputFn: maskInputFn2,
961
- slimDOMOptions,
962
1292
  dataURLOptions = {},
963
- inlineImages = false,
964
- recordCanvas = false,
965
- onSerialize,
966
- onIframeLoad,
967
- iframeLoadTimeout = 5e3,
968
- onStylesheetLoad,
969
- stylesheetLoadTimeout = 5e3,
970
- keepIframeSrcFn = () => false,
1293
+ inlineImages,
1294
+ recordCanvas,
1295
+ keepIframeSrcFn,
971
1296
  newlyAddedElement = false
972
1297
  } = options;
973
- let { needsMask } = options;
974
- let { preserveWhiteSpace = true } = options;
975
- if (!needsMask) {
976
- const checkAncestors = needsMask === void 0;
977
- needsMask = needMaskingText(
978
- n2,
979
- maskTextClass,
980
- maskTextSelector,
981
- checkAncestors
982
- );
1298
+ const rootId = getRootId(doc, mirror2);
1299
+ switch (n2.nodeType) {
1300
+ case n2.DOCUMENT_NODE:
1301
+ if (n2.compatMode !== "CSS1Compat") {
1302
+ return {
1303
+ type: NodeType$2.Document,
1304
+ childNodes: [],
1305
+ compatMode: n2.compatMode
1306
+ // probably "BackCompat"
1307
+ };
1308
+ } else {
1309
+ return {
1310
+ type: NodeType$2.Document,
1311
+ childNodes: []
1312
+ };
1313
+ }
1314
+ case n2.DOCUMENT_TYPE_NODE:
1315
+ return {
1316
+ type: NodeType$2.DocumentType,
1317
+ name: n2.name,
1318
+ publicId: n2.publicId,
1319
+ systemId: n2.systemId,
1320
+ rootId
1321
+ };
1322
+ case n2.ELEMENT_NODE:
1323
+ return serializeElementNode(n2, {
1324
+ doc,
1325
+ blockClass,
1326
+ blockSelector,
1327
+ inlineStylesheet,
1328
+ maskInputOptions,
1329
+ maskInputFn: maskInputFn2,
1330
+ dataURLOptions,
1331
+ inlineImages,
1332
+ recordCanvas,
1333
+ keepIframeSrcFn,
1334
+ newlyAddedElement,
1335
+ rootId
1336
+ });
1337
+ case n2.TEXT_NODE:
1338
+ return serializeTextNode(n2, {
1339
+ doc,
1340
+ needsMask,
1341
+ maskTextFn,
1342
+ rootId
1343
+ });
1344
+ case n2.CDATA_SECTION_NODE:
1345
+ return {
1346
+ type: NodeType$2.CDATA,
1347
+ textContent: "",
1348
+ rootId
1349
+ };
1350
+ case n2.COMMENT_NODE:
1351
+ return {
1352
+ type: NodeType$2.Comment,
1353
+ textContent: n2.textContent || "",
1354
+ rootId
1355
+ };
1356
+ default:
1357
+ return false;
983
1358
  }
984
- const _serializedNode = serializeNode(n2, {
1359
+ }
1360
+ function getRootId(doc, mirror2) {
1361
+ if (!mirror2.hasNode(doc)) return void 0;
1362
+ const docId = mirror2.getId(doc);
1363
+ return docId === 1 ? void 0 : docId;
1364
+ }
1365
+ function serializeTextNode(n2, options) {
1366
+ var _a2;
1367
+ const { needsMask, maskTextFn, rootId } = options;
1368
+ const parentTagName = n2.parentNode && n2.parentNode.tagName;
1369
+ let textContent = n2.textContent;
1370
+ const isStyle = parentTagName === "STYLE" ? true : void 0;
1371
+ const isScript = parentTagName === "SCRIPT" ? true : void 0;
1372
+ if (isStyle && textContent) {
1373
+ try {
1374
+ if (n2.nextSibling || n2.previousSibling) {
1375
+ } else if ((_a2 = n2.parentNode.sheet) == null ? void 0 : _a2.cssRules) {
1376
+ textContent = stringifyStylesheet(
1377
+ n2.parentNode.sheet
1378
+ );
1379
+ }
1380
+ } catch (err) {
1381
+ console.warn(
1382
+ `Cannot get CSS styles from text's parentNode. Error: ${err}`,
1383
+ n2
1384
+ );
1385
+ }
1386
+ textContent = absoluteToStylesheet(textContent, getHref(options.doc));
1387
+ }
1388
+ if (isScript) {
1389
+ textContent = "SCRIPT_PLACEHOLDER";
1390
+ }
1391
+ if (!isStyle && !isScript && textContent && needsMask) {
1392
+ textContent = maskTextFn ? maskTextFn(textContent, n2.parentElement) : textContent.replace(/[\S]/g, "*");
1393
+ }
1394
+ return {
1395
+ type: NodeType$2.Text,
1396
+ textContent: textContent || "",
1397
+ isStyle,
1398
+ rootId
1399
+ };
1400
+ }
1401
+ function serializeElementNode(n2, options) {
1402
+ const {
985
1403
  doc,
986
- mirror: mirror2,
987
1404
  blockClass,
988
1405
  blockSelector,
989
- needsMask,
990
1406
  inlineStylesheet,
991
- maskInputOptions,
992
- maskTextFn,
1407
+ maskInputOptions = {},
993
1408
  maskInputFn: maskInputFn2,
994
- dataURLOptions,
1409
+ dataURLOptions = {},
995
1410
  inlineImages,
996
1411
  recordCanvas,
997
1412
  keepIframeSrcFn,
998
- newlyAddedElement
999
- });
1000
- if (!_serializedNode) {
1001
- console.warn(n2, "not serialized");
1002
- return null;
1003
- }
1004
- let id;
1005
- if (mirror2.hasNode(n2)) {
1006
- id = mirror2.getId(n2);
1007
- } else if (slimDOMExcluded(_serializedNode, slimDOMOptions) || !preserveWhiteSpace && _serializedNode.type === NodeType$2.Text && !_serializedNode.isStyle && !_serializedNode.textContent.replace(/^\s+|\s+$/gm, "").length) {
1008
- id = IGNORED_NODE$1;
1009
- } else {
1010
- id = genId();
1413
+ newlyAddedElement = false,
1414
+ rootId
1415
+ } = options;
1416
+ const needBlock = _isBlockedElement(n2, blockClass, blockSelector);
1417
+ const tagName = getValidTagName$1(n2);
1418
+ let attributes = {};
1419
+ const len = n2.attributes.length;
1420
+ for (let i2 = 0; i2 < len; i2++) {
1421
+ const attr = n2.attributes[i2];
1422
+ if (!ignoreAttribute(tagName, attr.name, attr.value)) {
1423
+ attributes[attr.name] = transformAttribute(
1424
+ doc,
1425
+ tagName,
1426
+ toLowerCase(attr.name),
1427
+ attr.value
1428
+ );
1429
+ }
1011
1430
  }
1012
- const serializedNode = Object.assign(_serializedNode, { id });
1013
- mirror2.add(n2, serializedNode);
1014
- if (id === IGNORED_NODE$1) {
1015
- return null;
1431
+ if (tagName === "link" && inlineStylesheet) {
1432
+ const stylesheet = Array.from(doc.styleSheets).find((s2) => {
1433
+ return s2.href === n2.href;
1434
+ });
1435
+ let cssText = null;
1436
+ if (stylesheet) {
1437
+ cssText = stringifyStylesheet(stylesheet);
1438
+ }
1439
+ if (cssText) {
1440
+ delete attributes.rel;
1441
+ delete attributes.href;
1442
+ attributes._cssText = absoluteToStylesheet(cssText, stylesheet.href);
1443
+ }
1016
1444
  }
1017
- if (onSerialize) {
1018
- onSerialize(n2);
1445
+ if (tagName === "style" && n2.sheet && // TODO: Currently we only try to get dynamic stylesheet when it is an empty style element
1446
+ !(n2.innerText || n2.textContent || "").trim().length) {
1447
+ const cssText = stringifyStylesheet(
1448
+ n2.sheet
1449
+ );
1450
+ if (cssText) {
1451
+ attributes._cssText = absoluteToStylesheet(cssText, getHref(doc));
1452
+ }
1019
1453
  }
1020
- let recordChild = !skipChild;
1021
- if (serializedNode.type === NodeType$2.Element) {
1022
- recordChild = recordChild && !serializedNode.needBlock;
1023
- delete serializedNode.needBlock;
1024
- const shadowRoot = n2.shadowRoot;
1025
- if (shadowRoot && isNativeShadowDom(shadowRoot))
1026
- serializedNode.isShadowHost = true;
1454
+ if (tagName === "input" || tagName === "textarea" || tagName === "select") {
1455
+ const value = n2.value;
1456
+ const checked = n2.checked;
1457
+ if (attributes.type !== "radio" && attributes.type !== "checkbox" && attributes.type !== "submit" && attributes.type !== "button" && value) {
1458
+ const maskResult = maskInputValue({
1459
+ element: n2,
1460
+ type: getInputType(n2),
1461
+ tagName,
1462
+ value,
1463
+ maskInputOptions,
1464
+ maskInputFn: maskInputFn2
1465
+ });
1466
+ attributes.value = maskResult.value;
1467
+ if (maskResult.masked) {
1468
+ attributes.masked = true;
1469
+ }
1470
+ } else if (checked) {
1471
+ attributes.checked = checked;
1472
+ }
1027
1473
  }
1028
- if ((serializedNode.type === NodeType$2.Document || serializedNode.type === NodeType$2.Element) && recordChild) {
1029
- if (slimDOMOptions.headWhitespace && serializedNode.type === NodeType$2.Element && serializedNode.tagName === "head") {
1030
- preserveWhiteSpace = false;
1474
+ if (tagName === "option") {
1475
+ if (n2.selected && !maskInputOptions["select"]) {
1476
+ attributes.selected = true;
1477
+ } else {
1478
+ delete attributes.selected;
1031
1479
  }
1032
- const bypassOptions = {
1033
- doc,
1034
- mirror: mirror2,
1035
- blockClass,
1036
- blockSelector,
1037
- needsMask,
1038
- maskTextClass,
1039
- maskTextSelector,
1040
- skipChild,
1041
- inlineStylesheet,
1042
- maskInputOptions,
1043
- maskTextFn,
1044
- maskInputFn: maskInputFn2,
1045
- slimDOMOptions,
1046
- dataURLOptions,
1047
- inlineImages,
1048
- recordCanvas,
1049
- preserveWhiteSpace,
1050
- onSerialize,
1051
- onIframeLoad,
1052
- iframeLoadTimeout,
1053
- onStylesheetLoad,
1054
- stylesheetLoadTimeout,
1055
- keepIframeSrcFn
1056
- };
1057
- if (serializedNode.type === NodeType$2.Element && serializedNode.tagName === "textarea" && serializedNode.attributes.value !== void 0) ;
1058
- else {
1059
- for (const childN of Array.from(n2.childNodes)) {
1060
- const serializedChildNode = serializeNodeWithId(childN, bypassOptions);
1061
- if (serializedChildNode) {
1062
- serializedNode.childNodes.push(serializedChildNode);
1063
- }
1480
+ }
1481
+ if (tagName === "canvas" && recordCanvas) {
1482
+ if (n2.__context === "2d") {
1483
+ if (!is2DCanvasBlank(n2)) {
1484
+ attributes.rr_dataURL = n2.toDataURL(
1485
+ dataURLOptions.type,
1486
+ dataURLOptions.quality
1487
+ );
1488
+ }
1489
+ } else if (!("__context" in n2)) {
1490
+ const canvasDataURL = n2.toDataURL(
1491
+ dataURLOptions.type,
1492
+ dataURLOptions.quality
1493
+ );
1494
+ const blankCanvas = doc.createElement("canvas");
1495
+ blankCanvas.width = n2.width;
1496
+ blankCanvas.height = n2.height;
1497
+ const blankCanvasDataURL = blankCanvas.toDataURL(
1498
+ dataURLOptions.type,
1499
+ dataURLOptions.quality
1500
+ );
1501
+ if (canvasDataURL !== blankCanvasDataURL) {
1502
+ attributes.rr_dataURL = canvasDataURL;
1064
1503
  }
1065
1504
  }
1066
- if (isElement(n2) && n2.shadowRoot) {
1067
- for (const childN of Array.from(n2.shadowRoot.childNodes)) {
1068
- const serializedChildNode = serializeNodeWithId(childN, bypassOptions);
1069
- if (serializedChildNode) {
1070
- isNativeShadowDom(n2.shadowRoot) && (serializedChildNode.isShadow = true);
1071
- serializedNode.childNodes.push(serializedChildNode);
1505
+ }
1506
+ if (tagName === "img" && inlineImages) {
1507
+ if (!canvasService) {
1508
+ canvasService = doc.createElement("canvas");
1509
+ canvasCtx = canvasService.getContext("2d");
1510
+ }
1511
+ const image = n2;
1512
+ const imageSrc = image.currentSrc || image.getAttribute("src") || "<unknown-src>";
1513
+ const priorCrossOrigin = image.crossOrigin;
1514
+ const recordInlineImage = () => {
1515
+ image.removeEventListener("load", recordInlineImage);
1516
+ try {
1517
+ canvasService.width = image.naturalWidth;
1518
+ canvasService.height = image.naturalHeight;
1519
+ canvasCtx.drawImage(image, 0, 0);
1520
+ attributes.rr_dataURL = canvasService.toDataURL(
1521
+ dataURLOptions.type,
1522
+ dataURLOptions.quality
1523
+ );
1524
+ } catch (err) {
1525
+ if (image.crossOrigin !== "anonymous") {
1526
+ image.crossOrigin = "anonymous";
1527
+ if (image.complete && image.naturalWidth !== 0)
1528
+ recordInlineImage();
1529
+ else image.addEventListener("load", recordInlineImage);
1530
+ return;
1531
+ } else {
1532
+ console.warn(
1533
+ `Cannot inline img src=${imageSrc}! Error: ${err}`
1534
+ );
1072
1535
  }
1073
1536
  }
1074
- }
1537
+ if (image.crossOrigin === "anonymous") {
1538
+ priorCrossOrigin ? attributes.crossOrigin = priorCrossOrigin : image.removeAttribute("crossorigin");
1539
+ }
1540
+ };
1541
+ if (image.complete && image.naturalWidth !== 0) recordInlineImage();
1542
+ else image.addEventListener("load", recordInlineImage);
1075
1543
  }
1076
- if (n2.parentNode && isShadowRoot$1(n2.parentNode) && isNativeShadowDom(n2.parentNode)) {
1077
- serializedNode.isShadow = true;
1544
+ if (tagName === "audio" || tagName === "video") {
1545
+ const mediaAttributes = attributes;
1546
+ mediaAttributes.rr_mediaState = n2.paused ? "paused" : "played";
1547
+ mediaAttributes.rr_mediaCurrentTime = n2.currentTime;
1548
+ mediaAttributes.rr_mediaPlaybackRate = n2.playbackRate;
1549
+ mediaAttributes.rr_mediaMuted = n2.muted;
1550
+ mediaAttributes.rr_mediaLoop = n2.loop;
1551
+ mediaAttributes.rr_mediaVolume = n2.volume;
1078
1552
  }
1079
- if (serializedNode.type === NodeType$2.Element && serializedNode.tagName === "iframe") {
1080
- onceIframeLoaded(
1081
- n2,
1082
- () => {
1083
- const iframeDoc = n2.contentDocument;
1084
- if (iframeDoc && onIframeLoad) {
1085
- const serializedIframeNode = serializeNodeWithId(iframeDoc, {
1086
- doc: iframeDoc,
1087
- mirror: mirror2,
1088
- blockClass,
1089
- blockSelector,
1090
- needsMask,
1091
- maskTextClass,
1092
- maskTextSelector,
1093
- skipChild: false,
1094
- inlineStylesheet,
1095
- maskInputOptions,
1096
- maskTextFn,
1097
- maskInputFn: maskInputFn2,
1098
- slimDOMOptions,
1099
- dataURLOptions,
1100
- inlineImages,
1101
- recordCanvas,
1102
- preserveWhiteSpace,
1103
- onSerialize,
1104
- onIframeLoad,
1105
- iframeLoadTimeout,
1106
- onStylesheetLoad,
1107
- stylesheetLoadTimeout,
1108
- keepIframeSrcFn
1109
- });
1110
- if (serializedIframeNode) {
1111
- onIframeLoad(
1112
- n2,
1113
- serializedIframeNode
1114
- );
1115
- }
1116
- }
1117
- },
1118
- iframeLoadTimeout
1119
- );
1553
+ if (!newlyAddedElement) {
1554
+ if (n2.scrollLeft) {
1555
+ attributes.rr_scrollLeft = n2.scrollLeft;
1556
+ }
1557
+ if (n2.scrollTop) {
1558
+ attributes.rr_scrollTop = n2.scrollTop;
1559
+ }
1120
1560
  }
1121
- if (serializedNode.type === NodeType$2.Element && serializedNode.tagName === "link" && typeof serializedNode.attributes.rel === "string" && (serializedNode.attributes.rel === "stylesheet" || serializedNode.attributes.rel === "preload" && typeof serializedNode.attributes.href === "string" && extractFileExtension(serializedNode.attributes.href) === "css")) {
1122
- onceStylesheetLoaded(
1123
- n2,
1124
- () => {
1125
- if (onStylesheetLoad) {
1126
- const serializedLinkNode = serializeNodeWithId(n2, {
1127
- doc,
1561
+ if (needBlock) {
1562
+ const { width, height } = n2.getBoundingClientRect();
1563
+ attributes = {
1564
+ class: attributes.class,
1565
+ rr_width: `${width}px`,
1566
+ rr_height: `${height}px`
1567
+ };
1568
+ }
1569
+ if (tagName === "iframe" && !keepIframeSrcFn(attributes.src)) {
1570
+ if (!n2.contentDocument) {
1571
+ attributes.rr_src = attributes.src;
1572
+ }
1573
+ delete attributes.src;
1574
+ }
1575
+ let isCustomElement;
1576
+ try {
1577
+ if (customElements.get(tagName)) isCustomElement = true;
1578
+ } catch (e2) {
1579
+ }
1580
+ return {
1581
+ type: NodeType$2.Element,
1582
+ tagName,
1583
+ attributes,
1584
+ childNodes: [],
1585
+ isSVG: isSVGElement(n2) || void 0,
1586
+ needBlock,
1587
+ rootId,
1588
+ isCustom: isCustomElement
1589
+ };
1590
+ }
1591
+ function lowerIfExists(maybeAttr) {
1592
+ if (maybeAttr === void 0 || maybeAttr === null) {
1593
+ return "";
1594
+ } else {
1595
+ return maybeAttr.toLowerCase();
1596
+ }
1597
+ }
1598
+ function slimDOMExcluded(sn, slimDOMOptions) {
1599
+ if (slimDOMOptions.comment && sn.type === NodeType$2.Comment) {
1600
+ return true;
1601
+ } else if (sn.type === NodeType$2.Element) {
1602
+ if (slimDOMOptions.script && // script tag
1603
+ (sn.tagName === "script" || // (module)preload link
1604
+ sn.tagName === "link" && (sn.attributes.rel === "preload" || sn.attributes.rel === "modulepreload") && sn.attributes.as === "script" || // prefetch link
1605
+ sn.tagName === "link" && sn.attributes.rel === "prefetch" && typeof sn.attributes.href === "string" && extractFileExtension(sn.attributes.href) === "js")) {
1606
+ return true;
1607
+ } else if (slimDOMOptions.headFavicon && (sn.tagName === "link" && sn.attributes.rel === "shortcut icon" || sn.tagName === "meta" && (lowerIfExists(sn.attributes.name).match(
1608
+ /^msapplication-tile(image|color)$/
1609
+ ) || lowerIfExists(sn.attributes.name) === "application-name" || lowerIfExists(sn.attributes.rel) === "icon" || lowerIfExists(sn.attributes.rel) === "apple-touch-icon" || lowerIfExists(sn.attributes.rel) === "shortcut icon"))) {
1610
+ return true;
1611
+ } else if (sn.tagName === "meta") {
1612
+ if (slimDOMOptions.headMetaDescKeywords && lowerIfExists(sn.attributes.name).match(/^description|keywords$/)) {
1613
+ return true;
1614
+ } else if (slimDOMOptions.headMetaSocial && (lowerIfExists(sn.attributes.property).match(/^(og|twitter|fb):/) || // og = opengraph (facebook)
1615
+ lowerIfExists(sn.attributes.name).match(/^(og|twitter):/) || lowerIfExists(sn.attributes.name) === "pinterest")) {
1616
+ return true;
1617
+ } else if (slimDOMOptions.headMetaRobots && (lowerIfExists(sn.attributes.name) === "robots" || lowerIfExists(sn.attributes.name) === "googlebot" || lowerIfExists(sn.attributes.name) === "bingbot")) {
1618
+ return true;
1619
+ } else if (slimDOMOptions.headMetaHttpEquiv && sn.attributes["http-equiv"] !== void 0) {
1620
+ return true;
1621
+ } else if (slimDOMOptions.headMetaAuthorship && (lowerIfExists(sn.attributes.name) === "author" || lowerIfExists(sn.attributes.name) === "generator" || lowerIfExists(sn.attributes.name) === "framework" || lowerIfExists(sn.attributes.name) === "publisher" || lowerIfExists(sn.attributes.name) === "progid" || lowerIfExists(sn.attributes.property).match(/^article:/) || lowerIfExists(sn.attributes.property).match(/^product:/))) {
1622
+ return true;
1623
+ } else if (slimDOMOptions.headMetaVerification && (lowerIfExists(sn.attributes.name) === "google-site-verification" || lowerIfExists(sn.attributes.name) === "yandex-verification" || lowerIfExists(sn.attributes.name) === "csrf-token" || lowerIfExists(sn.attributes.name) === "p:domain_verify" || lowerIfExists(sn.attributes.name) === "verify-v1" || lowerIfExists(sn.attributes.name) === "verification" || lowerIfExists(sn.attributes.name) === "shopify-checkout-api-token")) {
1624
+ return true;
1625
+ }
1626
+ }
1627
+ }
1628
+ return false;
1629
+ }
1630
+ function serializeNodeWithId(n2, options) {
1631
+ const {
1632
+ doc,
1633
+ mirror: mirror2,
1634
+ blockClass,
1635
+ blockSelector,
1636
+ maskTextClass,
1637
+ maskTextSelector,
1638
+ skipChild = false,
1639
+ inlineStylesheet = true,
1640
+ maskInputOptions = {},
1641
+ maskTextFn,
1642
+ maskInputFn: maskInputFn2,
1643
+ slimDOMOptions,
1644
+ dataURLOptions = {},
1645
+ inlineImages = false,
1646
+ recordCanvas = false,
1647
+ onSerialize,
1648
+ onIframeLoad,
1649
+ iframeLoadTimeout = 5e3,
1650
+ onStylesheetLoad,
1651
+ stylesheetLoadTimeout = 5e3,
1652
+ keepIframeSrcFn = () => false,
1653
+ newlyAddedElement = false
1654
+ } = options;
1655
+ let { needsMask } = options;
1656
+ let { preserveWhiteSpace = true } = options;
1657
+ if (!needsMask) {
1658
+ const checkAncestors = needsMask === void 0;
1659
+ needsMask = needMaskingText(
1660
+ n2,
1661
+ maskTextClass,
1662
+ maskTextSelector,
1663
+ checkAncestors
1664
+ );
1665
+ }
1666
+ const _serializedNode = serializeNode(n2, {
1667
+ doc,
1668
+ mirror: mirror2,
1669
+ blockClass,
1670
+ blockSelector,
1671
+ needsMask,
1672
+ inlineStylesheet,
1673
+ maskInputOptions,
1674
+ maskTextFn,
1675
+ maskInputFn: maskInputFn2,
1676
+ dataURLOptions,
1677
+ inlineImages,
1678
+ recordCanvas,
1679
+ keepIframeSrcFn,
1680
+ newlyAddedElement
1681
+ });
1682
+ if (!_serializedNode) {
1683
+ console.warn(n2, "not serialized");
1684
+ return null;
1685
+ }
1686
+ let id;
1687
+ if (mirror2.hasNode(n2)) {
1688
+ id = mirror2.getId(n2);
1689
+ } else if (slimDOMExcluded(_serializedNode, slimDOMOptions) || !preserveWhiteSpace && _serializedNode.type === NodeType$2.Text && !_serializedNode.isStyle && !_serializedNode.textContent.replace(/^\s+|\s+$/gm, "").length) {
1690
+ id = IGNORED_NODE$1;
1691
+ } else {
1692
+ id = genId();
1693
+ }
1694
+ const serializedNode = Object.assign(_serializedNode, { id });
1695
+ mirror2.add(n2, serializedNode);
1696
+ if (id === IGNORED_NODE$1) {
1697
+ return null;
1698
+ }
1699
+ if (onSerialize) {
1700
+ onSerialize(n2);
1701
+ }
1702
+ let recordChild = !skipChild;
1703
+ if (serializedNode.type === NodeType$2.Element) {
1704
+ recordChild = recordChild && !serializedNode.needBlock;
1705
+ delete serializedNode.needBlock;
1706
+ const shadowRoot = n2.shadowRoot;
1707
+ if (shadowRoot && isNativeShadowDom(shadowRoot))
1708
+ serializedNode.isShadowHost = true;
1709
+ }
1710
+ if ((serializedNode.type === NodeType$2.Document || serializedNode.type === NodeType$2.Element) && recordChild) {
1711
+ if (slimDOMOptions.headWhitespace && serializedNode.type === NodeType$2.Element && serializedNode.tagName === "head") {
1712
+ preserveWhiteSpace = false;
1713
+ }
1714
+ const bypassOptions = {
1715
+ doc,
1716
+ mirror: mirror2,
1717
+ blockClass,
1718
+ blockSelector,
1719
+ needsMask,
1720
+ maskTextClass,
1721
+ maskTextSelector,
1722
+ skipChild,
1723
+ inlineStylesheet,
1724
+ maskInputOptions,
1725
+ maskTextFn,
1726
+ maskInputFn: maskInputFn2,
1727
+ slimDOMOptions,
1728
+ dataURLOptions,
1729
+ inlineImages,
1730
+ recordCanvas,
1731
+ preserveWhiteSpace,
1732
+ onSerialize,
1733
+ onIframeLoad,
1734
+ iframeLoadTimeout,
1735
+ onStylesheetLoad,
1736
+ stylesheetLoadTimeout,
1737
+ keepIframeSrcFn
1738
+ };
1739
+ if (serializedNode.type === NodeType$2.Element && serializedNode.tagName === "textarea" && serializedNode.attributes.value !== void 0) ;
1740
+ else {
1741
+ for (const childN of Array.from(n2.childNodes)) {
1742
+ const serializedChildNode = serializeNodeWithId(childN, bypassOptions);
1743
+ if (serializedChildNode) {
1744
+ serializedNode.childNodes.push(serializedChildNode);
1745
+ }
1746
+ }
1747
+ }
1748
+ if (isElement(n2) && n2.shadowRoot) {
1749
+ for (const childN of Array.from(n2.shadowRoot.childNodes)) {
1750
+ const serializedChildNode = serializeNodeWithId(childN, bypassOptions);
1751
+ if (serializedChildNode) {
1752
+ isNativeShadowDom(n2.shadowRoot) && (serializedChildNode.isShadow = true);
1753
+ serializedNode.childNodes.push(serializedChildNode);
1754
+ }
1755
+ }
1756
+ }
1757
+ }
1758
+ if (n2.parentNode && isShadowRoot$1(n2.parentNode) && isNativeShadowDom(n2.parentNode)) {
1759
+ serializedNode.isShadow = true;
1760
+ }
1761
+ if (serializedNode.type === NodeType$2.Element && serializedNode.tagName === "iframe") {
1762
+ onceIframeLoaded(
1763
+ n2,
1764
+ () => {
1765
+ const iframeDoc = n2.contentDocument;
1766
+ if (iframeDoc && onIframeLoad) {
1767
+ const serializedIframeNode = serializeNodeWithId(iframeDoc, {
1768
+ doc: iframeDoc,
1769
+ mirror: mirror2,
1770
+ blockClass,
1771
+ blockSelector,
1772
+ needsMask,
1773
+ maskTextClass,
1774
+ maskTextSelector,
1775
+ skipChild: false,
1776
+ inlineStylesheet,
1777
+ maskInputOptions,
1778
+ maskTextFn,
1779
+ maskInputFn: maskInputFn2,
1780
+ slimDOMOptions,
1781
+ dataURLOptions,
1782
+ inlineImages,
1783
+ recordCanvas,
1784
+ preserveWhiteSpace,
1785
+ onSerialize,
1786
+ onIframeLoad,
1787
+ iframeLoadTimeout,
1788
+ onStylesheetLoad,
1789
+ stylesheetLoadTimeout,
1790
+ keepIframeSrcFn
1791
+ });
1792
+ if (serializedIframeNode) {
1793
+ onIframeLoad(
1794
+ n2,
1795
+ serializedIframeNode
1796
+ );
1797
+ }
1798
+ }
1799
+ },
1800
+ iframeLoadTimeout
1801
+ );
1802
+ }
1803
+ if (serializedNode.type === NodeType$2.Element && serializedNode.tagName === "link" && typeof serializedNode.attributes.rel === "string" && (serializedNode.attributes.rel === "stylesheet" || serializedNode.attributes.rel === "preload" && typeof serializedNode.attributes.href === "string" && extractFileExtension(serializedNode.attributes.href) === "css")) {
1804
+ onceStylesheetLoaded(
1805
+ n2,
1806
+ () => {
1807
+ if (onStylesheetLoad) {
1808
+ const serializedLinkNode = serializeNodeWithId(n2, {
1809
+ doc,
1128
1810
  mirror: mirror2,
1129
1811
  blockClass,
1130
1812
  blockSelector,
@@ -19518,957 +20200,374 @@ const ErrorStackParser = {
19518
20200
  }, this);
19519
20201
  },
19520
20202
  parseFFOrSafari: function(error) {
19521
- const filtered = error.stack.split("\n").filter(function(line) {
19522
- return !line.match(SAFARI_NATIVE_CODE_REGEXP);
19523
- }, this);
19524
- return filtered.map(function(line) {
19525
- if (line.indexOf(" > eval") > -1) {
19526
- line = line.replace(
19527
- / line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,
19528
- ":$1"
19529
- );
19530
- }
19531
- if (line.indexOf("@") === -1 && line.indexOf(":") === -1) {
19532
- return new StackFrame({
19533
- functionName: line
19534
- });
19535
- } else {
19536
- const functionNameRegex = /((.*".+"[^@]*)?[^@]*)(?:@)/;
19537
- const matches = line.match(functionNameRegex);
19538
- const functionName = matches && matches[1] ? matches[1] : void 0;
19539
- const locationParts = this.extractLocation(
19540
- line.replace(functionNameRegex, "")
19541
- );
19542
- return new StackFrame({
19543
- functionName,
19544
- fileName: locationParts[0],
19545
- lineNumber: locationParts[1],
19546
- columnNumber: locationParts[2]
19547
- });
19548
- }
19549
- }, this);
19550
- },
19551
- parseOpera: function(e) {
19552
- if (!e.stacktrace || e.message.indexOf("\n") > -1 && e.message.split("\n").length > e.stacktrace.split("\n").length) {
19553
- return this.parseOpera9(e);
19554
- } else if (!e.stack) {
19555
- return this.parseOpera10(e);
19556
- } else {
19557
- return this.parseOpera11(e);
19558
- }
19559
- },
19560
- parseOpera9: function(e) {
19561
- const lineRE = /Line (\d+).*script (?:in )?(\S+)/i;
19562
- const lines = e.message.split("\n");
19563
- const result2 = [];
19564
- for (let i = 2, len = lines.length; i < len; i += 2) {
19565
- const match = lineRE.exec(lines[i]);
19566
- if (match) {
19567
- result2.push(
19568
- new StackFrame({
19569
- fileName: match[2],
19570
- lineNumber: parseFloat(match[1])
19571
- })
19572
- );
19573
- }
19574
- }
19575
- return result2;
19576
- },
19577
- parseOpera10: function(e) {
19578
- const lineRE = /Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i;
19579
- const lines = e.stacktrace.split("\n");
19580
- const result2 = [];
19581
- for (let i = 0, len = lines.length; i < len; i += 2) {
19582
- const match = lineRE.exec(lines[i]);
19583
- if (match) {
19584
- result2.push(
19585
- new StackFrame({
19586
- functionName: match[3] || void 0,
19587
- fileName: match[2],
19588
- lineNumber: parseFloat(match[1])
19589
- })
19590
- );
19591
- }
19592
- }
19593
- return result2;
19594
- },
19595
- // Opera 10.65+ Error.stack very similar to FF/Safari
19596
- parseOpera11: function(error) {
19597
- const filtered = error.stack.split("\n").filter(function(line) {
19598
- return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && !line.match(/^Error created at/);
19599
- }, this);
19600
- return filtered.map(function(line) {
19601
- const tokens = line.split("@");
19602
- const locationParts = this.extractLocation(tokens.pop());
19603
- const functionCall = tokens.shift() || "";
19604
- const functionName = functionCall.replace(/<anonymous function(: (\w+))?>/, "$2").replace(/\([^)]*\)/g, "") || void 0;
19605
- return new StackFrame({
19606
- functionName,
19607
- fileName: locationParts[0],
19608
- lineNumber: locationParts[1],
19609
- columnNumber: locationParts[2]
19610
- });
19611
- }, this);
19612
- }
19613
- };
19614
- function pathToSelector(node2) {
19615
- if (!node2 || !node2.outerHTML) {
19616
- return "";
19617
- }
19618
- let path = "";
19619
- while (node2.parentElement) {
19620
- let name = node2.localName;
19621
- if (!name) {
19622
- break;
19623
- }
19624
- name = name.toLowerCase();
19625
- const parent = node2.parentElement;
19626
- const domSiblings = [];
19627
- if (parent.children && parent.children.length > 0) {
19628
- for (let i = 0; i < parent.children.length; i++) {
19629
- const sibling = parent.children[i];
19630
- if (sibling.localName && sibling.localName.toLowerCase) {
19631
- if (sibling.localName.toLowerCase() === name) {
19632
- domSiblings.push(sibling);
19633
- }
19634
- }
19635
- }
19636
- }
19637
- if (domSiblings.length > 1) {
19638
- name += `:eq(${domSiblings.indexOf(node2)})`;
19639
- }
19640
- path = name + (path ? ">" + path : "");
19641
- node2 = parent;
19642
- }
19643
- return path;
19644
- }
19645
- function isObject(obj) {
19646
- return Object.prototype.toString.call(obj) === "[object Object]";
19647
- }
19648
- function isObjTooDeep(obj, limit) {
19649
- if (limit === 0) {
19650
- return true;
19651
- }
19652
- const keys = Object.keys(obj);
19653
- for (const key of keys) {
19654
- if (isObject(obj[key]) && isObjTooDeep(obj[key], limit - 1)) {
19655
- return true;
19656
- }
19657
- }
19658
- return false;
19659
- }
19660
- function stringify(obj, stringifyOptions) {
19661
- const options = {
19662
- numOfKeysLimit: 50,
19663
- depthOfLimit: 4
19664
- };
19665
- Object.assign(options, stringifyOptions);
19666
- const stack = [];
19667
- const keys = [];
19668
- return JSON.stringify(
19669
- obj,
19670
- function(key, value) {
19671
- if (stack.length > 0) {
19672
- const thisPos = stack.indexOf(this);
19673
- ~thisPos ? stack.splice(thisPos + 1) : stack.push(this);
19674
- ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key);
19675
- if (~stack.indexOf(value)) {
19676
- if (stack[0] === value) {
19677
- value = "[Circular ~]";
19678
- } else {
19679
- value = "[Circular ~." + keys.slice(0, stack.indexOf(value)).join(".") + "]";
19680
- }
19681
- }
19682
- } else {
19683
- stack.push(value);
19684
- }
19685
- if (value === null) return value;
19686
- if (value === void 0) return "undefined";
19687
- if (shouldIgnore(value)) {
19688
- return toString(value);
19689
- }
19690
- if (typeof value === "bigint") {
19691
- return value.toString() + "n";
19692
- }
19693
- if (value instanceof Event) {
19694
- const eventResult = {};
19695
- for (const eventKey in value) {
19696
- const eventValue = value[eventKey];
19697
- if (Array.isArray(eventValue)) {
19698
- eventResult[eventKey] = pathToSelector(
19699
- eventValue.length ? eventValue[0] : null
19700
- );
19701
- } else {
19702
- eventResult[eventKey] = eventValue;
19703
- }
19704
- }
19705
- return eventResult;
19706
- } else if (value instanceof Node) {
19707
- if (value instanceof HTMLElement) {
19708
- return value ? value.outerHTML : "";
19709
- }
19710
- return value.nodeName;
19711
- } else if (value instanceof Error) {
19712
- return value.stack ? value.stack + "\nEnd of stack for Error object" : value.name + ": " + value.message;
19713
- }
19714
- return value;
19715
- }
19716
- );
19717
- function shouldIgnore(_obj) {
19718
- if (isObject(_obj) && Object.keys(_obj).length > options.numOfKeysLimit) {
19719
- return true;
19720
- }
19721
- if (typeof _obj === "function") {
19722
- return true;
19723
- }
19724
- if (isObject(_obj) && isObjTooDeep(_obj, options.depthOfLimit)) {
19725
- return true;
19726
- }
19727
- return false;
19728
- }
19729
- function toString(_obj) {
19730
- let str = _obj.toString();
19731
- if (options.stringLengthLimit && str.length > options.stringLengthLimit) {
19732
- str = `${str.slice(0, options.stringLengthLimit)}...`;
19733
- }
19734
- return str;
19735
- }
19736
- }
19737
- const defaultLogOptions = {
19738
- level: [
19739
- "assert",
19740
- "clear",
19741
- "count",
19742
- "countReset",
19743
- "debug",
19744
- "dir",
19745
- "dirxml",
19746
- "error",
19747
- "group",
19748
- "groupCollapsed",
19749
- "groupEnd",
19750
- "info",
19751
- "log",
19752
- "table",
19753
- "time",
19754
- "timeEnd",
19755
- "timeLog",
19756
- "trace",
19757
- "warn"
19758
- ],
19759
- lengthThreshold: 1e3,
19760
- logger: "console"
19761
- };
19762
- function initLogObserver(cb, win, options) {
19763
- const logOptions = options ? Object.assign({}, defaultLogOptions, options) : defaultLogOptions;
19764
- const loggerType = logOptions.logger;
19765
- if (!loggerType) {
19766
- return () => {
19767
- };
19768
- }
19769
- let logger;
19770
- if (typeof loggerType === "string") {
19771
- logger = win[loggerType];
19772
- } else {
19773
- logger = loggerType;
19774
- }
19775
- let logCount = 0;
19776
- let inStack = false;
19777
- const cancelHandlers = [];
19778
- if (logOptions.level.includes("error")) {
19779
- const errorHandler2 = (event) => {
19780
- const message = event.message, error = event.error;
19781
- const trace = ErrorStackParser.parse(error).map(
19782
- (stackFrame) => stackFrame.toString()
19783
- );
19784
- const payload = [stringify(message, logOptions.stringifyOptions)];
19785
- cb({
19786
- level: "error",
19787
- trace,
19788
- payload
19789
- });
19790
- };
19791
- win.addEventListener("error", errorHandler2);
19792
- cancelHandlers.push(() => {
19793
- win.removeEventListener("error", errorHandler2);
19794
- });
19795
- const unhandledrejectionHandler = (event) => {
19796
- let error;
19797
- let payload;
19798
- if (event.reason instanceof Error) {
19799
- error = event.reason;
19800
- payload = [
19801
- stringify(
19802
- `Uncaught (in promise) ${error.name}: ${error.message}`,
19803
- logOptions.stringifyOptions
19804
- )
19805
- ];
19806
- } else {
19807
- error = new Error();
19808
- payload = [
19809
- stringify("Uncaught (in promise)", logOptions.stringifyOptions),
19810
- stringify(event.reason, logOptions.stringifyOptions)
19811
- ];
19812
- }
19813
- const trace = ErrorStackParser.parse(error).map(
19814
- (stackFrame) => stackFrame.toString()
19815
- );
19816
- cb({
19817
- level: "error",
19818
- trace,
19819
- payload
19820
- });
19821
- };
19822
- win.addEventListener("unhandledrejection", unhandledrejectionHandler);
19823
- cancelHandlers.push(() => {
19824
- win.removeEventListener("unhandledrejection", unhandledrejectionHandler);
19825
- });
19826
- }
19827
- for (const levelType of logOptions.level) {
19828
- cancelHandlers.push(replace(logger, levelType));
19829
- }
19830
- return () => {
19831
- cancelHandlers.forEach((h) => h());
19832
- };
19833
- function replace(_logger, level) {
19834
- if (!_logger[level]) {
19835
- return () => {
19836
- };
19837
- }
19838
- return utils.patch(
19839
- _logger,
19840
- level,
19841
- (original) => {
19842
- return (...args) => {
19843
- original.apply(this, args);
19844
- if (level === "assert" && !!args[0]) {
19845
- return;
19846
- }
19847
- if (inStack) {
19848
- return;
19849
- }
19850
- inStack = true;
19851
- try {
19852
- const trace = ErrorStackParser.parse(new Error()).map((stackFrame) => stackFrame.toString()).splice(1);
19853
- const argsForPayload = level === "assert" ? args.slice(1) : args;
19854
- const payload = argsForPayload.map(
19855
- (s) => stringify(s, logOptions.stringifyOptions)
19856
- );
19857
- logCount++;
19858
- if (logCount < logOptions.lengthThreshold) {
19859
- cb({
19860
- level,
19861
- trace,
19862
- payload
19863
- });
19864
- } else if (logCount === logOptions.lengthThreshold) {
19865
- cb({
19866
- level: "warn",
19867
- trace: [],
19868
- payload: [
19869
- stringify("The number of log records reached the threshold.")
19870
- ]
19871
- });
19872
- }
19873
- } catch (error) {
19874
- original("@sailfish-rrweb/rrweb logger error:", error, ...args);
19875
- } finally {
19876
- inStack = false;
19877
- }
19878
- };
19879
- }
19880
- );
19881
- }
19882
- }
19883
- const PLUGIN_NAME = "@sailfish-rrweb/rrweb/console@1";
19884
- const getRecordConsolePlugin = (options) => ({
19885
- name: PLUGIN_NAME,
19886
- observer: initLogObserver,
19887
- options
19888
- });
19889
- /*! *****************************************************************************
19890
- Copyright (c) Microsoft Corporation. All rights reserved.
19891
- Licensed under the Apache License, Version 2.0 (the "License"); you may not use
19892
- this file except in compliance with the License. You may obtain a copy of the
19893
- License at http://www.apache.org/licenses/LICENSE-2.0
19894
-
19895
- THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19896
- KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
19897
- WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
19898
- MERCHANTABLITY OR NON-INFRINGEMENT.
19899
-
19900
- See the Apache Version 2.0 License for specific language governing permissions
19901
- and limitations under the License.
19902
- ***************************************************************************** */
19903
- var extendStatics = function(d, b) {
19904
- extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {
19905
- d2.__proto__ = b2;
19906
- } || function(d2, b2) {
19907
- for (var p in b2) if (b2.hasOwnProperty(p)) d2[p] = b2[p];
19908
- };
19909
- return extendStatics(d, b);
19910
- };
19911
- function __extends(d, b) {
19912
- extendStatics(d, b);
19913
- function __() {
19914
- this.constructor = d;
19915
- }
19916
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
19917
- }
19918
- function __values(o) {
19919
- var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
19920
- if (m) return m.call(o);
19921
- return {
19922
- next: function() {
19923
- if (o && i >= o.length) o = void 0;
19924
- return { value: o && o[i++], done: !o };
19925
- }
19926
- };
19927
- }
19928
- function __read(o, n2) {
19929
- var m = typeof Symbol === "function" && o[Symbol.iterator];
19930
- if (!m) return o;
19931
- var i = m.call(o), r, ar = [], e;
19932
- try {
19933
- while ((n2 === void 0 || n2-- > 0) && !(r = i.next()).done) ar.push(r.value);
19934
- } catch (error) {
19935
- e = { error };
19936
- } finally {
19937
- try {
19938
- if (r && !r.done && (m = i["return"])) m.call(i);
19939
- } finally {
19940
- if (e) throw e.error;
19941
- }
19942
- }
19943
- return ar;
19944
- }
19945
- function __spread() {
19946
- for (var ar = [], i = 0; i < arguments.length; i++)
19947
- ar = ar.concat(__read(arguments[i]));
19948
- return ar;
19949
- }
19950
- var Event$1 = (
19951
- /** @class */
19952
- /* @__PURE__ */ function() {
19953
- function Event2(type, target) {
19954
- this.target = target;
19955
- this.type = type;
19956
- }
19957
- return Event2;
19958
- }()
19959
- );
19960
- var ErrorEvent = (
19961
- /** @class */
19962
- function(_super) {
19963
- __extends(ErrorEvent2, _super);
19964
- function ErrorEvent2(error, target) {
19965
- var _this = _super.call(this, "error", target) || this;
19966
- _this.message = error.message;
19967
- _this.error = error;
19968
- return _this;
19969
- }
19970
- return ErrorEvent2;
19971
- }(Event$1)
19972
- );
19973
- var CloseEvent = (
19974
- /** @class */
19975
- function(_super) {
19976
- __extends(CloseEvent2, _super);
19977
- function CloseEvent2(code, reason, target) {
19978
- if (code === void 0) {
19979
- code = 1e3;
19980
- }
19981
- if (reason === void 0) {
19982
- reason = "";
19983
- }
19984
- var _this = _super.call(this, "close", target) || this;
19985
- _this.wasClean = true;
19986
- _this.code = code;
19987
- _this.reason = reason;
19988
- return _this;
19989
- }
19990
- return CloseEvent2;
19991
- }(Event$1)
19992
- );
19993
- /*!
19994
- * Reconnecting WebSocket
19995
- * by Pedro Ladaria <pedro.ladaria@gmail.com>
19996
- * https://github.com/pladaria/reconnecting-websocket
19997
- * License MIT
19998
- */
19999
- var getGlobalWebSocket = function() {
20000
- if (typeof WebSocket !== "undefined") {
20001
- return WebSocket;
20002
- }
20003
- };
20004
- var isWebSocket = function(w) {
20005
- return typeof w !== "undefined" && !!w && w.CLOSING === 2;
20006
- };
20007
- var DEFAULT = {
20008
- maxReconnectionDelay: 1e4,
20009
- minReconnectionDelay: 1e3 + Math.random() * 4e3,
20010
- minUptime: 5e3,
20011
- reconnectionDelayGrowFactor: 1.3,
20012
- connectionTimeout: 4e3,
20013
- maxRetries: Infinity,
20014
- maxEnqueuedMessages: Infinity,
20015
- startClosed: false,
20016
- debug: false
20017
- };
20018
- var ReconnectingWebSocket = (
20019
- /** @class */
20020
- function() {
20021
- function ReconnectingWebSocket2(url, protocols, options) {
20022
- var _this = this;
20023
- if (options === void 0) {
20024
- options = {};
20025
- }
20026
- this._listeners = {
20027
- error: [],
20028
- message: [],
20029
- open: [],
20030
- close: []
20031
- };
20032
- this._retryCount = -1;
20033
- this._shouldReconnect = true;
20034
- this._connectLock = false;
20035
- this._binaryType = "blob";
20036
- this._closeCalled = false;
20037
- this._messageQueue = [];
20038
- this.onclose = null;
20039
- this.onerror = null;
20040
- this.onmessage = null;
20041
- this.onopen = null;
20042
- this._handleOpen = function(event) {
20043
- _this._debug("open event");
20044
- var _a2 = _this._options.minUptime, minUptime = _a2 === void 0 ? DEFAULT.minUptime : _a2;
20045
- clearTimeout(_this._connectTimeout);
20046
- _this._uptimeTimeout = setTimeout(function() {
20047
- return _this._acceptOpen();
20048
- }, minUptime);
20049
- _this._ws.binaryType = _this._binaryType;
20050
- _this._messageQueue.forEach(function(message) {
20051
- return _this._ws.send(message);
20052
- });
20053
- _this._messageQueue = [];
20054
- if (_this.onopen) {
20055
- _this.onopen(event);
20056
- }
20057
- _this._listeners.open.forEach(function(listener) {
20058
- return _this._callEventListener(event, listener);
20059
- });
20060
- };
20061
- this._handleMessage = function(event) {
20062
- _this._debug("message event");
20063
- if (_this.onmessage) {
20064
- _this.onmessage(event);
20065
- }
20066
- _this._listeners.message.forEach(function(listener) {
20067
- return _this._callEventListener(event, listener);
20068
- });
20069
- };
20070
- this._handleError = function(event) {
20071
- _this._debug("error event", event.message);
20072
- _this._disconnect(void 0, event.message === "TIMEOUT" ? "timeout" : void 0);
20073
- if (_this.onerror) {
20074
- _this.onerror(event);
20075
- }
20076
- _this._debug("exec error listeners");
20077
- _this._listeners.error.forEach(function(listener) {
20078
- return _this._callEventListener(event, listener);
20079
- });
20080
- _this._connect();
20081
- };
20082
- this._handleClose = function(event) {
20083
- _this._debug("close event");
20084
- _this._clearTimeouts();
20085
- if (_this._shouldReconnect) {
20086
- _this._connect();
20087
- }
20088
- if (_this.onclose) {
20089
- _this.onclose(event);
20090
- }
20091
- _this._listeners.close.forEach(function(listener) {
20092
- return _this._callEventListener(event, listener);
20093
- });
20094
- };
20095
- this._url = url;
20096
- this._protocols = protocols;
20097
- this._options = options;
20098
- if (this._options.startClosed) {
20099
- this._shouldReconnect = false;
20100
- }
20101
- this._connect();
20102
- }
20103
- Object.defineProperty(ReconnectingWebSocket2, "CONNECTING", {
20104
- get: function() {
20105
- return 0;
20106
- },
20107
- enumerable: true,
20108
- configurable: true
20109
- });
20110
- Object.defineProperty(ReconnectingWebSocket2, "OPEN", {
20111
- get: function() {
20112
- return 1;
20113
- },
20114
- enumerable: true,
20115
- configurable: true
20116
- });
20117
- Object.defineProperty(ReconnectingWebSocket2, "CLOSING", {
20118
- get: function() {
20119
- return 2;
20120
- },
20121
- enumerable: true,
20122
- configurable: true
20123
- });
20124
- Object.defineProperty(ReconnectingWebSocket2, "CLOSED", {
20125
- get: function() {
20126
- return 3;
20127
- },
20128
- enumerable: true,
20129
- configurable: true
20130
- });
20131
- Object.defineProperty(ReconnectingWebSocket2.prototype, "CONNECTING", {
20132
- get: function() {
20133
- return ReconnectingWebSocket2.CONNECTING;
20134
- },
20135
- enumerable: true,
20136
- configurable: true
20137
- });
20138
- Object.defineProperty(ReconnectingWebSocket2.prototype, "OPEN", {
20139
- get: function() {
20140
- return ReconnectingWebSocket2.OPEN;
20141
- },
20142
- enumerable: true,
20143
- configurable: true
20144
- });
20145
- Object.defineProperty(ReconnectingWebSocket2.prototype, "CLOSING", {
20146
- get: function() {
20147
- return ReconnectingWebSocket2.CLOSING;
20148
- },
20149
- enumerable: true,
20150
- configurable: true
20151
- });
20152
- Object.defineProperty(ReconnectingWebSocket2.prototype, "CLOSED", {
20153
- get: function() {
20154
- return ReconnectingWebSocket2.CLOSED;
20155
- },
20156
- enumerable: true,
20157
- configurable: true
20158
- });
20159
- Object.defineProperty(ReconnectingWebSocket2.prototype, "binaryType", {
20160
- get: function() {
20161
- return this._ws ? this._ws.binaryType : this._binaryType;
20162
- },
20163
- set: function(value) {
20164
- this._binaryType = value;
20165
- if (this._ws) {
20166
- this._ws.binaryType = value;
20167
- }
20168
- },
20169
- enumerable: true,
20170
- configurable: true
20171
- });
20172
- Object.defineProperty(ReconnectingWebSocket2.prototype, "retryCount", {
20173
- /**
20174
- * Returns the number or connection retries
20175
- */
20176
- get: function() {
20177
- return Math.max(this._retryCount, 0);
20178
- },
20179
- enumerable: true,
20180
- configurable: true
20181
- });
20182
- Object.defineProperty(ReconnectingWebSocket2.prototype, "bufferedAmount", {
20183
- /**
20184
- * The number of bytes of data that have been queued using calls to send() but not yet
20185
- * transmitted to the network. This value resets to zero once all queued data has been sent.
20186
- * This value does not reset to zero when the connection is closed; if you keep calling send(),
20187
- * this will continue to climb. Read only
20188
- */
20189
- get: function() {
20190
- var bytes = this._messageQueue.reduce(function(acc, message) {
20191
- if (typeof message === "string") {
20192
- acc += message.length;
20193
- } else if (message instanceof Blob) {
20194
- acc += message.size;
20195
- } else {
20196
- acc += message.byteLength;
20197
- }
20198
- return acc;
20199
- }, 0);
20200
- return bytes + (this._ws ? this._ws.bufferedAmount : 0);
20201
- },
20202
- enumerable: true,
20203
- configurable: true
20204
- });
20205
- Object.defineProperty(ReconnectingWebSocket2.prototype, "extensions", {
20206
- /**
20207
- * The extensions selected by the server. This is currently only the empty string or a list of
20208
- * extensions as negotiated by the connection
20209
- */
20210
- get: function() {
20211
- return this._ws ? this._ws.extensions : "";
20212
- },
20213
- enumerable: true,
20214
- configurable: true
20215
- });
20216
- Object.defineProperty(ReconnectingWebSocket2.prototype, "protocol", {
20217
- /**
20218
- * A string indicating the name of the sub-protocol the server selected;
20219
- * this will be one of the strings specified in the protocols parameter when creating the
20220
- * WebSocket object
20221
- */
20222
- get: function() {
20223
- return this._ws ? this._ws.protocol : "";
20224
- },
20225
- enumerable: true,
20226
- configurable: true
20227
- });
20228
- Object.defineProperty(ReconnectingWebSocket2.prototype, "readyState", {
20229
- /**
20230
- * The current state of the connection; this is one of the Ready state constants
20231
- */
20232
- get: function() {
20233
- if (this._ws) {
20234
- return this._ws.readyState;
20235
- }
20236
- return this._options.startClosed ? ReconnectingWebSocket2.CLOSED : ReconnectingWebSocket2.CONNECTING;
20237
- },
20238
- enumerable: true,
20239
- configurable: true
20240
- });
20241
- Object.defineProperty(ReconnectingWebSocket2.prototype, "url", {
20242
- /**
20243
- * The URL as resolved by the constructor
20244
- */
20245
- get: function() {
20246
- return this._ws ? this._ws.url : "";
20247
- },
20248
- enumerable: true,
20249
- configurable: true
20250
- });
20251
- ReconnectingWebSocket2.prototype.close = function(code, reason) {
20252
- if (code === void 0) {
20253
- code = 1e3;
20254
- }
20255
- this._closeCalled = true;
20256
- this._shouldReconnect = false;
20257
- this._clearTimeouts();
20258
- if (!this._ws) {
20259
- this._debug("close enqueued: no ws instance");
20260
- return;
20261
- }
20262
- if (this._ws.readyState === this.CLOSED) {
20263
- this._debug("close: already closed");
20264
- return;
20265
- }
20266
- this._ws.close(code, reason);
20267
- };
20268
- ReconnectingWebSocket2.prototype.reconnect = function(code, reason) {
20269
- this._shouldReconnect = true;
20270
- this._closeCalled = false;
20271
- this._retryCount = -1;
20272
- if (!this._ws || this._ws.readyState === this.CLOSED) {
20273
- this._connect();
20274
- } else {
20275
- this._disconnect(code, reason);
20276
- this._connect();
20277
- }
20278
- };
20279
- ReconnectingWebSocket2.prototype.send = function(data) {
20280
- if (this._ws && this._ws.readyState === this.OPEN) {
20281
- this._debug("send", data);
20282
- this._ws.send(data);
20283
- } else {
20284
- var _a2 = this._options.maxEnqueuedMessages, maxEnqueuedMessages = _a2 === void 0 ? DEFAULT.maxEnqueuedMessages : _a2;
20285
- if (this._messageQueue.length < maxEnqueuedMessages) {
20286
- this._debug("enqueue", data);
20287
- this._messageQueue.push(data);
20288
- }
20289
- }
20290
- };
20291
- ReconnectingWebSocket2.prototype.addEventListener = function(type, listener) {
20292
- if (this._listeners[type]) {
20293
- this._listeners[type].push(listener);
20294
- }
20295
- };
20296
- ReconnectingWebSocket2.prototype.dispatchEvent = function(event) {
20297
- var e_1, _a2;
20298
- var listeners = this._listeners[event.type];
20299
- if (listeners) {
20300
- try {
20301
- for (var listeners_1 = __values(listeners), listeners_1_1 = listeners_1.next(); !listeners_1_1.done; listeners_1_1 = listeners_1.next()) {
20302
- var listener = listeners_1_1.value;
20303
- this._callEventListener(event, listener);
20304
- }
20305
- } catch (e_1_1) {
20306
- e_1 = { error: e_1_1 };
20307
- } finally {
20308
- try {
20309
- if (listeners_1_1 && !listeners_1_1.done && (_a2 = listeners_1.return)) _a2.call(listeners_1);
20310
- } finally {
20311
- if (e_1) throw e_1.error;
20312
- }
20313
- }
20203
+ const filtered = error.stack.split("\n").filter(function(line) {
20204
+ return !line.match(SAFARI_NATIVE_CODE_REGEXP);
20205
+ }, this);
20206
+ return filtered.map(function(line) {
20207
+ if (line.indexOf(" > eval") > -1) {
20208
+ line = line.replace(
20209
+ / line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,
20210
+ ":$1"
20211
+ );
20314
20212
  }
20315
- return true;
20316
- };
20317
- ReconnectingWebSocket2.prototype.removeEventListener = function(type, listener) {
20318
- if (this._listeners[type]) {
20319
- this._listeners[type] = this._listeners[type].filter(function(l) {
20320
- return l !== listener;
20213
+ if (line.indexOf("@") === -1 && line.indexOf(":") === -1) {
20214
+ return new StackFrame({
20215
+ functionName: line
20216
+ });
20217
+ } else {
20218
+ const functionNameRegex = /((.*".+"[^@]*)?[^@]*)(?:@)/;
20219
+ const matches = line.match(functionNameRegex);
20220
+ const functionName = matches && matches[1] ? matches[1] : void 0;
20221
+ const locationParts = this.extractLocation(
20222
+ line.replace(functionNameRegex, "")
20223
+ );
20224
+ return new StackFrame({
20225
+ functionName,
20226
+ fileName: locationParts[0],
20227
+ lineNumber: locationParts[1],
20228
+ columnNumber: locationParts[2]
20321
20229
  });
20322
20230
  }
20323
- };
20324
- ReconnectingWebSocket2.prototype._debug = function() {
20325
- var args = [];
20326
- for (var _i = 0; _i < arguments.length; _i++) {
20327
- args[_i] = arguments[_i];
20328
- }
20329
- if (this._options.debug) {
20330
- console.log.apply(console, __spread(["RWS>"], args));
20231
+ }, this);
20232
+ },
20233
+ parseOpera: function(e) {
20234
+ if (!e.stacktrace || e.message.indexOf("\n") > -1 && e.message.split("\n").length > e.stacktrace.split("\n").length) {
20235
+ return this.parseOpera9(e);
20236
+ } else if (!e.stack) {
20237
+ return this.parseOpera10(e);
20238
+ } else {
20239
+ return this.parseOpera11(e);
20240
+ }
20241
+ },
20242
+ parseOpera9: function(e) {
20243
+ const lineRE = /Line (\d+).*script (?:in )?(\S+)/i;
20244
+ const lines = e.message.split("\n");
20245
+ const result2 = [];
20246
+ for (let i = 2, len = lines.length; i < len; i += 2) {
20247
+ const match = lineRE.exec(lines[i]);
20248
+ if (match) {
20249
+ result2.push(
20250
+ new StackFrame({
20251
+ fileName: match[2],
20252
+ lineNumber: parseFloat(match[1])
20253
+ })
20254
+ );
20331
20255
  }
20332
- };
20333
- ReconnectingWebSocket2.prototype._getNextDelay = function() {
20334
- var _a2 = this._options, _b = _a2.reconnectionDelayGrowFactor, reconnectionDelayGrowFactor = _b === void 0 ? DEFAULT.reconnectionDelayGrowFactor : _b, _c = _a2.minReconnectionDelay, minReconnectionDelay = _c === void 0 ? DEFAULT.minReconnectionDelay : _c, _d = _a2.maxReconnectionDelay, maxReconnectionDelay = _d === void 0 ? DEFAULT.maxReconnectionDelay : _d;
20335
- var delay = 0;
20336
- if (this._retryCount > 0) {
20337
- delay = minReconnectionDelay * Math.pow(reconnectionDelayGrowFactor, this._retryCount - 1);
20338
- if (delay > maxReconnectionDelay) {
20339
- delay = maxReconnectionDelay;
20340
- }
20256
+ }
20257
+ return result2;
20258
+ },
20259
+ parseOpera10: function(e) {
20260
+ const lineRE = /Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i;
20261
+ const lines = e.stacktrace.split("\n");
20262
+ const result2 = [];
20263
+ for (let i = 0, len = lines.length; i < len; i += 2) {
20264
+ const match = lineRE.exec(lines[i]);
20265
+ if (match) {
20266
+ result2.push(
20267
+ new StackFrame({
20268
+ functionName: match[3] || void 0,
20269
+ fileName: match[2],
20270
+ lineNumber: parseFloat(match[1])
20271
+ })
20272
+ );
20341
20273
  }
20342
- this._debug("next delay", delay);
20343
- return delay;
20344
- };
20345
- ReconnectingWebSocket2.prototype._wait = function() {
20346
- var _this = this;
20347
- return new Promise(function(resolve2) {
20348
- setTimeout(resolve2, _this._getNextDelay());
20274
+ }
20275
+ return result2;
20276
+ },
20277
+ // Opera 10.65+ Error.stack very similar to FF/Safari
20278
+ parseOpera11: function(error) {
20279
+ const filtered = error.stack.split("\n").filter(function(line) {
20280
+ return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && !line.match(/^Error created at/);
20281
+ }, this);
20282
+ return filtered.map(function(line) {
20283
+ const tokens = line.split("@");
20284
+ const locationParts = this.extractLocation(tokens.pop());
20285
+ const functionCall = tokens.shift() || "";
20286
+ const functionName = functionCall.replace(/<anonymous function(: (\w+))?>/, "$2").replace(/\([^)]*\)/g, "") || void 0;
20287
+ return new StackFrame({
20288
+ functionName,
20289
+ fileName: locationParts[0],
20290
+ lineNumber: locationParts[1],
20291
+ columnNumber: locationParts[2]
20349
20292
  });
20350
- };
20351
- ReconnectingWebSocket2.prototype._getNextUrl = function(urlProvider) {
20352
- if (typeof urlProvider === "string") {
20353
- return Promise.resolve(urlProvider);
20354
- }
20355
- if (typeof urlProvider === "function") {
20356
- var url = urlProvider();
20357
- if (typeof url === "string") {
20358
- return Promise.resolve(url);
20359
- }
20360
- if (!!url.then) {
20361
- return url;
20293
+ }, this);
20294
+ }
20295
+ };
20296
+ function pathToSelector(node2) {
20297
+ if (!node2 || !node2.outerHTML) {
20298
+ return "";
20299
+ }
20300
+ let path = "";
20301
+ while (node2.parentElement) {
20302
+ let name = node2.localName;
20303
+ if (!name) {
20304
+ break;
20305
+ }
20306
+ name = name.toLowerCase();
20307
+ const parent = node2.parentElement;
20308
+ const domSiblings = [];
20309
+ if (parent.children && parent.children.length > 0) {
20310
+ for (let i = 0; i < parent.children.length; i++) {
20311
+ const sibling = parent.children[i];
20312
+ if (sibling.localName && sibling.localName.toLowerCase) {
20313
+ if (sibling.localName.toLowerCase() === name) {
20314
+ domSiblings.push(sibling);
20315
+ }
20362
20316
  }
20363
20317
  }
20364
- throw Error("Invalid URL");
20365
- };
20366
- ReconnectingWebSocket2.prototype._connect = function() {
20367
- var _this = this;
20368
- if (this._connectLock || !this._shouldReconnect) {
20369
- return;
20370
- }
20371
- this._connectLock = true;
20372
- var _a2 = this._options, _b = _a2.maxRetries, maxRetries = _b === void 0 ? DEFAULT.maxRetries : _b, _c = _a2.connectionTimeout, connectionTimeout = _c === void 0 ? DEFAULT.connectionTimeout : _c, _d = _a2.WebSocket, WebSocket2 = _d === void 0 ? getGlobalWebSocket() : _d;
20373
- if (this._retryCount >= maxRetries) {
20374
- this._debug("max retries reached", this._retryCount, ">=", maxRetries);
20375
- return;
20376
- }
20377
- this._retryCount++;
20378
- this._debug("connect", this._retryCount);
20379
- this._removeListeners();
20380
- if (!isWebSocket(WebSocket2)) {
20381
- throw Error("No valid WebSocket class provided");
20382
- }
20383
- this._wait().then(function() {
20384
- return _this._getNextUrl(_this._url);
20385
- }).then(function(url) {
20386
- if (_this._closeCalled) {
20387
- return;
20318
+ }
20319
+ if (domSiblings.length > 1) {
20320
+ name += `:eq(${domSiblings.indexOf(node2)})`;
20321
+ }
20322
+ path = name + (path ? ">" + path : "");
20323
+ node2 = parent;
20324
+ }
20325
+ return path;
20326
+ }
20327
+ function isObject(obj) {
20328
+ return Object.prototype.toString.call(obj) === "[object Object]";
20329
+ }
20330
+ function isObjTooDeep(obj, limit) {
20331
+ if (limit === 0) {
20332
+ return true;
20333
+ }
20334
+ const keys = Object.keys(obj);
20335
+ for (const key of keys) {
20336
+ if (isObject(obj[key]) && isObjTooDeep(obj[key], limit - 1)) {
20337
+ return true;
20338
+ }
20339
+ }
20340
+ return false;
20341
+ }
20342
+ function stringify(obj, stringifyOptions) {
20343
+ const options = {
20344
+ numOfKeysLimit: 50,
20345
+ depthOfLimit: 4
20346
+ };
20347
+ Object.assign(options, stringifyOptions);
20348
+ const stack = [];
20349
+ const keys = [];
20350
+ return JSON.stringify(
20351
+ obj,
20352
+ function(key, value) {
20353
+ if (stack.length > 0) {
20354
+ const thisPos = stack.indexOf(this);
20355
+ ~thisPos ? stack.splice(thisPos + 1) : stack.push(this);
20356
+ ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key);
20357
+ if (~stack.indexOf(value)) {
20358
+ if (stack[0] === value) {
20359
+ value = "[Circular ~]";
20360
+ } else {
20361
+ value = "[Circular ~." + keys.slice(0, stack.indexOf(value)).join(".") + "]";
20362
+ }
20388
20363
  }
20389
- _this._debug("connect", { url, protocols: _this._protocols });
20390
- _this._ws = _this._protocols ? new WebSocket2(url, _this._protocols) : new WebSocket2(url);
20391
- _this._ws.binaryType = _this._binaryType;
20392
- _this._connectLock = false;
20393
- _this._addListeners();
20394
- _this._connectTimeout = setTimeout(function() {
20395
- return _this._handleTimeout();
20396
- }, connectionTimeout);
20397
- });
20398
- };
20399
- ReconnectingWebSocket2.prototype._handleTimeout = function() {
20400
- this._debug("timeout event");
20401
- this._handleError(new ErrorEvent(Error("TIMEOUT"), this));
20402
- };
20403
- ReconnectingWebSocket2.prototype._disconnect = function(code, reason) {
20404
- if (code === void 0) {
20405
- code = 1e3;
20364
+ } else {
20365
+ stack.push(value);
20406
20366
  }
20407
- this._clearTimeouts();
20408
- if (!this._ws) {
20409
- return;
20367
+ if (value === null) return value;
20368
+ if (value === void 0) return "undefined";
20369
+ if (shouldIgnore(value)) {
20370
+ return toString(value);
20410
20371
  }
20411
- this._removeListeners();
20412
- try {
20413
- this._ws.close(code, reason);
20414
- this._handleClose(new CloseEvent(code, reason, this));
20415
- } catch (error) {
20372
+ if (typeof value === "bigint") {
20373
+ return value.toString() + "n";
20374
+ }
20375
+ if (value instanceof Event) {
20376
+ const eventResult = {};
20377
+ for (const eventKey in value) {
20378
+ const eventValue = value[eventKey];
20379
+ if (Array.isArray(eventValue)) {
20380
+ eventResult[eventKey] = pathToSelector(
20381
+ eventValue.length ? eventValue[0] : null
20382
+ );
20383
+ } else {
20384
+ eventResult[eventKey] = eventValue;
20385
+ }
20386
+ }
20387
+ return eventResult;
20388
+ } else if (value instanceof Node) {
20389
+ if (value instanceof HTMLElement) {
20390
+ return value ? value.outerHTML : "";
20391
+ }
20392
+ return value.nodeName;
20393
+ } else if (value instanceof Error) {
20394
+ return value.stack ? value.stack + "\nEnd of stack for Error object" : value.name + ": " + value.message;
20416
20395
  }
20396
+ return value;
20397
+ }
20398
+ );
20399
+ function shouldIgnore(_obj) {
20400
+ if (isObject(_obj) && Object.keys(_obj).length > options.numOfKeysLimit) {
20401
+ return true;
20402
+ }
20403
+ if (typeof _obj === "function") {
20404
+ return true;
20405
+ }
20406
+ if (isObject(_obj) && isObjTooDeep(_obj, options.depthOfLimit)) {
20407
+ return true;
20408
+ }
20409
+ return false;
20410
+ }
20411
+ function toString(_obj) {
20412
+ let str = _obj.toString();
20413
+ if (options.stringLengthLimit && str.length > options.stringLengthLimit) {
20414
+ str = `${str.slice(0, options.stringLengthLimit)}...`;
20415
+ }
20416
+ return str;
20417
+ }
20418
+ }
20419
+ const defaultLogOptions = {
20420
+ level: [
20421
+ "assert",
20422
+ "clear",
20423
+ "count",
20424
+ "countReset",
20425
+ "debug",
20426
+ "dir",
20427
+ "dirxml",
20428
+ "error",
20429
+ "group",
20430
+ "groupCollapsed",
20431
+ "groupEnd",
20432
+ "info",
20433
+ "log",
20434
+ "table",
20435
+ "time",
20436
+ "timeEnd",
20437
+ "timeLog",
20438
+ "trace",
20439
+ "warn"
20440
+ ],
20441
+ lengthThreshold: 1e3,
20442
+ logger: "console"
20443
+ };
20444
+ function initLogObserver(cb, win, options) {
20445
+ const logOptions = options ? Object.assign({}, defaultLogOptions, options) : defaultLogOptions;
20446
+ const loggerType = logOptions.logger;
20447
+ if (!loggerType) {
20448
+ return () => {
20417
20449
  };
20418
- ReconnectingWebSocket2.prototype._acceptOpen = function() {
20419
- this._debug("accept open");
20420
- this._retryCount = 0;
20450
+ }
20451
+ let logger;
20452
+ if (typeof loggerType === "string") {
20453
+ logger = win[loggerType];
20454
+ } else {
20455
+ logger = loggerType;
20456
+ }
20457
+ let logCount = 0;
20458
+ let inStack = false;
20459
+ const cancelHandlers = [];
20460
+ if (logOptions.level.includes("error")) {
20461
+ const errorHandler2 = (event) => {
20462
+ const message = event.message, error = event.error;
20463
+ const trace = ErrorStackParser.parse(error).map(
20464
+ (stackFrame) => stackFrame.toString()
20465
+ );
20466
+ const payload = [stringify(message, logOptions.stringifyOptions)];
20467
+ cb({
20468
+ level: "error",
20469
+ trace,
20470
+ payload
20471
+ });
20421
20472
  };
20422
- ReconnectingWebSocket2.prototype._callEventListener = function(event, listener) {
20423
- if ("handleEvent" in listener) {
20424
- listener.handleEvent(event);
20473
+ win.addEventListener("error", errorHandler2);
20474
+ cancelHandlers.push(() => {
20475
+ win.removeEventListener("error", errorHandler2);
20476
+ });
20477
+ const unhandledrejectionHandler = (event) => {
20478
+ let error;
20479
+ let payload;
20480
+ if (event.reason instanceof Error) {
20481
+ error = event.reason;
20482
+ payload = [
20483
+ stringify(
20484
+ `Uncaught (in promise) ${error.name}: ${error.message}`,
20485
+ logOptions.stringifyOptions
20486
+ )
20487
+ ];
20425
20488
  } else {
20426
- listener(event);
20427
- }
20428
- };
20429
- ReconnectingWebSocket2.prototype._removeListeners = function() {
20430
- if (!this._ws) {
20431
- return;
20432
- }
20433
- this._debug("removeListeners");
20434
- this._ws.removeEventListener("open", this._handleOpen);
20435
- this._ws.removeEventListener("close", this._handleClose);
20436
- this._ws.removeEventListener("message", this._handleMessage);
20437
- this._ws.removeEventListener("error", this._handleError);
20438
- };
20439
- ReconnectingWebSocket2.prototype._addListeners = function() {
20440
- if (!this._ws) {
20441
- return;
20489
+ error = new Error();
20490
+ payload = [
20491
+ stringify("Uncaught (in promise)", logOptions.stringifyOptions),
20492
+ stringify(event.reason, logOptions.stringifyOptions)
20493
+ ];
20442
20494
  }
20443
- this._debug("addListeners");
20444
- this._ws.addEventListener("open", this._handleOpen);
20445
- this._ws.addEventListener("close", this._handleClose);
20446
- this._ws.addEventListener("message", this._handleMessage);
20447
- this._ws.addEventListener("error", this._handleError);
20448
- };
20449
- ReconnectingWebSocket2.prototype._clearTimeouts = function() {
20450
- clearTimeout(this._connectTimeout);
20451
- clearTimeout(this._uptimeTimeout);
20495
+ const trace = ErrorStackParser.parse(error).map(
20496
+ (stackFrame) => stackFrame.toString()
20497
+ );
20498
+ cb({
20499
+ level: "error",
20500
+ trace,
20501
+ payload
20502
+ });
20452
20503
  };
20453
- return ReconnectingWebSocket2;
20454
- }()
20455
- );
20456
- const version = "1.0.0-beta-14";
20457
- function initializeWebSocket(backendApi, apiKey, sessionId) {
20458
- const wsHost = getWebSocketHost(backendApi);
20459
- const wsScheme = window.location.protocol === "https:" ? "wss" : "ws";
20460
- const wsUrl = `${wsScheme}://${wsHost}/ws/notify/?apiKey=${apiKey}&sessionId=${sessionId}&sender=JS%2FTS&version=${version}`;
20461
- const options = {
20462
- connectionTimeout: 1e4
20504
+ win.addEventListener("unhandledrejection", unhandledrejectionHandler);
20505
+ cancelHandlers.push(() => {
20506
+ win.removeEventListener("unhandledrejection", unhandledrejectionHandler);
20507
+ });
20508
+ }
20509
+ for (const levelType of logOptions.level) {
20510
+ cancelHandlers.push(replace(logger, levelType));
20511
+ }
20512
+ return () => {
20513
+ cancelHandlers.forEach((h) => h());
20463
20514
  };
20464
- const webSocket = new ReconnectingWebSocket(wsUrl, [], options);
20465
- return webSocket;
20466
- }
20467
- function getWebSocketHost(url) {
20468
- const parser2 = document.createElement("a");
20469
- parser2.href = url;
20470
- return `${parser2.hostname}${parser2.port ? `:${parser2.port}` : ""}`;
20515
+ function replace(_logger, level) {
20516
+ if (!_logger[level]) {
20517
+ return () => {
20518
+ };
20519
+ }
20520
+ return utils.patch(
20521
+ _logger,
20522
+ level,
20523
+ (original) => {
20524
+ return (...args) => {
20525
+ original.apply(this, args);
20526
+ if (level === "assert" && !!args[0]) {
20527
+ return;
20528
+ }
20529
+ if (inStack) {
20530
+ return;
20531
+ }
20532
+ inStack = true;
20533
+ try {
20534
+ const trace = ErrorStackParser.parse(new Error()).map((stackFrame) => stackFrame.toString()).splice(1);
20535
+ const argsForPayload = level === "assert" ? args.slice(1) : args;
20536
+ const payload = argsForPayload.map(
20537
+ (s) => stringify(s, logOptions.stringifyOptions)
20538
+ );
20539
+ logCount++;
20540
+ if (logCount < logOptions.lengthThreshold) {
20541
+ cb({
20542
+ level,
20543
+ trace,
20544
+ payload
20545
+ });
20546
+ } else if (logCount === logOptions.lengthThreshold) {
20547
+ cb({
20548
+ level: "warn",
20549
+ trace: [],
20550
+ payload: [
20551
+ stringify("The number of log records reached the threshold.")
20552
+ ]
20553
+ });
20554
+ }
20555
+ } catch (error) {
20556
+ original("@sailfish-rrweb/rrweb logger error:", error, ...args);
20557
+ } finally {
20558
+ inStack = false;
20559
+ }
20560
+ };
20561
+ }
20562
+ );
20563
+ }
20471
20564
  }
20565
+ const PLUGIN_NAME = "@sailfish-rrweb/rrweb/console@1";
20566
+ const getRecordConsolePlugin = (options) => ({
20567
+ name: PLUGIN_NAME,
20568
+ observer: initLogObserver,
20569
+ options
20570
+ });
20472
20571
  const MASK_CLASS = "sailfishSanitize";
20473
20572
  function maskInputFn(text, node2) {
20474
20573
  var _a2;
@@ -20492,6 +20591,7 @@ function maskInputFn(text, node2) {
20492
20591
  return text;
20493
20592
  }
20494
20593
  async function initializeRecording(captureSettings, consoleRecordSettings, networkRecordSettings, backendApi, apiKey, sessionId) {
20594
+ const webSocket2 = initializeWebSocket(backendApi, apiKey, sessionId);
20495
20595
  try {
20496
20596
  record({
20497
20597
  emit(event) {
@@ -20507,17 +20607,39 @@ async function initializeRecording(captureSettings, consoleRecordSettings, netwo
20507
20607
  maskTextClass: MASK_CLASS,
20508
20608
  ...captureSettings
20509
20609
  });
20510
- const webSocket = initializeWebSocket(backendApi, apiKey, sessionId);
20511
20610
  setInterval(
20512
- () => sendRecordingEvents(
20513
- webSocket,
20514
- sessionId
20515
- ),
20611
+ () => sendRecordingEvents(webSocket2),
20516
20612
  1e4
20517
20613
  );
20518
20614
  } catch (error) {
20519
20615
  console.error("Error importing plugins!", error);
20520
20616
  }
20617
+ return webSocket2;
20618
+ }
20619
+ let lastIdentifyMessage = null;
20620
+ let lastMetadataMessage = null;
20621
+ function identify(userId, traits = {}, overwrite = false) {
20622
+ const message = {
20623
+ type: "identify",
20624
+ userId,
20625
+ traits
20626
+ };
20627
+ if (lastIdentifyMessage && lastIdentifyMessage.userId === userId && JSON.stringify(lastIdentifyMessage.traits) === JSON.stringify(traits)) {
20628
+ return;
20629
+ }
20630
+ lastIdentifyMessage = { userId, traits, overwrite };
20631
+ sendMessage(message);
20632
+ }
20633
+ function addOrUpdateMetadata(metadata) {
20634
+ const message = {
20635
+ type: "addOrUpdateMetadata",
20636
+ metadata
20637
+ };
20638
+ if (lastMetadataMessage && JSON.stringify(lastMetadataMessage) === JSON.stringify(metadata)) {
20639
+ return;
20640
+ }
20641
+ lastMetadataMessage = metadata;
20642
+ sendMessage(message);
20521
20643
  }
20522
20644
  const DEFAULT_DOMAINS_TO_IGNORE = [];
20523
20645
  const DEFAULT_CAPTURE_SETTINGS = {
@@ -20560,12 +20682,66 @@ const DEFAULT_NETWORK_CAPTURE_SETTINGS = {
20560
20682
  recordBody: true,
20561
20683
  recordInitialRequests: false
20562
20684
  };
20685
+ function getOrSetSessionId(forceNew = false) {
20686
+ let sessionId = sessionStorage.getItem("sailfishSessionId");
20687
+ if (!sessionId || forceNew) {
20688
+ sessionId = v4();
20689
+ sessionStorage.setItem("sailfishSessionId", sessionId);
20690
+ }
20691
+ return sessionId;
20692
+ }
20693
+ function handleVisibilityChange() {
20694
+ if (document.visibilityState === "visible") {
20695
+ getOrSetSessionId(true);
20696
+ }
20697
+ }
20698
+ document.addEventListener("visibilitychange", handleVisibilityChange);
20699
+ window.addEventListener("beforeunload", () => {
20700
+ sessionStorage.removeItem("sailfishSessionId");
20701
+ });
20702
+ function storeCredentialsAndConnection({
20703
+ apiKey,
20704
+ backendApi
20705
+ }) {
20706
+ sessionStorage.setItem("sailfishApiKey", apiKey);
20707
+ sessionStorage.setItem("sailfishBackendApi", backendApi);
20708
+ }
20709
+ (function() {
20710
+ const originalOpen = XMLHttpRequest.prototype.open;
20711
+ const originalSend = XMLHttpRequest.prototype.send;
20712
+ const sessionId = getOrSetSessionId();
20713
+ XMLHttpRequest.prototype.open = function(...args) {
20714
+ this._url = args[1];
20715
+ originalOpen.apply(this, args);
20716
+ };
20717
+ XMLHttpRequest.prototype.send = function(...args) {
20718
+ if (sessionId) {
20719
+ this.setRequestHeader("X-Sf3-Rid", sessionId);
20720
+ }
20721
+ originalSend.apply(this, args);
20722
+ };
20723
+ })();
20724
+ (function() {
20725
+ const originalFetch = window.fetch;
20726
+ const sessionId = getOrSetSessionId();
20727
+ window.fetch = async function(input2, init = {}) {
20728
+ if (sessionId) {
20729
+ init.headers = {
20730
+ ...init.headers,
20731
+ "X-Sf3-Rid": sessionId
20732
+ };
20733
+ }
20734
+ return originalFetch(input2, init);
20735
+ };
20736
+ })();
20563
20737
  async function startRecording({
20564
20738
  apiKey,
20565
20739
  backendApi
20566
20740
  }) {
20567
20741
  var _a2, _b;
20568
- const sessionId = v4();
20742
+ let sessionId = getOrSetSessionId();
20743
+ storeCredentialsAndConnection({ apiKey, backendApi });
20744
+ gatherAndCacheDeviceInfo();
20569
20745
  try {
20570
20746
  const captureSettingsResponse = await fetchCaptureSettings(
20571
20747
  apiKey,
@@ -20578,8 +20754,7 @@ async function startRecording({
20578
20754
  backendApi
20579
20755
  );
20580
20756
  if ((_b = sessionResponse.data) == null ? void 0 : _b.startRecordingSession) {
20581
- const webSocket = initializeWebSocket(backendApi, apiKey, sessionId);
20582
- initializeRecording(
20757
+ const websocket = await initializeRecording(
20583
20758
  captureSettings,
20584
20759
  DEFAULT_CONSOLE_RECORDING_SETTINGS,
20585
20760
  DEFAULT_NETWORK_CAPTURE_SETTINGS,
@@ -20587,7 +20762,12 @@ async function startRecording({
20587
20762
  apiKey,
20588
20763
  sessionId
20589
20764
  );
20590
- setInterval(() => sendRecordingEvents(webSocket, sessionId), 1e4);
20765
+ setInterval(() => {
20766
+ if (websocket && websocket.readyState === WebSocket.OPEN) {
20767
+ sendRecordingEvents(websocket);
20768
+ } else {
20769
+ }
20770
+ }, 1e4);
20591
20771
  } else {
20592
20772
  console.error(
20593
20773
  "Failed to start recording session:",
@@ -20609,11 +20789,14 @@ export {
20609
20789
  DEFAULT_CONSOLE_RECORDING_SETTINGS,
20610
20790
  DEFAULT_DOMAINS_TO_IGNORE,
20611
20791
  DEFAULT_NETWORK_CAPTURE_SETTINGS,
20792
+ addOrUpdateMetadata,
20612
20793
  cacheEvents,
20613
20794
  fetchCaptureSettings,
20795
+ identify,
20614
20796
  initializeRecording,
20615
20797
  initializeWebSocket,
20616
20798
  sendGraphQLRequest,
20799
+ sendMessage,
20617
20800
  sendRecordingEvents,
20618
20801
  startRecording,
20619
20802
  startRecordingSession