@coralogix/browser 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -1
- package/README.md +16 -7
- package/index.esm.js +12 -6695
- package/index.esm2.js +5050 -0
- package/package.json +1 -1
- package/sessionRecorder.esm.js +1685 -0
- package/src/version.d.ts +1 -1
|
@@ -0,0 +1,1685 @@
|
|
|
1
|
+
import { __awaiter, __generator, __assign } from 'tslib';
|
|
2
|
+
import { C as CxGlobal, r as reportInternalEvent, g as getSdkConfig, S as SESSION_RECORDER_SEGMENTS_MAP, a as getNowTime, b as SESSION_RECORDING_NETWORK_ERR0R_MESSAGE, M as MAX_BATCH_TIME_MS, R as Request, c as SESSION_RECORDING_POSTFIX_URL, d as SESSION_RECORDING_DEFAULT_HEADERS, B as BATCH_TIME_DELAY, e as SESSION_RECORDER_KEY, f as MAX_MUTATIONS_FOR_SESSION_RECORDING, h as SESSION_RECORDING_DEFAULT_ERROR_MESSAGE } from './index.esm2.js';
|
|
3
|
+
import { record } from 'rrweb';
|
|
4
|
+
import { getRecordConsolePlugin } from '@rrweb/rrweb-plugin-console-record';
|
|
5
|
+
import '@opentelemetry/sdk-trace-base';
|
|
6
|
+
import '@opentelemetry/sdk-trace-web';
|
|
7
|
+
import '@opentelemetry/instrumentation';
|
|
8
|
+
import 'error-stack-parser';
|
|
9
|
+
import '@opentelemetry/instrumentation-fetch';
|
|
10
|
+
import '@opentelemetry/instrumentation-xml-http-request';
|
|
11
|
+
import 'web-vitals/attribution';
|
|
12
|
+
import '@opentelemetry/api';
|
|
13
|
+
import '@opentelemetry/propagator-b3';
|
|
14
|
+
import '@opentelemetry/propagator-aws-xray';
|
|
15
|
+
|
|
16
|
+
var EventType = /* @__PURE__ */ ((EventType2) => {
|
|
17
|
+
EventType2[EventType2["DomContentLoaded"] = 0] = "DomContentLoaded";
|
|
18
|
+
EventType2[EventType2["Load"] = 1] = "Load";
|
|
19
|
+
EventType2[EventType2["FullSnapshot"] = 2] = "FullSnapshot";
|
|
20
|
+
EventType2[EventType2["IncrementalSnapshot"] = 3] = "IncrementalSnapshot";
|
|
21
|
+
EventType2[EventType2["Meta"] = 4] = "Meta";
|
|
22
|
+
EventType2[EventType2["Custom"] = 5] = "Custom";
|
|
23
|
+
EventType2[EventType2["Plugin"] = 6] = "Plugin";
|
|
24
|
+
return EventType2;
|
|
25
|
+
})(EventType || {});
|
|
26
|
+
|
|
27
|
+
var __defProp = Object.defineProperty;
|
|
28
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
29
|
+
var __publicField = (obj, key, value) => {
|
|
30
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
31
|
+
return value;
|
|
32
|
+
};
|
|
33
|
+
var NodeType = /* @__PURE__ */ ((NodeType2) => {
|
|
34
|
+
NodeType2[NodeType2["Document"] = 0] = "Document";
|
|
35
|
+
NodeType2[NodeType2["DocumentType"] = 1] = "DocumentType";
|
|
36
|
+
NodeType2[NodeType2["Element"] = 2] = "Element";
|
|
37
|
+
NodeType2[NodeType2["Text"] = 3] = "Text";
|
|
38
|
+
NodeType2[NodeType2["CDATA"] = 4] = "CDATA";
|
|
39
|
+
NodeType2[NodeType2["Comment"] = 5] = "Comment";
|
|
40
|
+
return NodeType2;
|
|
41
|
+
})(NodeType || {});
|
|
42
|
+
function isElement(n) {
|
|
43
|
+
return n.nodeType === n.ELEMENT_NODE;
|
|
44
|
+
}
|
|
45
|
+
function isShadowRoot(n) {
|
|
46
|
+
const host = n == null ? undefined : n.host;
|
|
47
|
+
return Boolean((host == null ? undefined : host.shadowRoot) === n);
|
|
48
|
+
}
|
|
49
|
+
function isNativeShadowDom(shadowRoot) {
|
|
50
|
+
return Object.prototype.toString.call(shadowRoot) === "[object ShadowRoot]";
|
|
51
|
+
}
|
|
52
|
+
function fixBrowserCompatibilityIssuesInCSS(cssText) {
|
|
53
|
+
if (cssText.includes(" background-clip: text;") && !cssText.includes(" -webkit-background-clip: text;")) {
|
|
54
|
+
cssText = cssText.replace(
|
|
55
|
+
/\sbackground-clip:\s*text;/g,
|
|
56
|
+
" -webkit-background-clip: text; background-clip: text;"
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return cssText;
|
|
60
|
+
}
|
|
61
|
+
function escapeImportStatement(rule) {
|
|
62
|
+
const { cssText } = rule;
|
|
63
|
+
if (cssText.split('"').length < 3)
|
|
64
|
+
return cssText;
|
|
65
|
+
const statement = ["@import", `url(${JSON.stringify(rule.href)})`];
|
|
66
|
+
if (rule.layerName === "") {
|
|
67
|
+
statement.push(`layer`);
|
|
68
|
+
} else if (rule.layerName) {
|
|
69
|
+
statement.push(`layer(${rule.layerName})`);
|
|
70
|
+
}
|
|
71
|
+
if (rule.supportsText) {
|
|
72
|
+
statement.push(`supports(${rule.supportsText})`);
|
|
73
|
+
}
|
|
74
|
+
if (rule.media.length) {
|
|
75
|
+
statement.push(rule.media.mediaText);
|
|
76
|
+
}
|
|
77
|
+
return statement.join(" ") + ";";
|
|
78
|
+
}
|
|
79
|
+
function stringifyStylesheet(s) {
|
|
80
|
+
try {
|
|
81
|
+
const rules = s.rules || s.cssRules;
|
|
82
|
+
return rules ? fixBrowserCompatibilityIssuesInCSS(
|
|
83
|
+
Array.from(rules, stringifyRule).join("")
|
|
84
|
+
) : null;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function stringifyRule(rule) {
|
|
90
|
+
let importStringified;
|
|
91
|
+
if (isCSSImportRule(rule)) {
|
|
92
|
+
try {
|
|
93
|
+
importStringified = // for same-origin stylesheets,
|
|
94
|
+
// we can access the imported stylesheet rules directly
|
|
95
|
+
stringifyStylesheet(rule.styleSheet) || // work around browser issues with the raw string `@import url(...)` statement
|
|
96
|
+
escapeImportStatement(rule);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
}
|
|
99
|
+
} else if (isCSSStyleRule(rule) && rule.selectorText.includes(":")) {
|
|
100
|
+
return fixSafariColons(rule.cssText);
|
|
101
|
+
}
|
|
102
|
+
return importStringified || rule.cssText;
|
|
103
|
+
}
|
|
104
|
+
function fixSafariColons(cssStringified) {
|
|
105
|
+
const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
|
|
106
|
+
return cssStringified.replace(regex, "$1\\$2");
|
|
107
|
+
}
|
|
108
|
+
function isCSSImportRule(rule) {
|
|
109
|
+
return "styleSheet" in rule;
|
|
110
|
+
}
|
|
111
|
+
function isCSSStyleRule(rule) {
|
|
112
|
+
return "selectorText" in rule;
|
|
113
|
+
}
|
|
114
|
+
class Mirror {
|
|
115
|
+
constructor() {
|
|
116
|
+
__publicField(this, "idNodeMap", /* @__PURE__ */ new Map());
|
|
117
|
+
__publicField(this, "nodeMetaMap", /* @__PURE__ */ new WeakMap());
|
|
118
|
+
}
|
|
119
|
+
getId(n) {
|
|
120
|
+
var _a;
|
|
121
|
+
if (!n)
|
|
122
|
+
return -1;
|
|
123
|
+
const id = (_a = this.getMeta(n)) == null ? undefined : _a.id;
|
|
124
|
+
return id ?? -1;
|
|
125
|
+
}
|
|
126
|
+
getNode(id) {
|
|
127
|
+
return this.idNodeMap.get(id) || null;
|
|
128
|
+
}
|
|
129
|
+
getIds() {
|
|
130
|
+
return Array.from(this.idNodeMap.keys());
|
|
131
|
+
}
|
|
132
|
+
getMeta(n) {
|
|
133
|
+
return this.nodeMetaMap.get(n) || null;
|
|
134
|
+
}
|
|
135
|
+
// removes the node from idNodeMap
|
|
136
|
+
// doesn't remove the node from nodeMetaMap
|
|
137
|
+
removeNodeFromMap(n) {
|
|
138
|
+
const id = this.getId(n);
|
|
139
|
+
this.idNodeMap.delete(id);
|
|
140
|
+
if (n.childNodes) {
|
|
141
|
+
n.childNodes.forEach(
|
|
142
|
+
(childNode) => this.removeNodeFromMap(childNode)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
has(id) {
|
|
147
|
+
return this.idNodeMap.has(id);
|
|
148
|
+
}
|
|
149
|
+
hasNode(node) {
|
|
150
|
+
return this.nodeMetaMap.has(node);
|
|
151
|
+
}
|
|
152
|
+
add(n, meta) {
|
|
153
|
+
const id = meta.id;
|
|
154
|
+
this.idNodeMap.set(id, n);
|
|
155
|
+
this.nodeMetaMap.set(n, meta);
|
|
156
|
+
}
|
|
157
|
+
replace(id, n) {
|
|
158
|
+
const oldNode = this.getNode(id);
|
|
159
|
+
if (oldNode) {
|
|
160
|
+
const meta = this.nodeMetaMap.get(oldNode);
|
|
161
|
+
if (meta)
|
|
162
|
+
this.nodeMetaMap.set(n, meta);
|
|
163
|
+
}
|
|
164
|
+
this.idNodeMap.set(id, n);
|
|
165
|
+
}
|
|
166
|
+
reset() {
|
|
167
|
+
this.idNodeMap = /* @__PURE__ */ new Map();
|
|
168
|
+
this.nodeMetaMap = /* @__PURE__ */ new WeakMap();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function maskInputValue({
|
|
172
|
+
element,
|
|
173
|
+
maskInputOptions,
|
|
174
|
+
tagName,
|
|
175
|
+
type,
|
|
176
|
+
value,
|
|
177
|
+
maskInputFn
|
|
178
|
+
}) {
|
|
179
|
+
let text = value || "";
|
|
180
|
+
const actualType = type && toLowerCase(type);
|
|
181
|
+
if (maskInputOptions[tagName.toLowerCase()] || actualType && maskInputOptions[actualType]) {
|
|
182
|
+
if (maskInputFn) {
|
|
183
|
+
text = maskInputFn(text, element);
|
|
184
|
+
} else {
|
|
185
|
+
text = "*".repeat(text.length);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return text;
|
|
189
|
+
}
|
|
190
|
+
function toLowerCase(str) {
|
|
191
|
+
return str.toLowerCase();
|
|
192
|
+
}
|
|
193
|
+
const ORIGINAL_ATTRIBUTE_NAME = "__rrweb_original__";
|
|
194
|
+
function is2DCanvasBlank(canvas) {
|
|
195
|
+
const ctx = canvas.getContext("2d");
|
|
196
|
+
if (!ctx)
|
|
197
|
+
return true;
|
|
198
|
+
const chunkSize = 50;
|
|
199
|
+
for (let x = 0; x < canvas.width; x += chunkSize) {
|
|
200
|
+
for (let y = 0; y < canvas.height; y += chunkSize) {
|
|
201
|
+
const getImageData = ctx.getImageData;
|
|
202
|
+
const originalGetImageData = ORIGINAL_ATTRIBUTE_NAME in getImageData ? getImageData[ORIGINAL_ATTRIBUTE_NAME] : getImageData;
|
|
203
|
+
const pixelBuffer = new Uint32Array(
|
|
204
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
|
205
|
+
originalGetImageData.call(
|
|
206
|
+
ctx,
|
|
207
|
+
x,
|
|
208
|
+
y,
|
|
209
|
+
Math.min(chunkSize, canvas.width - x),
|
|
210
|
+
Math.min(chunkSize, canvas.height - y)
|
|
211
|
+
).data.buffer
|
|
212
|
+
);
|
|
213
|
+
if (pixelBuffer.some((pixel) => pixel !== 0))
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
function getInputType(element) {
|
|
220
|
+
const type = element.type;
|
|
221
|
+
return element.hasAttribute("data-rr-is-password") ? "password" : type ? (
|
|
222
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
223
|
+
toLowerCase(type)
|
|
224
|
+
) : null;
|
|
225
|
+
}
|
|
226
|
+
function extractFileExtension(path, baseURL) {
|
|
227
|
+
let url;
|
|
228
|
+
try {
|
|
229
|
+
url = new URL(path, baseURL ?? window.location.href);
|
|
230
|
+
} catch (err) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
const regex = /\.([0-9a-z]+)(?:$)/i;
|
|
234
|
+
const match = url.pathname.match(regex);
|
|
235
|
+
return (match == null ? undefined : match[1]) ?? null;
|
|
236
|
+
}
|
|
237
|
+
let _id = 1;
|
|
238
|
+
const tagNameRegex = new RegExp("[^a-z0-9-_:]");
|
|
239
|
+
const IGNORED_NODE = -2;
|
|
240
|
+
function genId() {
|
|
241
|
+
return _id++;
|
|
242
|
+
}
|
|
243
|
+
function getValidTagName(element) {
|
|
244
|
+
if (element instanceof HTMLFormElement) {
|
|
245
|
+
return "form";
|
|
246
|
+
}
|
|
247
|
+
const processedTagName = toLowerCase(element.tagName);
|
|
248
|
+
if (tagNameRegex.test(processedTagName)) {
|
|
249
|
+
return "div";
|
|
250
|
+
}
|
|
251
|
+
return processedTagName;
|
|
252
|
+
}
|
|
253
|
+
function extractOrigin(url) {
|
|
254
|
+
let origin = "";
|
|
255
|
+
if (url.indexOf("//") > -1) {
|
|
256
|
+
origin = url.split("/").slice(0, 3).join("/");
|
|
257
|
+
} else {
|
|
258
|
+
origin = url.split("/")[0];
|
|
259
|
+
}
|
|
260
|
+
origin = origin.split("?")[0];
|
|
261
|
+
return origin;
|
|
262
|
+
}
|
|
263
|
+
let canvasService;
|
|
264
|
+
let canvasCtx;
|
|
265
|
+
const URL_IN_CSS_REF = /url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm;
|
|
266
|
+
const URL_PROTOCOL_MATCH = /^(?:[a-z+]+:)?\/\//i;
|
|
267
|
+
const URL_WWW_MATCH = /^www\..*/i;
|
|
268
|
+
const DATA_URI = /^(data:)([^,]*),(.*)/i;
|
|
269
|
+
function absoluteToStylesheet(cssText, href) {
|
|
270
|
+
return (cssText || "").replace(
|
|
271
|
+
URL_IN_CSS_REF,
|
|
272
|
+
(origin, quote1, path1, quote2, path2, path3) => {
|
|
273
|
+
const filePath = path1 || path2 || path3;
|
|
274
|
+
const maybeQuote = quote1 || quote2 || "";
|
|
275
|
+
if (!filePath) {
|
|
276
|
+
return origin;
|
|
277
|
+
}
|
|
278
|
+
if (URL_PROTOCOL_MATCH.test(filePath) || URL_WWW_MATCH.test(filePath)) {
|
|
279
|
+
return `url(${maybeQuote}${filePath}${maybeQuote})`;
|
|
280
|
+
}
|
|
281
|
+
if (DATA_URI.test(filePath)) {
|
|
282
|
+
return `url(${maybeQuote}${filePath}${maybeQuote})`;
|
|
283
|
+
}
|
|
284
|
+
if (filePath[0] === "/") {
|
|
285
|
+
return `url(${maybeQuote}${extractOrigin(href) + filePath}${maybeQuote})`;
|
|
286
|
+
}
|
|
287
|
+
const stack = href.split("/");
|
|
288
|
+
const parts = filePath.split("/");
|
|
289
|
+
stack.pop();
|
|
290
|
+
for (const part of parts) {
|
|
291
|
+
if (part === ".") {
|
|
292
|
+
continue;
|
|
293
|
+
} else if (part === "..") {
|
|
294
|
+
stack.pop();
|
|
295
|
+
} else {
|
|
296
|
+
stack.push(part);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return `url(${maybeQuote}${stack.join("/")}${maybeQuote})`;
|
|
300
|
+
}
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
const SRCSET_NOT_SPACES = /^[^ \t\n\r\u000c]+/;
|
|
304
|
+
const SRCSET_COMMAS_OR_SPACES = /^[, \t\n\r\u000c]+/;
|
|
305
|
+
function getAbsoluteSrcsetString(doc, attributeValue) {
|
|
306
|
+
if (attributeValue.trim() === "") {
|
|
307
|
+
return attributeValue;
|
|
308
|
+
}
|
|
309
|
+
let pos = 0;
|
|
310
|
+
function collectCharacters(regEx) {
|
|
311
|
+
let chars;
|
|
312
|
+
const match = regEx.exec(attributeValue.substring(pos));
|
|
313
|
+
if (match) {
|
|
314
|
+
chars = match[0];
|
|
315
|
+
pos += chars.length;
|
|
316
|
+
return chars;
|
|
317
|
+
}
|
|
318
|
+
return "";
|
|
319
|
+
}
|
|
320
|
+
const output = [];
|
|
321
|
+
while (true) {
|
|
322
|
+
collectCharacters(SRCSET_COMMAS_OR_SPACES);
|
|
323
|
+
if (pos >= attributeValue.length) {
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
let url = collectCharacters(SRCSET_NOT_SPACES);
|
|
327
|
+
if (url.slice(-1) === ",") {
|
|
328
|
+
url = absoluteToDoc(doc, url.substring(0, url.length - 1));
|
|
329
|
+
output.push(url);
|
|
330
|
+
} else {
|
|
331
|
+
let descriptorsStr = "";
|
|
332
|
+
url = absoluteToDoc(doc, url);
|
|
333
|
+
let inParens = false;
|
|
334
|
+
while (true) {
|
|
335
|
+
const c = attributeValue.charAt(pos);
|
|
336
|
+
if (c === "") {
|
|
337
|
+
output.push((url + descriptorsStr).trim());
|
|
338
|
+
break;
|
|
339
|
+
} else if (!inParens) {
|
|
340
|
+
if (c === ",") {
|
|
341
|
+
pos += 1;
|
|
342
|
+
output.push((url + descriptorsStr).trim());
|
|
343
|
+
break;
|
|
344
|
+
} else if (c === "(") {
|
|
345
|
+
inParens = true;
|
|
346
|
+
}
|
|
347
|
+
} else {
|
|
348
|
+
if (c === ")") {
|
|
349
|
+
inParens = false;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
descriptorsStr += c;
|
|
353
|
+
pos += 1;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return output.join(", ");
|
|
358
|
+
}
|
|
359
|
+
const cachedDocument = /* @__PURE__ */ new WeakMap();
|
|
360
|
+
function absoluteToDoc(doc, attributeValue) {
|
|
361
|
+
if (!attributeValue || attributeValue.trim() === "") {
|
|
362
|
+
return attributeValue;
|
|
363
|
+
}
|
|
364
|
+
return getHref(doc, attributeValue);
|
|
365
|
+
}
|
|
366
|
+
function isSVGElement(el) {
|
|
367
|
+
return Boolean(el.tagName === "svg" || el.ownerSVGElement);
|
|
368
|
+
}
|
|
369
|
+
function getHref(doc, customHref) {
|
|
370
|
+
let a = cachedDocument.get(doc);
|
|
371
|
+
if (!a) {
|
|
372
|
+
a = doc.createElement("a");
|
|
373
|
+
cachedDocument.set(doc, a);
|
|
374
|
+
}
|
|
375
|
+
if (!customHref) {
|
|
376
|
+
customHref = "";
|
|
377
|
+
} else if (customHref.startsWith("blob:") || customHref.startsWith("data:")) {
|
|
378
|
+
return customHref;
|
|
379
|
+
}
|
|
380
|
+
a.setAttribute("href", customHref);
|
|
381
|
+
return a.href;
|
|
382
|
+
}
|
|
383
|
+
function transformAttribute(doc, tagName, name, value) {
|
|
384
|
+
if (!value) {
|
|
385
|
+
return value;
|
|
386
|
+
}
|
|
387
|
+
if (name === "src" || name === "href" && !(tagName === "use" && value[0] === "#")) {
|
|
388
|
+
return absoluteToDoc(doc, value);
|
|
389
|
+
} else if (name === "xlink:href" && value[0] !== "#") {
|
|
390
|
+
return absoluteToDoc(doc, value);
|
|
391
|
+
} else if (name === "background" && (tagName === "table" || tagName === "td" || tagName === "th")) {
|
|
392
|
+
return absoluteToDoc(doc, value);
|
|
393
|
+
} else if (name === "srcset") {
|
|
394
|
+
return getAbsoluteSrcsetString(doc, value);
|
|
395
|
+
} else if (name === "style") {
|
|
396
|
+
return absoluteToStylesheet(value, getHref(doc));
|
|
397
|
+
} else if (tagName === "object" && name === "data") {
|
|
398
|
+
return absoluteToDoc(doc, value);
|
|
399
|
+
}
|
|
400
|
+
return value;
|
|
401
|
+
}
|
|
402
|
+
function ignoreAttribute(tagName, name, _value) {
|
|
403
|
+
return (tagName === "video" || tagName === "audio") && name === "autoplay";
|
|
404
|
+
}
|
|
405
|
+
function _isBlockedElement(element, blockClass, blockSelector) {
|
|
406
|
+
try {
|
|
407
|
+
if (typeof blockClass === "string") {
|
|
408
|
+
if (element.classList.contains(blockClass)) {
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
} else {
|
|
412
|
+
for (let eIndex = element.classList.length; eIndex--; ) {
|
|
413
|
+
const className = element.classList[eIndex];
|
|
414
|
+
if (blockClass.test(className)) {
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (blockSelector) {
|
|
420
|
+
return element.matches(blockSelector);
|
|
421
|
+
}
|
|
422
|
+
} catch (e) {
|
|
423
|
+
}
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
function classMatchesRegex(node, regex, checkAncestors) {
|
|
427
|
+
if (!node)
|
|
428
|
+
return false;
|
|
429
|
+
if (node.nodeType !== node.ELEMENT_NODE) {
|
|
430
|
+
if (!checkAncestors)
|
|
431
|
+
return false;
|
|
432
|
+
return classMatchesRegex(node.parentNode, regex, checkAncestors);
|
|
433
|
+
}
|
|
434
|
+
for (let eIndex = node.classList.length; eIndex--; ) {
|
|
435
|
+
const className = node.classList[eIndex];
|
|
436
|
+
if (regex.test(className)) {
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if (!checkAncestors)
|
|
441
|
+
return false;
|
|
442
|
+
return classMatchesRegex(node.parentNode, regex, checkAncestors);
|
|
443
|
+
}
|
|
444
|
+
function needMaskingText(node, maskTextClass, maskTextSelector, checkAncestors) {
|
|
445
|
+
try {
|
|
446
|
+
const el = node.nodeType === node.ELEMENT_NODE ? node : node.parentElement;
|
|
447
|
+
if (el === null)
|
|
448
|
+
return false;
|
|
449
|
+
if (typeof maskTextClass === "string") {
|
|
450
|
+
if (checkAncestors) {
|
|
451
|
+
if (el.closest(`.${maskTextClass}`))
|
|
452
|
+
return true;
|
|
453
|
+
} else {
|
|
454
|
+
if (el.classList.contains(maskTextClass))
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
} else {
|
|
458
|
+
if (classMatchesRegex(el, maskTextClass, checkAncestors))
|
|
459
|
+
return true;
|
|
460
|
+
}
|
|
461
|
+
if (maskTextSelector) {
|
|
462
|
+
if (checkAncestors) {
|
|
463
|
+
if (el.closest(maskTextSelector))
|
|
464
|
+
return true;
|
|
465
|
+
} else {
|
|
466
|
+
if (el.matches(maskTextSelector))
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
} catch (e) {
|
|
471
|
+
}
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
function onceIframeLoaded(iframeEl, listener, iframeLoadTimeout) {
|
|
475
|
+
const win = iframeEl.contentWindow;
|
|
476
|
+
if (!win) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
let fired = false;
|
|
480
|
+
let readyState;
|
|
481
|
+
try {
|
|
482
|
+
readyState = win.document.readyState;
|
|
483
|
+
} catch (error) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
if (readyState !== "complete") {
|
|
487
|
+
const timer = setTimeout(() => {
|
|
488
|
+
if (!fired) {
|
|
489
|
+
listener();
|
|
490
|
+
fired = true;
|
|
491
|
+
}
|
|
492
|
+
}, iframeLoadTimeout);
|
|
493
|
+
iframeEl.addEventListener("load", () => {
|
|
494
|
+
clearTimeout(timer);
|
|
495
|
+
fired = true;
|
|
496
|
+
listener();
|
|
497
|
+
});
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
const blankUrl = "about:blank";
|
|
501
|
+
if (win.location.href !== blankUrl || iframeEl.src === blankUrl || iframeEl.src === "") {
|
|
502
|
+
setTimeout(listener, 0);
|
|
503
|
+
return iframeEl.addEventListener("load", listener);
|
|
504
|
+
}
|
|
505
|
+
iframeEl.addEventListener("load", listener);
|
|
506
|
+
}
|
|
507
|
+
function onceStylesheetLoaded(link, listener, styleSheetLoadTimeout) {
|
|
508
|
+
let fired = false;
|
|
509
|
+
let styleSheetLoaded;
|
|
510
|
+
try {
|
|
511
|
+
styleSheetLoaded = link.sheet;
|
|
512
|
+
} catch (error) {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
if (styleSheetLoaded)
|
|
516
|
+
return;
|
|
517
|
+
const timer = setTimeout(() => {
|
|
518
|
+
if (!fired) {
|
|
519
|
+
listener();
|
|
520
|
+
fired = true;
|
|
521
|
+
}
|
|
522
|
+
}, styleSheetLoadTimeout);
|
|
523
|
+
link.addEventListener("load", () => {
|
|
524
|
+
clearTimeout(timer);
|
|
525
|
+
fired = true;
|
|
526
|
+
listener();
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
function serializeNode(n, options) {
|
|
530
|
+
const {
|
|
531
|
+
doc,
|
|
532
|
+
mirror,
|
|
533
|
+
blockClass,
|
|
534
|
+
blockSelector,
|
|
535
|
+
needsMask,
|
|
536
|
+
inlineStylesheet,
|
|
537
|
+
maskInputOptions = {},
|
|
538
|
+
maskTextFn,
|
|
539
|
+
maskInputFn,
|
|
540
|
+
dataURLOptions = {},
|
|
541
|
+
inlineImages,
|
|
542
|
+
recordCanvas,
|
|
543
|
+
keepIframeSrcFn,
|
|
544
|
+
newlyAddedElement = false
|
|
545
|
+
} = options;
|
|
546
|
+
const rootId = getRootId(doc, mirror);
|
|
547
|
+
switch (n.nodeType) {
|
|
548
|
+
case n.DOCUMENT_NODE:
|
|
549
|
+
if (n.compatMode !== "CSS1Compat") {
|
|
550
|
+
return {
|
|
551
|
+
type: NodeType.Document,
|
|
552
|
+
childNodes: [],
|
|
553
|
+
compatMode: n.compatMode
|
|
554
|
+
// probably "BackCompat"
|
|
555
|
+
};
|
|
556
|
+
} else {
|
|
557
|
+
return {
|
|
558
|
+
type: NodeType.Document,
|
|
559
|
+
childNodes: []
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
case n.DOCUMENT_TYPE_NODE:
|
|
563
|
+
return {
|
|
564
|
+
type: NodeType.DocumentType,
|
|
565
|
+
name: n.name,
|
|
566
|
+
publicId: n.publicId,
|
|
567
|
+
systemId: n.systemId,
|
|
568
|
+
rootId
|
|
569
|
+
};
|
|
570
|
+
case n.ELEMENT_NODE:
|
|
571
|
+
return serializeElementNode(n, {
|
|
572
|
+
doc,
|
|
573
|
+
blockClass,
|
|
574
|
+
blockSelector,
|
|
575
|
+
inlineStylesheet,
|
|
576
|
+
maskInputOptions,
|
|
577
|
+
maskInputFn,
|
|
578
|
+
dataURLOptions,
|
|
579
|
+
inlineImages,
|
|
580
|
+
recordCanvas,
|
|
581
|
+
keepIframeSrcFn,
|
|
582
|
+
newlyAddedElement,
|
|
583
|
+
rootId
|
|
584
|
+
});
|
|
585
|
+
case n.TEXT_NODE:
|
|
586
|
+
return serializeTextNode(n, {
|
|
587
|
+
doc,
|
|
588
|
+
needsMask,
|
|
589
|
+
maskTextFn,
|
|
590
|
+
rootId
|
|
591
|
+
});
|
|
592
|
+
case n.CDATA_SECTION_NODE:
|
|
593
|
+
return {
|
|
594
|
+
type: NodeType.CDATA,
|
|
595
|
+
textContent: "",
|
|
596
|
+
rootId
|
|
597
|
+
};
|
|
598
|
+
case n.COMMENT_NODE:
|
|
599
|
+
return {
|
|
600
|
+
type: NodeType.Comment,
|
|
601
|
+
textContent: n.textContent || "",
|
|
602
|
+
rootId
|
|
603
|
+
};
|
|
604
|
+
default:
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
function getRootId(doc, mirror) {
|
|
609
|
+
if (!mirror.hasNode(doc))
|
|
610
|
+
return undefined;
|
|
611
|
+
const docId = mirror.getId(doc);
|
|
612
|
+
return docId === 1 ? undefined : docId;
|
|
613
|
+
}
|
|
614
|
+
function serializeTextNode(n, options) {
|
|
615
|
+
var _a;
|
|
616
|
+
const { needsMask, maskTextFn, rootId } = options;
|
|
617
|
+
const parentTagName = n.parentNode && n.parentNode.tagName;
|
|
618
|
+
let textContent = n.textContent;
|
|
619
|
+
const isStyle = parentTagName === "STYLE" ? true : undefined;
|
|
620
|
+
const isScript = parentTagName === "SCRIPT" ? true : undefined;
|
|
621
|
+
if (isStyle && textContent) {
|
|
622
|
+
try {
|
|
623
|
+
if (n.nextSibling || n.previousSibling) {
|
|
624
|
+
} else if ((_a = n.parentNode.sheet) == null ? void 0 : _a.cssRules) {
|
|
625
|
+
textContent = stringifyStylesheet(
|
|
626
|
+
n.parentNode.sheet
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
} catch (err) {
|
|
630
|
+
console.warn(
|
|
631
|
+
`Cannot get CSS styles from text's parentNode. Error: ${err}`,
|
|
632
|
+
n
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
textContent = absoluteToStylesheet(textContent, getHref(options.doc));
|
|
636
|
+
}
|
|
637
|
+
if (isScript) {
|
|
638
|
+
textContent = "SCRIPT_PLACEHOLDER";
|
|
639
|
+
}
|
|
640
|
+
if (!isStyle && !isScript && textContent && needsMask) {
|
|
641
|
+
textContent = maskTextFn ? maskTextFn(textContent, n.parentElement) : textContent.replace(/[\S]/g, "*");
|
|
642
|
+
}
|
|
643
|
+
return {
|
|
644
|
+
type: NodeType.Text,
|
|
645
|
+
textContent: textContent || "",
|
|
646
|
+
isStyle,
|
|
647
|
+
rootId
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
function serializeElementNode(n, options) {
|
|
651
|
+
const {
|
|
652
|
+
doc,
|
|
653
|
+
blockClass,
|
|
654
|
+
blockSelector,
|
|
655
|
+
inlineStylesheet,
|
|
656
|
+
maskInputOptions = {},
|
|
657
|
+
maskInputFn,
|
|
658
|
+
dataURLOptions = {},
|
|
659
|
+
inlineImages,
|
|
660
|
+
recordCanvas,
|
|
661
|
+
keepIframeSrcFn,
|
|
662
|
+
newlyAddedElement = false,
|
|
663
|
+
rootId
|
|
664
|
+
} = options;
|
|
665
|
+
const needBlock = _isBlockedElement(n, blockClass, blockSelector);
|
|
666
|
+
const tagName = getValidTagName(n);
|
|
667
|
+
let attributes2 = {};
|
|
668
|
+
const len = n.attributes.length;
|
|
669
|
+
for (let i = 0; i < len; i++) {
|
|
670
|
+
const attr = n.attributes[i];
|
|
671
|
+
if (!ignoreAttribute(tagName, attr.name, attr.value)) {
|
|
672
|
+
attributes2[attr.name] = transformAttribute(
|
|
673
|
+
doc,
|
|
674
|
+
tagName,
|
|
675
|
+
toLowerCase(attr.name),
|
|
676
|
+
attr.value
|
|
677
|
+
);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
if (tagName === "link" && inlineStylesheet) {
|
|
681
|
+
const stylesheet = Array.from(doc.styleSheets).find((s) => {
|
|
682
|
+
return s.href === n.href;
|
|
683
|
+
});
|
|
684
|
+
let cssText = null;
|
|
685
|
+
if (stylesheet) {
|
|
686
|
+
cssText = stringifyStylesheet(stylesheet);
|
|
687
|
+
}
|
|
688
|
+
if (cssText) {
|
|
689
|
+
delete attributes2.rel;
|
|
690
|
+
delete attributes2.href;
|
|
691
|
+
attributes2._cssText = absoluteToStylesheet(cssText, stylesheet.href);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
if (tagName === "style" && n.sheet && // TODO: Currently we only try to get dynamic stylesheet when it is an empty style element
|
|
695
|
+
!(n.innerText || n.textContent || "").trim().length) {
|
|
696
|
+
const cssText = stringifyStylesheet(
|
|
697
|
+
n.sheet
|
|
698
|
+
);
|
|
699
|
+
if (cssText) {
|
|
700
|
+
attributes2._cssText = absoluteToStylesheet(cssText, getHref(doc));
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (tagName === "input" || tagName === "textarea" || tagName === "select") {
|
|
704
|
+
const value = n.value;
|
|
705
|
+
const checked = n.checked;
|
|
706
|
+
if (attributes2.type !== "radio" && attributes2.type !== "checkbox" && attributes2.type !== "submit" && attributes2.type !== "button" && value) {
|
|
707
|
+
attributes2.value = maskInputValue({
|
|
708
|
+
element: n,
|
|
709
|
+
type: getInputType(n),
|
|
710
|
+
tagName,
|
|
711
|
+
value,
|
|
712
|
+
maskInputOptions,
|
|
713
|
+
maskInputFn
|
|
714
|
+
});
|
|
715
|
+
} else if (checked) {
|
|
716
|
+
attributes2.checked = checked;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
if (tagName === "option") {
|
|
720
|
+
if (n.selected && !maskInputOptions["select"]) {
|
|
721
|
+
attributes2.selected = true;
|
|
722
|
+
} else {
|
|
723
|
+
delete attributes2.selected;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
if (tagName === "canvas" && recordCanvas) {
|
|
727
|
+
if (n.__context === "2d") {
|
|
728
|
+
if (!is2DCanvasBlank(n)) {
|
|
729
|
+
attributes2.rr_dataURL = n.toDataURL(
|
|
730
|
+
dataURLOptions.type,
|
|
731
|
+
dataURLOptions.quality
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
} else if (!("__context" in n)) {
|
|
735
|
+
const canvasDataURL = n.toDataURL(
|
|
736
|
+
dataURLOptions.type,
|
|
737
|
+
dataURLOptions.quality
|
|
738
|
+
);
|
|
739
|
+
const blankCanvas = doc.createElement("canvas");
|
|
740
|
+
blankCanvas.width = n.width;
|
|
741
|
+
blankCanvas.height = n.height;
|
|
742
|
+
const blankCanvasDataURL = blankCanvas.toDataURL(
|
|
743
|
+
dataURLOptions.type,
|
|
744
|
+
dataURLOptions.quality
|
|
745
|
+
);
|
|
746
|
+
if (canvasDataURL !== blankCanvasDataURL) {
|
|
747
|
+
attributes2.rr_dataURL = canvasDataURL;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
if (tagName === "img" && inlineImages) {
|
|
752
|
+
if (!canvasService) {
|
|
753
|
+
canvasService = doc.createElement("canvas");
|
|
754
|
+
canvasCtx = canvasService.getContext("2d");
|
|
755
|
+
}
|
|
756
|
+
const image = n;
|
|
757
|
+
const imageSrc = image.currentSrc || image.getAttribute("src") || "<unknown-src>";
|
|
758
|
+
const priorCrossOrigin = image.crossOrigin;
|
|
759
|
+
const recordInlineImage = () => {
|
|
760
|
+
image.removeEventListener("load", recordInlineImage);
|
|
761
|
+
try {
|
|
762
|
+
canvasService.width = image.naturalWidth;
|
|
763
|
+
canvasService.height = image.naturalHeight;
|
|
764
|
+
canvasCtx.drawImage(image, 0, 0);
|
|
765
|
+
attributes2.rr_dataURL = canvasService.toDataURL(
|
|
766
|
+
dataURLOptions.type,
|
|
767
|
+
dataURLOptions.quality
|
|
768
|
+
);
|
|
769
|
+
} catch (err) {
|
|
770
|
+
if (image.crossOrigin !== "anonymous") {
|
|
771
|
+
image.crossOrigin = "anonymous";
|
|
772
|
+
if (image.complete && image.naturalWidth !== 0)
|
|
773
|
+
recordInlineImage();
|
|
774
|
+
else
|
|
775
|
+
image.addEventListener("load", recordInlineImage);
|
|
776
|
+
return;
|
|
777
|
+
} else {
|
|
778
|
+
console.warn(
|
|
779
|
+
`Cannot inline img src=${imageSrc}! Error: ${err}`
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
if (image.crossOrigin === "anonymous") {
|
|
784
|
+
priorCrossOrigin ? attributes2.crossOrigin = priorCrossOrigin : image.removeAttribute("crossorigin");
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
if (image.complete && image.naturalWidth !== 0)
|
|
788
|
+
recordInlineImage();
|
|
789
|
+
else
|
|
790
|
+
image.addEventListener("load", recordInlineImage);
|
|
791
|
+
}
|
|
792
|
+
if (tagName === "audio" || tagName === "video") {
|
|
793
|
+
const mediaAttributes = attributes2;
|
|
794
|
+
mediaAttributes.rr_mediaState = n.paused ? "paused" : "played";
|
|
795
|
+
mediaAttributes.rr_mediaCurrentTime = n.currentTime;
|
|
796
|
+
mediaAttributes.rr_mediaPlaybackRate = n.playbackRate;
|
|
797
|
+
mediaAttributes.rr_mediaMuted = n.muted;
|
|
798
|
+
mediaAttributes.rr_mediaLoop = n.loop;
|
|
799
|
+
mediaAttributes.rr_mediaVolume = n.volume;
|
|
800
|
+
}
|
|
801
|
+
if (!newlyAddedElement) {
|
|
802
|
+
if (n.scrollLeft) {
|
|
803
|
+
attributes2.rr_scrollLeft = n.scrollLeft;
|
|
804
|
+
}
|
|
805
|
+
if (n.scrollTop) {
|
|
806
|
+
attributes2.rr_scrollTop = n.scrollTop;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
if (needBlock) {
|
|
810
|
+
const { width, height } = n.getBoundingClientRect();
|
|
811
|
+
attributes2 = {
|
|
812
|
+
class: attributes2.class,
|
|
813
|
+
rr_width: `${width}px`,
|
|
814
|
+
rr_height: `${height}px`
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
if (tagName === "iframe" && !keepIframeSrcFn(attributes2.src)) {
|
|
818
|
+
if (!n.contentDocument) {
|
|
819
|
+
attributes2.rr_src = attributes2.src;
|
|
820
|
+
}
|
|
821
|
+
delete attributes2.src;
|
|
822
|
+
}
|
|
823
|
+
let isCustomElement;
|
|
824
|
+
try {
|
|
825
|
+
if (customElements.get(tagName))
|
|
826
|
+
isCustomElement = true;
|
|
827
|
+
} catch (e) {
|
|
828
|
+
}
|
|
829
|
+
return {
|
|
830
|
+
type: NodeType.Element,
|
|
831
|
+
tagName,
|
|
832
|
+
attributes: attributes2,
|
|
833
|
+
childNodes: [],
|
|
834
|
+
isSVG: isSVGElement(n) || undefined,
|
|
835
|
+
needBlock,
|
|
836
|
+
rootId,
|
|
837
|
+
isCustom: isCustomElement
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
function lowerIfExists(maybeAttr) {
|
|
841
|
+
if (maybeAttr === undefined || maybeAttr === null) {
|
|
842
|
+
return "";
|
|
843
|
+
} else {
|
|
844
|
+
return maybeAttr.toLowerCase();
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
function slimDOMExcluded(sn, slimDOMOptions) {
|
|
848
|
+
if (slimDOMOptions.comment && sn.type === NodeType.Comment) {
|
|
849
|
+
return true;
|
|
850
|
+
} else if (sn.type === NodeType.Element) {
|
|
851
|
+
if (slimDOMOptions.script && // script tag
|
|
852
|
+
(sn.tagName === "script" || // (module)preload link
|
|
853
|
+
sn.tagName === "link" && (sn.attributes.rel === "preload" || sn.attributes.rel === "modulepreload") && sn.attributes.as === "script" || // prefetch link
|
|
854
|
+
sn.tagName === "link" && sn.attributes.rel === "prefetch" && typeof sn.attributes.href === "string" && extractFileExtension(sn.attributes.href) === "js")) {
|
|
855
|
+
return true;
|
|
856
|
+
} else if (slimDOMOptions.headFavicon && (sn.tagName === "link" && sn.attributes.rel === "shortcut icon" || sn.tagName === "meta" && (lowerIfExists(sn.attributes.name).match(
|
|
857
|
+
/^msapplication-tile(image|color)$/
|
|
858
|
+
) || lowerIfExists(sn.attributes.name) === "application-name" || lowerIfExists(sn.attributes.rel) === "icon" || lowerIfExists(sn.attributes.rel) === "apple-touch-icon" || lowerIfExists(sn.attributes.rel) === "shortcut icon"))) {
|
|
859
|
+
return true;
|
|
860
|
+
} else if (sn.tagName === "meta") {
|
|
861
|
+
if (slimDOMOptions.headMetaDescKeywords && lowerIfExists(sn.attributes.name).match(/^description|keywords$/)) {
|
|
862
|
+
return true;
|
|
863
|
+
} else if (slimDOMOptions.headMetaSocial && (lowerIfExists(sn.attributes.property).match(/^(og|twitter|fb):/) || // og = opengraph (facebook)
|
|
864
|
+
lowerIfExists(sn.attributes.name).match(/^(og|twitter):/) || lowerIfExists(sn.attributes.name) === "pinterest")) {
|
|
865
|
+
return true;
|
|
866
|
+
} else if (slimDOMOptions.headMetaRobots && (lowerIfExists(sn.attributes.name) === "robots" || lowerIfExists(sn.attributes.name) === "googlebot" || lowerIfExists(sn.attributes.name) === "bingbot")) {
|
|
867
|
+
return true;
|
|
868
|
+
} else if (slimDOMOptions.headMetaHttpEquiv && sn.attributes["http-equiv"] !== undefined) {
|
|
869
|
+
return true;
|
|
870
|
+
} 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:/))) {
|
|
871
|
+
return true;
|
|
872
|
+
} 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")) {
|
|
873
|
+
return true;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
return false;
|
|
878
|
+
}
|
|
879
|
+
function serializeNodeWithId(n, options) {
|
|
880
|
+
const {
|
|
881
|
+
doc,
|
|
882
|
+
mirror,
|
|
883
|
+
blockClass,
|
|
884
|
+
blockSelector,
|
|
885
|
+
maskTextClass,
|
|
886
|
+
maskTextSelector,
|
|
887
|
+
skipChild = false,
|
|
888
|
+
inlineStylesheet = true,
|
|
889
|
+
maskInputOptions = {},
|
|
890
|
+
maskTextFn,
|
|
891
|
+
maskInputFn,
|
|
892
|
+
slimDOMOptions,
|
|
893
|
+
dataURLOptions = {},
|
|
894
|
+
inlineImages = false,
|
|
895
|
+
recordCanvas = false,
|
|
896
|
+
onSerialize,
|
|
897
|
+
onIframeLoad,
|
|
898
|
+
iframeLoadTimeout = 5e3,
|
|
899
|
+
onStylesheetLoad,
|
|
900
|
+
stylesheetLoadTimeout = 5e3,
|
|
901
|
+
keepIframeSrcFn = () => false,
|
|
902
|
+
newlyAddedElement = false
|
|
903
|
+
} = options;
|
|
904
|
+
let { needsMask } = options;
|
|
905
|
+
let { preserveWhiteSpace = true } = options;
|
|
906
|
+
if (!needsMask && n.childNodes) {
|
|
907
|
+
const checkAncestors = needsMask === undefined;
|
|
908
|
+
needsMask = needMaskingText(
|
|
909
|
+
n,
|
|
910
|
+
maskTextClass,
|
|
911
|
+
maskTextSelector,
|
|
912
|
+
checkAncestors
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
const _serializedNode = serializeNode(n, {
|
|
916
|
+
doc,
|
|
917
|
+
mirror,
|
|
918
|
+
blockClass,
|
|
919
|
+
blockSelector,
|
|
920
|
+
needsMask,
|
|
921
|
+
inlineStylesheet,
|
|
922
|
+
maskInputOptions,
|
|
923
|
+
maskTextFn,
|
|
924
|
+
maskInputFn,
|
|
925
|
+
dataURLOptions,
|
|
926
|
+
inlineImages,
|
|
927
|
+
recordCanvas,
|
|
928
|
+
keepIframeSrcFn,
|
|
929
|
+
newlyAddedElement
|
|
930
|
+
});
|
|
931
|
+
if (!_serializedNode) {
|
|
932
|
+
console.warn(n, "not serialized");
|
|
933
|
+
return null;
|
|
934
|
+
}
|
|
935
|
+
let id;
|
|
936
|
+
if (mirror.hasNode(n)) {
|
|
937
|
+
id = mirror.getId(n);
|
|
938
|
+
} else if (slimDOMExcluded(_serializedNode, slimDOMOptions) || !preserveWhiteSpace && _serializedNode.type === NodeType.Text && !_serializedNode.isStyle && !_serializedNode.textContent.replace(/^\s+|\s+$/gm, "").length) {
|
|
939
|
+
id = IGNORED_NODE;
|
|
940
|
+
} else {
|
|
941
|
+
id = genId();
|
|
942
|
+
}
|
|
943
|
+
const serializedNode2 = Object.assign(_serializedNode, { id });
|
|
944
|
+
mirror.add(n, serializedNode2);
|
|
945
|
+
if (id === IGNORED_NODE) {
|
|
946
|
+
return null;
|
|
947
|
+
}
|
|
948
|
+
if (onSerialize) {
|
|
949
|
+
onSerialize(n);
|
|
950
|
+
}
|
|
951
|
+
let recordChild = !skipChild;
|
|
952
|
+
if (serializedNode2.type === NodeType.Element) {
|
|
953
|
+
recordChild = recordChild && !serializedNode2.needBlock;
|
|
954
|
+
delete serializedNode2.needBlock;
|
|
955
|
+
const shadowRoot = n.shadowRoot;
|
|
956
|
+
if (shadowRoot && isNativeShadowDom(shadowRoot))
|
|
957
|
+
serializedNode2.isShadowHost = true;
|
|
958
|
+
}
|
|
959
|
+
if ((serializedNode2.type === NodeType.Document || serializedNode2.type === NodeType.Element) && recordChild) {
|
|
960
|
+
if (slimDOMOptions.headWhitespace && serializedNode2.type === NodeType.Element && serializedNode2.tagName === "head") {
|
|
961
|
+
preserveWhiteSpace = false;
|
|
962
|
+
}
|
|
963
|
+
const bypassOptions = {
|
|
964
|
+
doc,
|
|
965
|
+
mirror,
|
|
966
|
+
blockClass,
|
|
967
|
+
blockSelector,
|
|
968
|
+
needsMask,
|
|
969
|
+
maskTextClass,
|
|
970
|
+
maskTextSelector,
|
|
971
|
+
skipChild,
|
|
972
|
+
inlineStylesheet,
|
|
973
|
+
maskInputOptions,
|
|
974
|
+
maskTextFn,
|
|
975
|
+
maskInputFn,
|
|
976
|
+
slimDOMOptions,
|
|
977
|
+
dataURLOptions,
|
|
978
|
+
inlineImages,
|
|
979
|
+
recordCanvas,
|
|
980
|
+
preserveWhiteSpace,
|
|
981
|
+
onSerialize,
|
|
982
|
+
onIframeLoad,
|
|
983
|
+
iframeLoadTimeout,
|
|
984
|
+
onStylesheetLoad,
|
|
985
|
+
stylesheetLoadTimeout,
|
|
986
|
+
keepIframeSrcFn
|
|
987
|
+
};
|
|
988
|
+
if (serializedNode2.type === NodeType.Element && serializedNode2.tagName === "textarea" && serializedNode2.attributes.value !== undefined)
|
|
989
|
+
;
|
|
990
|
+
else {
|
|
991
|
+
for (const childN of Array.from(n.childNodes)) {
|
|
992
|
+
const serializedChildNode = serializeNodeWithId(childN, bypassOptions);
|
|
993
|
+
if (serializedChildNode) {
|
|
994
|
+
serializedNode2.childNodes.push(serializedChildNode);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
if (isElement(n) && n.shadowRoot) {
|
|
999
|
+
for (const childN of Array.from(n.shadowRoot.childNodes)) {
|
|
1000
|
+
const serializedChildNode = serializeNodeWithId(childN, bypassOptions);
|
|
1001
|
+
if (serializedChildNode) {
|
|
1002
|
+
isNativeShadowDom(n.shadowRoot) && (serializedChildNode.isShadow = true);
|
|
1003
|
+
serializedNode2.childNodes.push(serializedChildNode);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
if (n.parentNode && isShadowRoot(n.parentNode) && isNativeShadowDom(n.parentNode)) {
|
|
1009
|
+
serializedNode2.isShadow = true;
|
|
1010
|
+
}
|
|
1011
|
+
if (serializedNode2.type === NodeType.Element && serializedNode2.tagName === "iframe") {
|
|
1012
|
+
onceIframeLoaded(
|
|
1013
|
+
n,
|
|
1014
|
+
() => {
|
|
1015
|
+
const iframeDoc = n.contentDocument;
|
|
1016
|
+
if (iframeDoc && onIframeLoad) {
|
|
1017
|
+
const serializedIframeNode = serializeNodeWithId(iframeDoc, {
|
|
1018
|
+
doc: iframeDoc,
|
|
1019
|
+
mirror,
|
|
1020
|
+
blockClass,
|
|
1021
|
+
blockSelector,
|
|
1022
|
+
needsMask,
|
|
1023
|
+
maskTextClass,
|
|
1024
|
+
maskTextSelector,
|
|
1025
|
+
skipChild: false,
|
|
1026
|
+
inlineStylesheet,
|
|
1027
|
+
maskInputOptions,
|
|
1028
|
+
maskTextFn,
|
|
1029
|
+
maskInputFn,
|
|
1030
|
+
slimDOMOptions,
|
|
1031
|
+
dataURLOptions,
|
|
1032
|
+
inlineImages,
|
|
1033
|
+
recordCanvas,
|
|
1034
|
+
preserveWhiteSpace,
|
|
1035
|
+
onSerialize,
|
|
1036
|
+
onIframeLoad,
|
|
1037
|
+
iframeLoadTimeout,
|
|
1038
|
+
onStylesheetLoad,
|
|
1039
|
+
stylesheetLoadTimeout,
|
|
1040
|
+
keepIframeSrcFn
|
|
1041
|
+
});
|
|
1042
|
+
if (serializedIframeNode) {
|
|
1043
|
+
onIframeLoad(
|
|
1044
|
+
n,
|
|
1045
|
+
serializedIframeNode
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
},
|
|
1050
|
+
iframeLoadTimeout
|
|
1051
|
+
);
|
|
1052
|
+
}
|
|
1053
|
+
if (serializedNode2.type === NodeType.Element && serializedNode2.tagName === "link" && typeof serializedNode2.attributes.rel === "string" && (serializedNode2.attributes.rel === "stylesheet" || serializedNode2.attributes.rel === "preload" && typeof serializedNode2.attributes.href === "string" && extractFileExtension(serializedNode2.attributes.href) === "css")) {
|
|
1054
|
+
onceStylesheetLoaded(
|
|
1055
|
+
n,
|
|
1056
|
+
() => {
|
|
1057
|
+
if (onStylesheetLoad) {
|
|
1058
|
+
const serializedLinkNode = serializeNodeWithId(n, {
|
|
1059
|
+
doc,
|
|
1060
|
+
mirror,
|
|
1061
|
+
blockClass,
|
|
1062
|
+
blockSelector,
|
|
1063
|
+
needsMask,
|
|
1064
|
+
maskTextClass,
|
|
1065
|
+
maskTextSelector,
|
|
1066
|
+
skipChild: false,
|
|
1067
|
+
inlineStylesheet,
|
|
1068
|
+
maskInputOptions,
|
|
1069
|
+
maskTextFn,
|
|
1070
|
+
maskInputFn,
|
|
1071
|
+
slimDOMOptions,
|
|
1072
|
+
dataURLOptions,
|
|
1073
|
+
inlineImages,
|
|
1074
|
+
recordCanvas,
|
|
1075
|
+
preserveWhiteSpace,
|
|
1076
|
+
onSerialize,
|
|
1077
|
+
onIframeLoad,
|
|
1078
|
+
iframeLoadTimeout,
|
|
1079
|
+
onStylesheetLoad,
|
|
1080
|
+
stylesheetLoadTimeout,
|
|
1081
|
+
keepIframeSrcFn
|
|
1082
|
+
});
|
|
1083
|
+
if (serializedLinkNode) {
|
|
1084
|
+
onStylesheetLoad(
|
|
1085
|
+
n,
|
|
1086
|
+
serializedLinkNode
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
},
|
|
1091
|
+
stylesheetLoadTimeout
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
return serializedNode2;
|
|
1095
|
+
}
|
|
1096
|
+
function snapshot(n, options) {
|
|
1097
|
+
const {
|
|
1098
|
+
mirror = new Mirror(),
|
|
1099
|
+
blockClass = "rr-block",
|
|
1100
|
+
blockSelector = null,
|
|
1101
|
+
maskTextClass = "rr-mask",
|
|
1102
|
+
maskTextSelector = null,
|
|
1103
|
+
inlineStylesheet = true,
|
|
1104
|
+
inlineImages = false,
|
|
1105
|
+
recordCanvas = false,
|
|
1106
|
+
maskAllInputs = false,
|
|
1107
|
+
maskTextFn,
|
|
1108
|
+
maskInputFn,
|
|
1109
|
+
slimDOM = false,
|
|
1110
|
+
dataURLOptions,
|
|
1111
|
+
preserveWhiteSpace,
|
|
1112
|
+
onSerialize,
|
|
1113
|
+
onIframeLoad,
|
|
1114
|
+
iframeLoadTimeout,
|
|
1115
|
+
onStylesheetLoad,
|
|
1116
|
+
stylesheetLoadTimeout,
|
|
1117
|
+
keepIframeSrcFn = () => false
|
|
1118
|
+
} = options || {};
|
|
1119
|
+
const maskInputOptions = maskAllInputs === true ? {
|
|
1120
|
+
color: true,
|
|
1121
|
+
date: true,
|
|
1122
|
+
"datetime-local": true,
|
|
1123
|
+
email: true,
|
|
1124
|
+
month: true,
|
|
1125
|
+
number: true,
|
|
1126
|
+
range: true,
|
|
1127
|
+
search: true,
|
|
1128
|
+
tel: true,
|
|
1129
|
+
text: true,
|
|
1130
|
+
time: true,
|
|
1131
|
+
url: true,
|
|
1132
|
+
week: true,
|
|
1133
|
+
textarea: true,
|
|
1134
|
+
select: true,
|
|
1135
|
+
password: true
|
|
1136
|
+
} : maskAllInputs === false ? {
|
|
1137
|
+
password: true
|
|
1138
|
+
} : maskAllInputs;
|
|
1139
|
+
const slimDOMOptions = slimDOM === true || slimDOM === "all" ? (
|
|
1140
|
+
// if true: set of sensible options that should not throw away any information
|
|
1141
|
+
{
|
|
1142
|
+
script: true,
|
|
1143
|
+
comment: true,
|
|
1144
|
+
headFavicon: true,
|
|
1145
|
+
headWhitespace: true,
|
|
1146
|
+
headMetaDescKeywords: slimDOM === "all",
|
|
1147
|
+
// destructive
|
|
1148
|
+
headMetaSocial: true,
|
|
1149
|
+
headMetaRobots: true,
|
|
1150
|
+
headMetaHttpEquiv: true,
|
|
1151
|
+
headMetaAuthorship: true,
|
|
1152
|
+
headMetaVerification: true
|
|
1153
|
+
}
|
|
1154
|
+
) : slimDOM === false ? {} : slimDOM;
|
|
1155
|
+
return serializeNodeWithId(n, {
|
|
1156
|
+
doc: n,
|
|
1157
|
+
mirror,
|
|
1158
|
+
blockClass,
|
|
1159
|
+
blockSelector,
|
|
1160
|
+
maskTextClass,
|
|
1161
|
+
maskTextSelector,
|
|
1162
|
+
skipChild: false,
|
|
1163
|
+
inlineStylesheet,
|
|
1164
|
+
maskInputOptions,
|
|
1165
|
+
maskTextFn,
|
|
1166
|
+
maskInputFn,
|
|
1167
|
+
slimDOMOptions,
|
|
1168
|
+
dataURLOptions,
|
|
1169
|
+
inlineImages,
|
|
1170
|
+
recordCanvas,
|
|
1171
|
+
preserveWhiteSpace,
|
|
1172
|
+
onSerialize,
|
|
1173
|
+
onIframeLoad,
|
|
1174
|
+
iframeLoadTimeout,
|
|
1175
|
+
onStylesheetLoad,
|
|
1176
|
+
stylesheetLoadTimeout,
|
|
1177
|
+
keepIframeSrcFn,
|
|
1178
|
+
newlyAddedElement: false
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// @ts-nocheck
|
|
1183
|
+
function getWorkerString() {
|
|
1184
|
+
var _this = this;
|
|
1185
|
+
var MAX_CHUNK_SIZE = 1024 * 1024; //1MB
|
|
1186
|
+
var ERROR_MESSAGE = 'Coralogix Browser SDK - Error from session recording worker:\n';
|
|
1187
|
+
importScriptWithFallback('https://cdn.rum-ingress-coralogix.com/coralogix/browser/latest/pako_deflate.es5.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/pako/2.1.0/pako_deflate.es5.min.js');
|
|
1188
|
+
self.onmessage = function (_a) {
|
|
1189
|
+
var data = _a.data;
|
|
1190
|
+
if (!_this.pako) {
|
|
1191
|
+
console.warn('Coralogix Browser SDK - Web worker not created due to missing pako library');
|
|
1192
|
+
self.postMessage({
|
|
1193
|
+
event: 'stopRecording',
|
|
1194
|
+
});
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
var recordsData;
|
|
1198
|
+
var isScreenshot = !!data.screenshotId;
|
|
1199
|
+
if (isScreenshot) {
|
|
1200
|
+
recordsData = JSON.stringify(data.records);
|
|
1201
|
+
}
|
|
1202
|
+
else {
|
|
1203
|
+
recordsData = omitSquareBrackets(JSON.stringify(data.records));
|
|
1204
|
+
}
|
|
1205
|
+
var sessionId = data.sessionId;
|
|
1206
|
+
var sessionCreationDate = data.sessionCreationDate;
|
|
1207
|
+
var screenshotId = data.screenshotId;
|
|
1208
|
+
var gzipData = _this.pako.gzip(recordsData);
|
|
1209
|
+
var gzipSize = gzipData.byteLength;
|
|
1210
|
+
if (gzipSize >= MAX_CHUNK_SIZE) {
|
|
1211
|
+
var totalChunks = Math.ceil(gzipSize / MAX_CHUNK_SIZE);
|
|
1212
|
+
for (var i = 0; i < totalChunks; i++) {
|
|
1213
|
+
var start = i * MAX_CHUNK_SIZE;
|
|
1214
|
+
var end = (i + 1) * MAX_CHUNK_SIZE;
|
|
1215
|
+
var chunk = gzipData.slice(start, end);
|
|
1216
|
+
createBlobAndSend(sessionId, sessionCreationDate, chunk, i, totalChunks - 1, screenshotId, 'splitRecordData');
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
else {
|
|
1220
|
+
createBlobAndSend(sessionId, sessionCreationDate, gzipData, undefined, undefined, screenshotId);
|
|
1221
|
+
}
|
|
1222
|
+
};
|
|
1223
|
+
self.onerror = function (err) {
|
|
1224
|
+
console.warn(ERROR_MESSAGE, err);
|
|
1225
|
+
self.postMessage({
|
|
1226
|
+
event: 'stopRecording',
|
|
1227
|
+
});
|
|
1228
|
+
};
|
|
1229
|
+
function omitSquareBrackets(json) {
|
|
1230
|
+
return json.slice(1, -1);
|
|
1231
|
+
}
|
|
1232
|
+
function importScriptWithFallback(url, fallbackUrl) {
|
|
1233
|
+
try {
|
|
1234
|
+
importScripts(url);
|
|
1235
|
+
}
|
|
1236
|
+
catch (err) {
|
|
1237
|
+
try {
|
|
1238
|
+
importScripts(fallbackUrl);
|
|
1239
|
+
}
|
|
1240
|
+
catch (fallbackErr) {
|
|
1241
|
+
self.postMessage({ event: 'stopRecording' });
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
function createBlobAndSend(sessionId, sessionCreationDate, gzipData, chunkIndex, totalChunks, screenshotId, event) {
|
|
1246
|
+
if (event === undefined) { event = 'sendRecordData'; }
|
|
1247
|
+
var blob = new Blob([gzipData], {
|
|
1248
|
+
type: 'application/octet-stream',
|
|
1249
|
+
});
|
|
1250
|
+
self.postMessage({
|
|
1251
|
+
sessionId: sessionId,
|
|
1252
|
+
sessionCreationDate: sessionCreationDate,
|
|
1253
|
+
gzipBlob: blob,
|
|
1254
|
+
chunkIndex: chunkIndex,
|
|
1255
|
+
totalChunks: totalChunks,
|
|
1256
|
+
screenshotId: screenshotId,
|
|
1257
|
+
event: event,
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
var WorkerManager = /** @class */ (function () {
|
|
1263
|
+
function WorkerManager() {
|
|
1264
|
+
}
|
|
1265
|
+
WorkerManager.prototype.loadAndCreateWorker = function (workerUrl) {
|
|
1266
|
+
return __awaiter(this, undefined, undefined, function () {
|
|
1267
|
+
var workerCode, _a, workerBlob, blobUrl, error_1;
|
|
1268
|
+
return __generator(this, function (_b) {
|
|
1269
|
+
switch (_b.label) {
|
|
1270
|
+
case 0:
|
|
1271
|
+
_b.trys.push([0, 4, , 5]);
|
|
1272
|
+
if (!workerUrl) return [3 /*break*/, 2];
|
|
1273
|
+
return [4 /*yield*/, this.loadWorkerScript(workerUrl)];
|
|
1274
|
+
case 1:
|
|
1275
|
+
_a = _b.sent();
|
|
1276
|
+
return [3 /*break*/, 3];
|
|
1277
|
+
case 2:
|
|
1278
|
+
_a = "(".concat(getWorkerString.toString(), ")()");
|
|
1279
|
+
_b.label = 3;
|
|
1280
|
+
case 3:
|
|
1281
|
+
workerCode = _a;
|
|
1282
|
+
workerBlob = new Blob([workerCode], {
|
|
1283
|
+
type: 'application/javascript',
|
|
1284
|
+
});
|
|
1285
|
+
blobUrl = URL.createObjectURL(workerBlob);
|
|
1286
|
+
return [2 /*return*/, new Worker(blobUrl)];
|
|
1287
|
+
case 4:
|
|
1288
|
+
error_1 = _b.sent();
|
|
1289
|
+
console.warn("CoralogixRum: Error creating worker ".concat(error_1));
|
|
1290
|
+
return [2 /*return*/, undefined];
|
|
1291
|
+
case 5: return [2 /*return*/];
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
});
|
|
1295
|
+
};
|
|
1296
|
+
WorkerManager.prototype.loadWorkerScript = function (url) {
|
|
1297
|
+
return __awaiter(this, undefined, undefined, function () {
|
|
1298
|
+
var response;
|
|
1299
|
+
return __generator(this, function (_a) {
|
|
1300
|
+
switch (_a.label) {
|
|
1301
|
+
case 0:
|
|
1302
|
+
_a.trys.push([0, 3, , 4]);
|
|
1303
|
+
return [4 /*yield*/, fetch(this.getFullWorkerUrl(url))];
|
|
1304
|
+
case 1:
|
|
1305
|
+
response = _a.sent();
|
|
1306
|
+
if (!response.ok) {
|
|
1307
|
+
console.warn("CoralogixRum: Error fetching custom web worker");
|
|
1308
|
+
return [2 /*return*/, ''];
|
|
1309
|
+
}
|
|
1310
|
+
return [4 /*yield*/, response.text()];
|
|
1311
|
+
case 2: return [2 /*return*/, _a.sent()];
|
|
1312
|
+
case 3:
|
|
1313
|
+
_a.sent();
|
|
1314
|
+
console.warn("CoralogixRum: Error fetching custom web worker");
|
|
1315
|
+
return [2 /*return*/, ''];
|
|
1316
|
+
case 4: return [2 /*return*/];
|
|
1317
|
+
}
|
|
1318
|
+
});
|
|
1319
|
+
});
|
|
1320
|
+
};
|
|
1321
|
+
WorkerManager.prototype.getFullWorkerUrl = function (workerUrl) {
|
|
1322
|
+
if (workerUrl.startsWith('http://') || workerUrl.startsWith('https://')) {
|
|
1323
|
+
return workerUrl;
|
|
1324
|
+
}
|
|
1325
|
+
return "".concat(CxGlobal.location.origin).concat(workerUrl);
|
|
1326
|
+
};
|
|
1327
|
+
return WorkerManager;
|
|
1328
|
+
}());
|
|
1329
|
+
|
|
1330
|
+
var SessionRecorder = /** @class */ (function () {
|
|
1331
|
+
function SessionRecorder(sessionManager, recordConfig) {
|
|
1332
|
+
var _this = this;
|
|
1333
|
+
var _a;
|
|
1334
|
+
this.isAutoStartRecording = false;
|
|
1335
|
+
this.onlySessionWithErrorMode = false;
|
|
1336
|
+
this.recordEvents = [];
|
|
1337
|
+
this.recordEventsForSessionWithError = [[], []];
|
|
1338
|
+
this.segmentIndexCounter = {};
|
|
1339
|
+
this.hasRecording = false;
|
|
1340
|
+
this.hasScreenshot = false;
|
|
1341
|
+
this.recordingStopped = false;
|
|
1342
|
+
this.batchTimeDelay = BATCH_TIME_DELAY;
|
|
1343
|
+
this.isErrorOccurred = false;
|
|
1344
|
+
this.debugMode = !!((_a = getSdkConfig()) === null || _a === undefined ? undefined : _a.debug);
|
|
1345
|
+
this._recordingStopDueToTimeout = false;
|
|
1346
|
+
this.handleRecordEvent = function (event, isCheckout) {
|
|
1347
|
+
if (!_this.recordingStopped) {
|
|
1348
|
+
if (_this.onlySessionWithErrorMode) {
|
|
1349
|
+
_this.handleRecordEventForSessionWithError(event, isCheckout);
|
|
1350
|
+
}
|
|
1351
|
+
else {
|
|
1352
|
+
_this.recordEvents.push(event);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
this.prepareRecordEventsBeforeSend = function () {
|
|
1357
|
+
if (_this.onlySessionWithErrorMode) {
|
|
1358
|
+
_this.prepareRecordEventsForSessionWithError();
|
|
1359
|
+
}
|
|
1360
|
+
else {
|
|
1361
|
+
if (!_this.recordEvents.length) {
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
_this.compressRecordData(_this.recordEvents);
|
|
1365
|
+
_this.resetBatching();
|
|
1366
|
+
}
|
|
1367
|
+
};
|
|
1368
|
+
this.sendRecordEvents = function (workerData, shouldSplit) {
|
|
1369
|
+
var formData = new FormData();
|
|
1370
|
+
var metaData = _this.getMetadata(workerData, shouldSplit);
|
|
1371
|
+
formData.append('chunk', workerData.gzipBlob);
|
|
1372
|
+
formData.append('metaData', JSON.stringify(metaData));
|
|
1373
|
+
var sendRecordRequest = function () { return __awaiter(_this, undefined, undefined, function () {
|
|
1374
|
+
var response, _a;
|
|
1375
|
+
var _b;
|
|
1376
|
+
return __generator(this, function (_c) {
|
|
1377
|
+
switch (_c.label) {
|
|
1378
|
+
case 0:
|
|
1379
|
+
_c.trys.push([0, 4, , 5]);
|
|
1380
|
+
if (!!this.isErrorOccurred) return [3 /*break*/, 2];
|
|
1381
|
+
return [4 /*yield*/, ((_b = this.request) === null || _b === undefined ? undefined : _b.send(formData))];
|
|
1382
|
+
case 1:
|
|
1383
|
+
_a = _c.sent();
|
|
1384
|
+
return [3 /*break*/, 3];
|
|
1385
|
+
case 2:
|
|
1386
|
+
_a = undefined;
|
|
1387
|
+
_c.label = 3;
|
|
1388
|
+
case 3:
|
|
1389
|
+
response = _a;
|
|
1390
|
+
this.handleSessionRecordingResponse(response);
|
|
1391
|
+
return [3 /*break*/, 5];
|
|
1392
|
+
case 4:
|
|
1393
|
+
_c.sent();
|
|
1394
|
+
this.handleSessionRecordingResponse(undefined);
|
|
1395
|
+
return [3 /*break*/, 5];
|
|
1396
|
+
case 5: return [2 /*return*/];
|
|
1397
|
+
}
|
|
1398
|
+
});
|
|
1399
|
+
}); };
|
|
1400
|
+
if (shouldSplit) {
|
|
1401
|
+
_this.batchTimeout = setTimeout(sendRecordRequest, _this.batchTimeDelay);
|
|
1402
|
+
_this.batchTimeDelay += BATCH_TIME_DELAY;
|
|
1403
|
+
}
|
|
1404
|
+
else {
|
|
1405
|
+
sendRecordRequest();
|
|
1406
|
+
_this.batchTimeDelay = BATCH_TIME_DELAY;
|
|
1407
|
+
}
|
|
1408
|
+
};
|
|
1409
|
+
CxGlobal[SESSION_RECORDER_KEY] = this;
|
|
1410
|
+
this.sessionManager = sessionManager;
|
|
1411
|
+
var onlySessionWithErrorMode = sessionManager.onlySessionWithErrorMode, maxRecordTimeForSessionWithError = sessionManager.maxRecordTimeForSessionWithError;
|
|
1412
|
+
var maxMutations = recordConfig.maxMutations, autoStartSessionRecording = recordConfig.autoStartSessionRecording, workerUrl = recordConfig.workerUrl;
|
|
1413
|
+
this.onlySessionWithErrorMode = onlySessionWithErrorMode;
|
|
1414
|
+
this.maxRecordTimeForSessionWithError = maxRecordTimeForSessionWithError;
|
|
1415
|
+
this.isAutoStartRecording = autoStartSessionRecording;
|
|
1416
|
+
this.maxMutations = maxMutations !== null && maxMutations !== undefined ? maxMutations : MAX_MUTATIONS_FOR_SESSION_RECORDING;
|
|
1417
|
+
this.recordConfig = this.prepareRecordConfig(recordConfig);
|
|
1418
|
+
if (CxGlobal.Worker) {
|
|
1419
|
+
this.workerManager = new WorkerManager();
|
|
1420
|
+
this.initializeSessionWorker(workerUrl);
|
|
1421
|
+
}
|
|
1422
|
+
else {
|
|
1423
|
+
if (this.debugMode) {
|
|
1424
|
+
console.warn(SESSION_RECORDING_DEFAULT_ERROR_MESSAGE);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
SessionRecorder.prototype.getSessionHasScreenshot = function () {
|
|
1429
|
+
return this.hasScreenshot;
|
|
1430
|
+
};
|
|
1431
|
+
SessionRecorder.prototype.getSessionHasRecording = function () {
|
|
1432
|
+
var _a;
|
|
1433
|
+
return (this.hasRecording &&
|
|
1434
|
+
!!this.segmentIndexCounter[(_a = this.sessionManager.getActiveSession()) === null || _a === undefined ? undefined : _a.sessionId]);
|
|
1435
|
+
};
|
|
1436
|
+
SessionRecorder.prototype.updateSegmentIndexCounter = function (segmentIndexCounter) {
|
|
1437
|
+
this.segmentIndexCounter = segmentIndexCounter;
|
|
1438
|
+
};
|
|
1439
|
+
SessionRecorder.prototype.getIsAutoStartRecording = function () {
|
|
1440
|
+
return this.isAutoStartRecording;
|
|
1441
|
+
};
|
|
1442
|
+
Object.defineProperty(SessionRecorder.prototype, "recordingStopDueToTimeout", {
|
|
1443
|
+
get: function () {
|
|
1444
|
+
return this._recordingStopDueToTimeout;
|
|
1445
|
+
},
|
|
1446
|
+
set: function (value) {
|
|
1447
|
+
this._recordingStopDueToTimeout = value;
|
|
1448
|
+
},
|
|
1449
|
+
enumerable: false,
|
|
1450
|
+
configurable: true
|
|
1451
|
+
});
|
|
1452
|
+
SessionRecorder.prototype.startRecording = function () {
|
|
1453
|
+
return __awaiter(this, undefined, undefined, function () {
|
|
1454
|
+
return __generator(this, function (_a) {
|
|
1455
|
+
switch (_a.label) {
|
|
1456
|
+
case 0: return [4 /*yield*/, this.isWorkerReady];
|
|
1457
|
+
case 1:
|
|
1458
|
+
_a.sent();
|
|
1459
|
+
if (!this.sessionWorker || this.recordRef) {
|
|
1460
|
+
return [2 /*return*/];
|
|
1461
|
+
}
|
|
1462
|
+
if (this.debugMode) {
|
|
1463
|
+
console.debug('Coralogix Browser SDK - Session recording started');
|
|
1464
|
+
}
|
|
1465
|
+
this.startMutationObserver();
|
|
1466
|
+
this.resetBatching();
|
|
1467
|
+
this.hasRecording = true;
|
|
1468
|
+
this.recordingStopped = false;
|
|
1469
|
+
this.isErrorOccurred = false;
|
|
1470
|
+
this.recordingStopDueToTimeout = false;
|
|
1471
|
+
this.recordRef = record(this.recordConfig);
|
|
1472
|
+
this.startBatchingRecords();
|
|
1473
|
+
return [2 /*return*/];
|
|
1474
|
+
}
|
|
1475
|
+
});
|
|
1476
|
+
});
|
|
1477
|
+
};
|
|
1478
|
+
SessionRecorder.prototype.screenshot = function (id) {
|
|
1479
|
+
this.hasScreenshot = true;
|
|
1480
|
+
var _a = this.sessionManager.getActiveSession() || {}, sessionId = _a.sessionId, sessionCreationDate = _a.sessionCreationDate;
|
|
1481
|
+
var snapshotRecords = snapshot(document, this.recordConfig);
|
|
1482
|
+
if (snapshotRecords) {
|
|
1483
|
+
this.sessionWorker.postMessage({
|
|
1484
|
+
event: 'sendRecordData',
|
|
1485
|
+
records: snapshotRecords,
|
|
1486
|
+
sessionId: sessionId,
|
|
1487
|
+
screenshotId: id,
|
|
1488
|
+
sessionCreationDate: sessionCreationDate,
|
|
1489
|
+
});
|
|
1490
|
+
}
|
|
1491
|
+
};
|
|
1492
|
+
SessionRecorder.prototype.stopRecording = function () {
|
|
1493
|
+
if (!this.recordRef) {
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
if (this.debugMode) {
|
|
1497
|
+
console.debug('Coralogix Browser SDK - Session recording stopped');
|
|
1498
|
+
}
|
|
1499
|
+
this.recordRef();
|
|
1500
|
+
this.recordRef = undefined;
|
|
1501
|
+
this.recordingStopped = true;
|
|
1502
|
+
this.hasRecording = false;
|
|
1503
|
+
this.prepareRecordEventsBeforeSend();
|
|
1504
|
+
this.clearIntervals();
|
|
1505
|
+
this.stopMutationObserver();
|
|
1506
|
+
};
|
|
1507
|
+
SessionRecorder.prototype.stopMutationObserver = function () {
|
|
1508
|
+
var _a;
|
|
1509
|
+
(_a = this.mutationObserver) === null || _a === undefined ? undefined : _a.disconnect();
|
|
1510
|
+
};
|
|
1511
|
+
SessionRecorder.prototype.startMutationObserver = function () {
|
|
1512
|
+
var _this = this;
|
|
1513
|
+
this.stopMutationObserver();
|
|
1514
|
+
this.mutationObserver = new MutationObserver(function (mutations) {
|
|
1515
|
+
if (mutations.length > _this.maxMutations) {
|
|
1516
|
+
var message = "Coralogix Browser SDK - Recording stopped due to too many mutations ".concat(mutations.length);
|
|
1517
|
+
console.warn(message);
|
|
1518
|
+
reportInternalEvent('recording-stop', message);
|
|
1519
|
+
_this.stopRecording();
|
|
1520
|
+
}
|
|
1521
|
+
});
|
|
1522
|
+
this.mutationObserver.observe(document, {
|
|
1523
|
+
attributes: false,
|
|
1524
|
+
attributeOldValue: false,
|
|
1525
|
+
characterData: false,
|
|
1526
|
+
characterDataOldValue: false,
|
|
1527
|
+
childList: true,
|
|
1528
|
+
subtree: true,
|
|
1529
|
+
});
|
|
1530
|
+
};
|
|
1531
|
+
SessionRecorder.prototype.clearIntervals = function () {
|
|
1532
|
+
if (this.batchingTimeInterval) {
|
|
1533
|
+
clearInterval(this.batchingTimeInterval);
|
|
1534
|
+
}
|
|
1535
|
+
};
|
|
1536
|
+
SessionRecorder.prototype.prepareRecordConfig = function (recordConfig) {
|
|
1537
|
+
var _a;
|
|
1538
|
+
var _b = recordConfig || {}, excludeDOMOptions = _b.excludeDOMOptions, recordConsoleEvents = _b.recordConsoleEvents;
|
|
1539
|
+
// @ts-ignore
|
|
1540
|
+
this.recordConfig = __assign(__assign({}, recordConfig), { emit: this.handleRecordEvent, checkoutEveryNms: this.onlySessionWithErrorMode
|
|
1541
|
+
? this.maxRecordTimeForSessionWithError
|
|
1542
|
+
: undefined, slimDOMOptions: __assign(__assign({}, excludeDOMOptions), { script: (_a = excludeDOMOptions === null || excludeDOMOptions === undefined ? undefined : excludeDOMOptions.script) !== null && _a !== undefined ? _a : true }), plugins: recordConsoleEvents ? [getRecordConsolePlugin()] : [] });
|
|
1543
|
+
return this.recordConfig;
|
|
1544
|
+
};
|
|
1545
|
+
SessionRecorder.prototype.handleRecordEventForSessionWithError = function (event, isCheckout) {
|
|
1546
|
+
var shouldIgnoreEvent = this.sessionManager.sessionHasError &&
|
|
1547
|
+
!!isCheckout &&
|
|
1548
|
+
event.type === EventType.FullSnapshot;
|
|
1549
|
+
if (shouldIgnoreEvent) {
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
var shouldAddNewSnapshot = !!isCheckout && event.type === EventType.Meta;
|
|
1553
|
+
// Add new snapshot to the cache
|
|
1554
|
+
if (shouldAddNewSnapshot) {
|
|
1555
|
+
this.recordEventsForSessionWithError.push([]);
|
|
1556
|
+
}
|
|
1557
|
+
var _a = this.recordEventsForSessionWithError, length = _a.length, _b = length - 1, lastEvents = _a[_b];
|
|
1558
|
+
lastEvents.push(event);
|
|
1559
|
+
};
|
|
1560
|
+
SessionRecorder.prototype.prepareRecordEventsForSessionWithError = function () {
|
|
1561
|
+
var _a = this.recordEventsForSessionWithError, length = _a.length, _b = length - 2, beforeLast = _a[_b], _c = length - 1, last = _a[_c];
|
|
1562
|
+
if (this.sessionManager.sessionHasError) {
|
|
1563
|
+
var lastEvents = beforeLast.concat(last);
|
|
1564
|
+
if (!lastEvents.length) {
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
this.compressRecordData(lastEvents);
|
|
1568
|
+
this.resetBatching();
|
|
1569
|
+
}
|
|
1570
|
+
else {
|
|
1571
|
+
// If no error occurred, we need to keep only the last 2 snapshots
|
|
1572
|
+
this.recordEventsForSessionWithError = [beforeLast, last];
|
|
1573
|
+
}
|
|
1574
|
+
};
|
|
1575
|
+
SessionRecorder.prototype.compressRecordData = function (recordEvents) {
|
|
1576
|
+
var _a = this.sessionManager.getActiveSession() || {}, sessionId = _a.sessionId, sessionCreationDate = _a.sessionCreationDate;
|
|
1577
|
+
this.sessionWorker.postMessage({
|
|
1578
|
+
event: 'compressRecordData',
|
|
1579
|
+
records: recordEvents,
|
|
1580
|
+
sessionId: sessionId,
|
|
1581
|
+
sessionCreationDate: sessionCreationDate,
|
|
1582
|
+
});
|
|
1583
|
+
};
|
|
1584
|
+
SessionRecorder.prototype.registerToWorkerMessages = function () {
|
|
1585
|
+
var _this = this;
|
|
1586
|
+
this.sessionWorker.onmessage = function (_a) {
|
|
1587
|
+
var data = _a.data;
|
|
1588
|
+
switch (data.event) {
|
|
1589
|
+
case 'sendRecordData':
|
|
1590
|
+
_this.sendRecordEvents(data, false);
|
|
1591
|
+
break;
|
|
1592
|
+
case 'splitRecordData':
|
|
1593
|
+
_this.sendRecordEvents(data, true);
|
|
1594
|
+
break;
|
|
1595
|
+
case 'stopRecording':
|
|
1596
|
+
_this.stopRecording();
|
|
1597
|
+
break;
|
|
1598
|
+
}
|
|
1599
|
+
};
|
|
1600
|
+
};
|
|
1601
|
+
SessionRecorder.prototype.resetBatching = function () {
|
|
1602
|
+
if (this.onlySessionWithErrorMode) {
|
|
1603
|
+
this.recordEventsForSessionWithError = [[], []];
|
|
1604
|
+
}
|
|
1605
|
+
else {
|
|
1606
|
+
this.recordEvents = [];
|
|
1607
|
+
}
|
|
1608
|
+
};
|
|
1609
|
+
SessionRecorder.prototype.getMetadata = function (workerData, shouldSplit) {
|
|
1610
|
+
var sessionId = workerData.sessionId, sessionCreationDate = workerData.sessionCreationDate, screenshotId = workerData.screenshotId, gzipBlob = workerData.gzipBlob, chunkIndex = workerData.chunkIndex, totalChunks = workerData.totalChunks;
|
|
1611
|
+
var segmentIndex = 0;
|
|
1612
|
+
var application = getSdkConfig().application;
|
|
1613
|
+
var isScreenshot = !!screenshotId;
|
|
1614
|
+
if (!isScreenshot) {
|
|
1615
|
+
if (!this.segmentIndexCounter[sessionId]) {
|
|
1616
|
+
this.segmentIndexCounter[sessionId] = 0;
|
|
1617
|
+
}
|
|
1618
|
+
if (shouldSplit) {
|
|
1619
|
+
segmentIndex =
|
|
1620
|
+
chunkIndex === totalChunks
|
|
1621
|
+
? this.segmentIndexCounter[sessionId]++
|
|
1622
|
+
: this.segmentIndexCounter[sessionId];
|
|
1623
|
+
}
|
|
1624
|
+
else {
|
|
1625
|
+
segmentIndex = this.segmentIndexCounter[sessionId]++;
|
|
1626
|
+
}
|
|
1627
|
+
sessionStorage.setItem(SESSION_RECORDER_SEGMENTS_MAP, JSON.stringify(this.segmentIndexCounter));
|
|
1628
|
+
}
|
|
1629
|
+
var metaData = {
|
|
1630
|
+
segmentIndex: segmentIndex,
|
|
1631
|
+
segmentSize: gzipBlob.size,
|
|
1632
|
+
segmentTimestamp: getNowTime(),
|
|
1633
|
+
sessionCreationDate: sessionCreationDate,
|
|
1634
|
+
sessionId: sessionId,
|
|
1635
|
+
snapshotId: screenshotId,
|
|
1636
|
+
application: application,
|
|
1637
|
+
subIndex: chunkIndex !== null && chunkIndex !== undefined ? chunkIndex : -1,
|
|
1638
|
+
};
|
|
1639
|
+
return metaData;
|
|
1640
|
+
};
|
|
1641
|
+
SessionRecorder.prototype.handleSessionRecordingResponse = function (response) {
|
|
1642
|
+
if (!(response === null || response === undefined ? undefined : response.ok) && !this.isErrorOccurred) {
|
|
1643
|
+
console.warn(SESSION_RECORDING_NETWORK_ERR0R_MESSAGE);
|
|
1644
|
+
this.isErrorOccurred = true;
|
|
1645
|
+
this.stopRecording();
|
|
1646
|
+
if (this.batchTimeout) {
|
|
1647
|
+
clearTimeout(this.batchTimeout);
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
else {
|
|
1651
|
+
this.isErrorOccurred = false;
|
|
1652
|
+
}
|
|
1653
|
+
};
|
|
1654
|
+
SessionRecorder.prototype.startBatchingRecords = function () {
|
|
1655
|
+
this.batchingTimeInterval = setInterval(this.prepareRecordEventsBeforeSend, MAX_BATCH_TIME_MS);
|
|
1656
|
+
};
|
|
1657
|
+
SessionRecorder.prototype.initializeSessionWorker = function (workerUrl) {
|
|
1658
|
+
var _this = this;
|
|
1659
|
+
this.isWorkerReady = new Promise(function (resolve, reject) {
|
|
1660
|
+
_this.workerManager
|
|
1661
|
+
.loadAndCreateWorker(workerUrl)
|
|
1662
|
+
.then(function (worker) {
|
|
1663
|
+
_this.sessionWorker = worker;
|
|
1664
|
+
if (_this.isAutoStartRecording) {
|
|
1665
|
+
_this.startRecording();
|
|
1666
|
+
}
|
|
1667
|
+
_this.request = new Request({
|
|
1668
|
+
suffix: SESSION_RECORDING_POSTFIX_URL,
|
|
1669
|
+
headers: SESSION_RECORDING_DEFAULT_HEADERS,
|
|
1670
|
+
});
|
|
1671
|
+
_this.registerToWorkerMessages();
|
|
1672
|
+
resolve(true);
|
|
1673
|
+
})
|
|
1674
|
+
.catch(function (err) {
|
|
1675
|
+
if (_this.debugMode) {
|
|
1676
|
+
console.warn('Coralogix Browser SDK - Web worker not created due to: ', err);
|
|
1677
|
+
}
|
|
1678
|
+
reject(err);
|
|
1679
|
+
});
|
|
1680
|
+
});
|
|
1681
|
+
};
|
|
1682
|
+
return SessionRecorder;
|
|
1683
|
+
}());
|
|
1684
|
+
|
|
1685
|
+
export { SessionRecorder };
|