@lvce-editor/renderer-process 30.57.2 → 30.58.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/dist/rendererProcessMain.js +4138 -4144
- package/dist/sessionReplayWorkerMain.js +947 -12
- package/package.json +1 -1
|
@@ -1,3 +1,714 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
// ../session-replay-worker/src/api/transfer.ts
|
|
8
|
+
var getTransferrables = (value) => {
|
|
9
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10
|
+
const result = /* @__PURE__ */ new Set();
|
|
11
|
+
const visit = (item) => {
|
|
12
|
+
if (!item || typeof item !== "object" || seen.has(item)) return;
|
|
13
|
+
seen.add(item);
|
|
14
|
+
if (Object.prototype.toString.call(item) === "[object ArrayBuffer]") result.add(item);
|
|
15
|
+
else if (ArrayBuffer.isView(item)) visit(item.buffer);
|
|
16
|
+
else if (["MessagePort", "OffscreenCanvas", "ImageBitmap", "AudioData", "VideoFrame", "ReadableStream", "WritableStream", "TransformStream"].some(
|
|
17
|
+
(name) => typeof globalThis[name] === "function" && item instanceof globalThis[name]
|
|
18
|
+
))
|
|
19
|
+
result.add(item);
|
|
20
|
+
else if (Object.prototype.toString.call(item) === "[object Map]") {
|
|
21
|
+
for (const [key, entry] of item) {
|
|
22
|
+
visit(key);
|
|
23
|
+
visit(entry);
|
|
24
|
+
}
|
|
25
|
+
} else if (Object.prototype.toString.call(item) === "[object Set]") {
|
|
26
|
+
for (const entry of item) visit(entry);
|
|
27
|
+
} else for (const entry of Object.values(item)) visit(entry);
|
|
28
|
+
};
|
|
29
|
+
visit(value);
|
|
30
|
+
return [...result];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// ../../node_modules/@lvce-editor/constants/dist/parts/ElementTagMap/ElementTagMap.js
|
|
34
|
+
var ElementTagMap_exports = {};
|
|
35
|
+
__export(ElementTagMap_exports, {
|
|
36
|
+
getElementTag: () => getElementTag
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// ../../node_modules/@lvce-editor/constants/dist/parts/ElementTags/ElementTags.js
|
|
40
|
+
var Audio = "audio";
|
|
41
|
+
var Button = "button";
|
|
42
|
+
var Col = "col";
|
|
43
|
+
var ColGroup = "colgroup";
|
|
44
|
+
var Del = "del";
|
|
45
|
+
var Div = "div";
|
|
46
|
+
var H1 = "h1";
|
|
47
|
+
var H2 = "h2";
|
|
48
|
+
var H3 = "h3";
|
|
49
|
+
var H4 = "h4";
|
|
50
|
+
var H5 = "h5";
|
|
51
|
+
var H6 = "h6";
|
|
52
|
+
var I = "i";
|
|
53
|
+
var Img = "img";
|
|
54
|
+
var Input = "input";
|
|
55
|
+
var Ins = "ins";
|
|
56
|
+
var Kbd = "kbd";
|
|
57
|
+
var Span = "span";
|
|
58
|
+
var Table = "table";
|
|
59
|
+
var TBody = "tbody";
|
|
60
|
+
var Td = "td";
|
|
61
|
+
var Th = "th";
|
|
62
|
+
var THead = "thead";
|
|
63
|
+
var Tr = "tr";
|
|
64
|
+
var Article = "article";
|
|
65
|
+
var Aside = "aside";
|
|
66
|
+
var Footer = "footer";
|
|
67
|
+
var Header = "header";
|
|
68
|
+
var Nav = "nav";
|
|
69
|
+
var Section = "section";
|
|
70
|
+
var Search = "search";
|
|
71
|
+
var Dd = "dd";
|
|
72
|
+
var Dl = "dl";
|
|
73
|
+
var Figcaption = "figcaption";
|
|
74
|
+
var Figure = "figure";
|
|
75
|
+
var Hr = "hr";
|
|
76
|
+
var Li = "li";
|
|
77
|
+
var Ol = "ol";
|
|
78
|
+
var P = "p";
|
|
79
|
+
var Pre = "pre";
|
|
80
|
+
var A = "a";
|
|
81
|
+
var Br = "br";
|
|
82
|
+
var Cite = "cite";
|
|
83
|
+
var Data = "data";
|
|
84
|
+
var Time = "time";
|
|
85
|
+
var Tfoot = "tfoot";
|
|
86
|
+
var Ul = "ul";
|
|
87
|
+
var Video = "video";
|
|
88
|
+
var TextArea = "textarea";
|
|
89
|
+
var Select = "select";
|
|
90
|
+
var Option = "option";
|
|
91
|
+
var Code = "code";
|
|
92
|
+
var Label = "label";
|
|
93
|
+
var Dt = "dt";
|
|
94
|
+
var Iframe = "iframe";
|
|
95
|
+
var Main = "main";
|
|
96
|
+
var Em = "em";
|
|
97
|
+
var Strong = "strong";
|
|
98
|
+
var Style = "style";
|
|
99
|
+
var Html = "html";
|
|
100
|
+
var Head = "head";
|
|
101
|
+
var Title = "title";
|
|
102
|
+
var Meta = "meta";
|
|
103
|
+
var Canvas = "canvas";
|
|
104
|
+
var Circle = "circle";
|
|
105
|
+
var Form = "form";
|
|
106
|
+
var Defs = "defs";
|
|
107
|
+
var Ellipse = "ellipse";
|
|
108
|
+
var G = "g";
|
|
109
|
+
var Line = "line";
|
|
110
|
+
var Path = "path";
|
|
111
|
+
var Polygon = "polygon";
|
|
112
|
+
var Polyline = "polyline";
|
|
113
|
+
var Quote = "quote";
|
|
114
|
+
var BlockQuote = "blockquote";
|
|
115
|
+
var Rect = "rect";
|
|
116
|
+
var Svg = "svg";
|
|
117
|
+
var Use = "use";
|
|
118
|
+
|
|
119
|
+
// ../../node_modules/@lvce-editor/constants/dist/parts/VirtualDomElements/VirtualDomElements.js
|
|
120
|
+
var VirtualDomElements_exports = {};
|
|
121
|
+
__export(VirtualDomElements_exports, {
|
|
122
|
+
A: () => A2,
|
|
123
|
+
Abbr: () => Abbr,
|
|
124
|
+
Article: () => Article2,
|
|
125
|
+
Aside: () => Aside2,
|
|
126
|
+
Audio: () => Audio2,
|
|
127
|
+
BlockQuote: () => BlockQuote2,
|
|
128
|
+
Br: () => Br2,
|
|
129
|
+
Button: () => Button2,
|
|
130
|
+
Canvas: () => Canvas2,
|
|
131
|
+
Circle: () => Circle2,
|
|
132
|
+
Cite: () => Cite2,
|
|
133
|
+
Code: () => Code2,
|
|
134
|
+
Col: () => Col2,
|
|
135
|
+
ColGroup: () => ColGroup2,
|
|
136
|
+
Data: () => Data2,
|
|
137
|
+
Dd: () => Dd2,
|
|
138
|
+
Defs: () => Defs2,
|
|
139
|
+
Del: () => Del2,
|
|
140
|
+
Div: () => Div2,
|
|
141
|
+
Dl: () => Dl2,
|
|
142
|
+
Dt: () => Dt2,
|
|
143
|
+
Ellipse: () => Ellipse2,
|
|
144
|
+
Em: () => Em2,
|
|
145
|
+
Figcaption: () => Figcaption2,
|
|
146
|
+
Figure: () => Figure2,
|
|
147
|
+
Footer: () => Footer2,
|
|
148
|
+
Form: () => Form2,
|
|
149
|
+
G: () => G2,
|
|
150
|
+
H1: () => H12,
|
|
151
|
+
H2: () => H22,
|
|
152
|
+
H3: () => H32,
|
|
153
|
+
H4: () => H42,
|
|
154
|
+
H5: () => H52,
|
|
155
|
+
H6: () => H62,
|
|
156
|
+
Head: () => Head2,
|
|
157
|
+
Header: () => Header2,
|
|
158
|
+
Hr: () => Hr2,
|
|
159
|
+
Html: () => Html2,
|
|
160
|
+
I: () => I2,
|
|
161
|
+
Iframe: () => Iframe2,
|
|
162
|
+
Img: () => Img2,
|
|
163
|
+
Input: () => Input2,
|
|
164
|
+
Ins: () => Ins2,
|
|
165
|
+
Kbd: () => Kbd2,
|
|
166
|
+
Label: () => Label2,
|
|
167
|
+
Li: () => Li2,
|
|
168
|
+
Line: () => Line2,
|
|
169
|
+
Main: () => Main2,
|
|
170
|
+
Meta: () => Meta2,
|
|
171
|
+
Nav: () => Nav2,
|
|
172
|
+
Ol: () => Ol2,
|
|
173
|
+
Option: () => Option2,
|
|
174
|
+
P: () => P2,
|
|
175
|
+
Path: () => Path2,
|
|
176
|
+
Polygon: () => Polygon2,
|
|
177
|
+
Polyline: () => Polyline2,
|
|
178
|
+
Pre: () => Pre2,
|
|
179
|
+
Quote: () => Quote2,
|
|
180
|
+
Rect: () => Rect2,
|
|
181
|
+
Reference: () => Reference,
|
|
182
|
+
Root: () => Root,
|
|
183
|
+
Search: () => Search2,
|
|
184
|
+
Section: () => Section2,
|
|
185
|
+
Select: () => Select2,
|
|
186
|
+
Span: () => Span2,
|
|
187
|
+
Strong: () => Strong2,
|
|
188
|
+
Style: () => Style2,
|
|
189
|
+
Svg: () => Svg2,
|
|
190
|
+
TBody: () => TBody2,
|
|
191
|
+
THead: () => THead2,
|
|
192
|
+
Table: () => Table2,
|
|
193
|
+
Td: () => Td2,
|
|
194
|
+
Text: () => Text,
|
|
195
|
+
TextArea: () => TextArea2,
|
|
196
|
+
Tfoot: () => Tfoot2,
|
|
197
|
+
Th: () => Th2,
|
|
198
|
+
Time: () => Time2,
|
|
199
|
+
Title: () => Title2,
|
|
200
|
+
Tr: () => Tr2,
|
|
201
|
+
Ul: () => Ul2,
|
|
202
|
+
Use: () => Use2,
|
|
203
|
+
Video: () => Video2
|
|
204
|
+
});
|
|
205
|
+
var Audio2 = 0;
|
|
206
|
+
var Button2 = 1;
|
|
207
|
+
var Col2 = 2;
|
|
208
|
+
var ColGroup2 = 3;
|
|
209
|
+
var Div2 = 4;
|
|
210
|
+
var H12 = 5;
|
|
211
|
+
var Input2 = 6;
|
|
212
|
+
var Kbd2 = 7;
|
|
213
|
+
var Span2 = 8;
|
|
214
|
+
var Table2 = 9;
|
|
215
|
+
var TBody2 = 10;
|
|
216
|
+
var Td2 = 11;
|
|
217
|
+
var Text = 12;
|
|
218
|
+
var Th2 = 13;
|
|
219
|
+
var THead2 = 14;
|
|
220
|
+
var Tr2 = 15;
|
|
221
|
+
var I2 = 16;
|
|
222
|
+
var Img2 = 17;
|
|
223
|
+
var Root = 0;
|
|
224
|
+
var Ins2 = 20;
|
|
225
|
+
var Del2 = 21;
|
|
226
|
+
var H22 = 22;
|
|
227
|
+
var H32 = 23;
|
|
228
|
+
var H42 = 24;
|
|
229
|
+
var H52 = 25;
|
|
230
|
+
var H62 = 26;
|
|
231
|
+
var Article2 = 27;
|
|
232
|
+
var Aside2 = 28;
|
|
233
|
+
var Footer2 = 29;
|
|
234
|
+
var Header2 = 30;
|
|
235
|
+
var Nav2 = 40;
|
|
236
|
+
var Section2 = 41;
|
|
237
|
+
var Search2 = 42;
|
|
238
|
+
var Dd2 = 43;
|
|
239
|
+
var Dl2 = 44;
|
|
240
|
+
var Figcaption2 = 45;
|
|
241
|
+
var Figure2 = 46;
|
|
242
|
+
var Hr2 = 47;
|
|
243
|
+
var Li2 = 48;
|
|
244
|
+
var Ol2 = 49;
|
|
245
|
+
var P2 = 50;
|
|
246
|
+
var Pre2 = 51;
|
|
247
|
+
var A2 = 53;
|
|
248
|
+
var Abbr = 54;
|
|
249
|
+
var Br2 = 55;
|
|
250
|
+
var Cite2 = 56;
|
|
251
|
+
var Data2 = 57;
|
|
252
|
+
var Time2 = 58;
|
|
253
|
+
var Tfoot2 = 59;
|
|
254
|
+
var Ul2 = 60;
|
|
255
|
+
var Video2 = 61;
|
|
256
|
+
var TextArea2 = 62;
|
|
257
|
+
var Select2 = 63;
|
|
258
|
+
var Option2 = 64;
|
|
259
|
+
var Code2 = 65;
|
|
260
|
+
var Label2 = 66;
|
|
261
|
+
var Dt2 = 67;
|
|
262
|
+
var Iframe2 = 68;
|
|
263
|
+
var Main2 = 69;
|
|
264
|
+
var Strong2 = 70;
|
|
265
|
+
var Em2 = 71;
|
|
266
|
+
var Style2 = 72;
|
|
267
|
+
var Html2 = 73;
|
|
268
|
+
var Head2 = 74;
|
|
269
|
+
var Title2 = 75;
|
|
270
|
+
var Meta2 = 76;
|
|
271
|
+
var Canvas2 = 77;
|
|
272
|
+
var Form2 = 78;
|
|
273
|
+
var BlockQuote2 = 79;
|
|
274
|
+
var Quote2 = 80;
|
|
275
|
+
var Circle2 = 81;
|
|
276
|
+
var Defs2 = 82;
|
|
277
|
+
var Ellipse2 = 83;
|
|
278
|
+
var G2 = 84;
|
|
279
|
+
var Line2 = 85;
|
|
280
|
+
var Path2 = 86;
|
|
281
|
+
var Polygon2 = 87;
|
|
282
|
+
var Polyline2 = 88;
|
|
283
|
+
var Rect2 = 89;
|
|
284
|
+
var Svg2 = 90;
|
|
285
|
+
var Use2 = 91;
|
|
286
|
+
var Reference = 100;
|
|
287
|
+
|
|
288
|
+
// ../../node_modules/@lvce-editor/constants/dist/parts/ElementTagMap/ElementTagMap.js
|
|
289
|
+
var elementTagMap = {
|
|
290
|
+
[A2]: A,
|
|
291
|
+
[Article2]: Article,
|
|
292
|
+
[Aside2]: Aside,
|
|
293
|
+
[Audio2]: Audio,
|
|
294
|
+
[BlockQuote2]: BlockQuote,
|
|
295
|
+
[Br2]: Br,
|
|
296
|
+
[Button2]: Button,
|
|
297
|
+
[Canvas2]: Canvas,
|
|
298
|
+
[Circle2]: Circle,
|
|
299
|
+
[Cite2]: Cite,
|
|
300
|
+
[Code2]: Code,
|
|
301
|
+
[Col2]: Col,
|
|
302
|
+
[ColGroup2]: ColGroup,
|
|
303
|
+
[Data2]: Data,
|
|
304
|
+
[Dd2]: Dd,
|
|
305
|
+
[Defs2]: Defs,
|
|
306
|
+
[Del2]: Del,
|
|
307
|
+
[Div2]: Div,
|
|
308
|
+
[Dl2]: Dl,
|
|
309
|
+
[Dt2]: Dt,
|
|
310
|
+
[Ellipse2]: Ellipse,
|
|
311
|
+
[Em2]: Em,
|
|
312
|
+
[Figcaption2]: Figcaption,
|
|
313
|
+
[Figure2]: Figure,
|
|
314
|
+
[Footer2]: Footer,
|
|
315
|
+
[Form2]: Form,
|
|
316
|
+
[G2]: G,
|
|
317
|
+
[H12]: H1,
|
|
318
|
+
[H22]: H2,
|
|
319
|
+
[H32]: H3,
|
|
320
|
+
[H42]: H4,
|
|
321
|
+
[H52]: H5,
|
|
322
|
+
[H62]: H6,
|
|
323
|
+
[Head2]: Head,
|
|
324
|
+
[Header2]: Header,
|
|
325
|
+
[Hr2]: Hr,
|
|
326
|
+
[Html2]: Html,
|
|
327
|
+
[I2]: I,
|
|
328
|
+
[Iframe2]: Iframe,
|
|
329
|
+
[Img2]: Img,
|
|
330
|
+
[Input2]: Input,
|
|
331
|
+
[Ins2]: Ins,
|
|
332
|
+
[Kbd2]: Kbd,
|
|
333
|
+
[Label2]: Label,
|
|
334
|
+
[Li2]: Li,
|
|
335
|
+
[Line2]: Line,
|
|
336
|
+
[Main2]: Main,
|
|
337
|
+
[Meta2]: Meta,
|
|
338
|
+
[Nav2]: Nav,
|
|
339
|
+
[Ol2]: Ol,
|
|
340
|
+
[Option2]: Option,
|
|
341
|
+
[P2]: P,
|
|
342
|
+
[Path2]: Path,
|
|
343
|
+
[Polygon2]: Polygon,
|
|
344
|
+
[Polyline2]: Polyline,
|
|
345
|
+
[Pre2]: Pre,
|
|
346
|
+
[Quote2]: Quote,
|
|
347
|
+
[Rect2]: Rect,
|
|
348
|
+
[Search2]: Search,
|
|
349
|
+
[Section2]: Section,
|
|
350
|
+
[Select2]: Select,
|
|
351
|
+
[Span2]: Span,
|
|
352
|
+
[Strong2]: Strong,
|
|
353
|
+
[Style2]: Style,
|
|
354
|
+
[Svg2]: Svg,
|
|
355
|
+
[Table2]: Table,
|
|
356
|
+
[TBody2]: TBody,
|
|
357
|
+
[Td2]: Td,
|
|
358
|
+
[TextArea2]: TextArea,
|
|
359
|
+
[Tfoot2]: Tfoot,
|
|
360
|
+
[Th2]: Th,
|
|
361
|
+
[THead2]: THead,
|
|
362
|
+
[Time2]: Time,
|
|
363
|
+
[Title2]: Title,
|
|
364
|
+
[Tr2]: Tr,
|
|
365
|
+
[Ul2]: Ul,
|
|
366
|
+
[Use2]: Use,
|
|
367
|
+
[Video2]: Video
|
|
368
|
+
};
|
|
369
|
+
var getElementTag = (type) => {
|
|
370
|
+
const elementTag = elementTagMap[type];
|
|
371
|
+
if (elementTag) {
|
|
372
|
+
return elementTag;
|
|
373
|
+
}
|
|
374
|
+
throw new Error(`element tag not found ${type}`);
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
// ../session-replay-worker/src/visualDom.ts
|
|
378
|
+
var element = (tag = "div") => ({ attrs: {}, children: [], tag });
|
|
379
|
+
var styleKeys = /* @__PURE__ */ new Set(["width", "height", "top", "left", "marginTop", "paddingLeft", "paddingRight"]);
|
|
380
|
+
var attributes = { className: "class", htmlFor: "for", inputType: "type" };
|
|
381
|
+
var setStyle = (node, key, value) => {
|
|
382
|
+
node.attrs ||= {};
|
|
383
|
+
const declarations = (node.attrs.style || "").split(";").filter((entry) => entry.trim() && entry.split(":", 1)[0].trim() !== key);
|
|
384
|
+
if (value !== void 0 && value !== "") declarations.push(`${key}:${typeof value === "number" || typeof value === "string" ? value : ""}`);
|
|
385
|
+
node.attrs.style = declarations.join(";");
|
|
386
|
+
};
|
|
387
|
+
var property = (node, key, value) => {
|
|
388
|
+
if (!node || /^on/i.test(key) || ["type", "childCount", "uid"].includes(key)) return;
|
|
389
|
+
switch (key) {
|
|
390
|
+
case "checked":
|
|
391
|
+
node.checked = Boolean(value);
|
|
392
|
+
return;
|
|
393
|
+
case "scrollLeft":
|
|
394
|
+
case "scrollTop": {
|
|
395
|
+
node.scroll ||= [0, 0];
|
|
396
|
+
node.scroll[key === "scrollTop" ? 1 : 0] = Number(value) || 0;
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
case "value":
|
|
400
|
+
node.value = typeof value === "string" ? value : "";
|
|
401
|
+
return;
|
|
402
|
+
default:
|
|
403
|
+
break;
|
|
404
|
+
}
|
|
405
|
+
if (styleKeys.has(key)) {
|
|
406
|
+
setStyle(
|
|
407
|
+
node,
|
|
408
|
+
key.replaceAll(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`),
|
|
409
|
+
typeof value === "number" ? `${value}px` : value
|
|
410
|
+
);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
const attribute = attributes[key] || (key.startsWith("aria") ? `aria-${key.slice(4).toLowerCase()}` : key);
|
|
414
|
+
node.attrs ||= {};
|
|
415
|
+
if ([void 0, null, false].includes(value)) delete node.attrs[attribute];
|
|
416
|
+
else node.attrs[attribute] = typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : "";
|
|
417
|
+
};
|
|
418
|
+
var matches = (node, selector) => {
|
|
419
|
+
if (selector.startsWith(".")) return (node.attrs?.class || "").split(" ").includes(selector.slice(1));
|
|
420
|
+
if (selector.startsWith("#")) return node.attrs?.id === selector.slice(1);
|
|
421
|
+
const name = /^\[name="([^"]+)"\]$/.exec(selector);
|
|
422
|
+
return name ? node.attrs?.name === name[1] : node.tag === selector;
|
|
423
|
+
};
|
|
424
|
+
var find = (node, selector) => {
|
|
425
|
+
if (matches(node, selector)) return node;
|
|
426
|
+
const children = node.children || [];
|
|
427
|
+
for (const child of children) {
|
|
428
|
+
const result = find(child, selector);
|
|
429
|
+
if (result) return result;
|
|
430
|
+
}
|
|
431
|
+
return void 0;
|
|
432
|
+
};
|
|
433
|
+
var createVisualDom = () => {
|
|
434
|
+
const views = /* @__PURE__ */ new Map();
|
|
435
|
+
const parents = /* @__PURE__ */ new WeakMap();
|
|
436
|
+
const owners = /* @__PURE__ */ new WeakMap();
|
|
437
|
+
let nodeCount = 0;
|
|
438
|
+
const detach = (node) => {
|
|
439
|
+
const parent = parents.get(node);
|
|
440
|
+
if (parent) parent.children.splice(parent.children.indexOf(node), 1);
|
|
441
|
+
parents.delete(node);
|
|
442
|
+
};
|
|
443
|
+
const clear = (node) => {
|
|
444
|
+
while (node.children?.length) detach(node.children.at(0));
|
|
445
|
+
};
|
|
446
|
+
const append = (parent, node, index) => {
|
|
447
|
+
let depth = 0;
|
|
448
|
+
for (let ancestor = parent; ancestor; ancestor = parents.get(ancestor)) {
|
|
449
|
+
if (ancestor === node || ++depth > 150) throw new Error("Invalid replay DOM reference or depth");
|
|
450
|
+
}
|
|
451
|
+
const oldParent = parents.get(node);
|
|
452
|
+
const oldIndex = oldParent?.children?.indexOf(node);
|
|
453
|
+
if (oldParent === parent && index !== void 0 && oldIndex !== void 0 && oldIndex < index) index--;
|
|
454
|
+
detach(node);
|
|
455
|
+
parent.children ||= [];
|
|
456
|
+
parent.children.splice(index ?? parent.children.length, 0, node);
|
|
457
|
+
parents.set(node, parent);
|
|
458
|
+
};
|
|
459
|
+
const replace = (node, next) => {
|
|
460
|
+
if (node === next) return next;
|
|
461
|
+
const parent = parents.get(node);
|
|
462
|
+
const index = parent?.children.indexOf(node);
|
|
463
|
+
detach(node);
|
|
464
|
+
if (parent) append(parent, next, index);
|
|
465
|
+
const uid = owners.get(node);
|
|
466
|
+
if (uid !== void 0) {
|
|
467
|
+
views.set(uid, next);
|
|
468
|
+
owners.set(next, uid);
|
|
469
|
+
}
|
|
470
|
+
return next;
|
|
471
|
+
};
|
|
472
|
+
const renderNode = (value) => {
|
|
473
|
+
let node;
|
|
474
|
+
if (value.type === VirtualDomElements_exports.Reference) node = views.get(value.uid) || { text: "Reference node not found" };
|
|
475
|
+
else if (value.type === VirtualDomElements_exports.Text) node = { text: value.text };
|
|
476
|
+
else {
|
|
477
|
+
node = element(ElementTagMap_exports.getElementTag(value.type));
|
|
478
|
+
for (const [key, entry] of Object.entries(value)) property(node, key, entry);
|
|
479
|
+
}
|
|
480
|
+
return node;
|
|
481
|
+
};
|
|
482
|
+
const render = (nodes) => {
|
|
483
|
+
const roots = [];
|
|
484
|
+
const stack = [];
|
|
485
|
+
for (const value of nodes) {
|
|
486
|
+
if (++nodeCount > 2e6) throw new Error("Session replay DOM operation limit reached");
|
|
487
|
+
while (stack.at(-1)?.remaining === 0) stack.pop();
|
|
488
|
+
const node = renderNode(value);
|
|
489
|
+
const parent = stack.at(-1);
|
|
490
|
+
if (parent) {
|
|
491
|
+
append(parent.node, node);
|
|
492
|
+
parent.remaining--;
|
|
493
|
+
} else roots.push(node);
|
|
494
|
+
const childCount = value.childCount || 0;
|
|
495
|
+
if (!Number.isSafeInteger(childCount) || childCount < 0 || stack.length > 150) throw new Error("Invalid virtual DOM child count or depth");
|
|
496
|
+
if (childCount) stack.push({ node, remaining: childCount });
|
|
497
|
+
}
|
|
498
|
+
if (stack.some((entry) => entry.remaining !== 0)) throw new Error("Incomplete replay virtual DOM");
|
|
499
|
+
return roots;
|
|
500
|
+
};
|
|
501
|
+
const patch = (uid, patches) => {
|
|
502
|
+
let current = views.get(uid);
|
|
503
|
+
if (!current) return;
|
|
504
|
+
owners.set(current, uid);
|
|
505
|
+
const mutations = {
|
|
506
|
+
1: (node, value) => {
|
|
507
|
+
node.text = String(value.value);
|
|
508
|
+
return node;
|
|
509
|
+
},
|
|
510
|
+
10: (node, value) => parents.get(node)?.children?.[value.index],
|
|
511
|
+
11: (node, value) => {
|
|
512
|
+
const next = views.get(value.uid);
|
|
513
|
+
return next ? replace(node, next) : node;
|
|
514
|
+
},
|
|
515
|
+
2: (node, value) => {
|
|
516
|
+
const next = render(value.nodes)[0];
|
|
517
|
+
if (next) return replace(node, next);
|
|
518
|
+
detach(node);
|
|
519
|
+
return node;
|
|
520
|
+
},
|
|
521
|
+
3: (node, value) => {
|
|
522
|
+
property(node, value.key, value.value);
|
|
523
|
+
return node;
|
|
524
|
+
},
|
|
525
|
+
4: (node, value) => {
|
|
526
|
+
property(node, value.key, void 0);
|
|
527
|
+
return node;
|
|
528
|
+
},
|
|
529
|
+
6: (node, value) => {
|
|
530
|
+
const children = render(value.nodes);
|
|
531
|
+
for (const child of children) append(node, child);
|
|
532
|
+
return node;
|
|
533
|
+
},
|
|
534
|
+
7: (node, value) => node.children?.[value.index],
|
|
535
|
+
8: (node) => parents.get(node),
|
|
536
|
+
9: (node, value) => {
|
|
537
|
+
if (node.children?.[value.index]) detach(node.children[value.index]);
|
|
538
|
+
return node;
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
for (let index = 0; index < patches.length; index++) {
|
|
542
|
+
const value = patches[index];
|
|
543
|
+
if (value.type === 7 && value.index === current.children?.length && patches[index + 1]?.type === 2) append(current, element());
|
|
544
|
+
if (!mutations[value.type]) continue;
|
|
545
|
+
current = mutations[value.type](current, value);
|
|
546
|
+
if (!current) return;
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
return { append, clear, detach, element, find, patch, property, render, replace, views };
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
// ../session-replay-worker/src/visualState.ts
|
|
553
|
+
var createVisualState = (initial) => {
|
|
554
|
+
const frame = structuredClone(initial);
|
|
555
|
+
const dom = createVisualDom();
|
|
556
|
+
const { append, clear, detach, element: element2, find: find2, patch, property: property2, render, replace, views } = dom;
|
|
557
|
+
const sheets = new Map((frame.styles || []).map((text, index) => [`initial-${index}`, text]));
|
|
558
|
+
const calls = /* @__PURE__ */ new Map();
|
|
559
|
+
const batches = /* @__PURE__ */ new Map();
|
|
560
|
+
const setDom = (uid, nodes) => {
|
|
561
|
+
const view = views.get(uid);
|
|
562
|
+
if (!view) return;
|
|
563
|
+
const next = render(nodes)[0];
|
|
564
|
+
if (next) {
|
|
565
|
+
replace(view, next);
|
|
566
|
+
views.set(uid, next);
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
const apply = (method, params = []) => {
|
|
570
|
+
if (method && Object.hasOwn(handlers, method)) handlers[method](...params);
|
|
571
|
+
};
|
|
572
|
+
const execute = (commands2) => {
|
|
573
|
+
for (const [method, ...params] of commands2) apply(method, params);
|
|
574
|
+
};
|
|
575
|
+
const commit = (uid, transaction) => {
|
|
576
|
+
const batch = batches.get(transaction);
|
|
577
|
+
if (!batch || batch.uid !== uid) return;
|
|
578
|
+
batch.committed = true;
|
|
579
|
+
for (const [key, pending2] of batches) {
|
|
580
|
+
if (pending2.uid !== uid) continue;
|
|
581
|
+
if (!pending2.committed) return;
|
|
582
|
+
execute(pending2.commands);
|
|
583
|
+
batches.delete(key);
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
const appendView = (uid, childId, references) => {
|
|
587
|
+
const view = views.get(uid);
|
|
588
|
+
const child = views.get(childId);
|
|
589
|
+
if (!view || !child) return;
|
|
590
|
+
const nextReferences = references?.slice(references.indexOf(childId) + 1) || [];
|
|
591
|
+
const next = nextReferences.map((id) => views.get(id)).find((node) => node && view.children?.includes(node));
|
|
592
|
+
append(view, child, next ? view.children.indexOf(next) : void 0);
|
|
593
|
+
};
|
|
594
|
+
const setProperty = (uid, selector, key, value) => {
|
|
595
|
+
const view = views.get(uid);
|
|
596
|
+
const node = view && find2(view, selector);
|
|
597
|
+
if (!node) return;
|
|
598
|
+
if (key === "textContent") {
|
|
599
|
+
clear(node);
|
|
600
|
+
append(node, { text: String(value) });
|
|
601
|
+
} else property2(node, key, value);
|
|
602
|
+
};
|
|
603
|
+
const setBounds = (uid, left, top, width, height) => {
|
|
604
|
+
const view = views.get(uid);
|
|
605
|
+
const bounds = Object.entries({ height, left, top, width });
|
|
606
|
+
for (const [key, value] of bounds) property2(view, key, value);
|
|
607
|
+
};
|
|
608
|
+
const setCss = (uid, text) => {
|
|
609
|
+
sheets.set(uid, text);
|
|
610
|
+
};
|
|
611
|
+
const create = (_id, uid = Number(_id)) => {
|
|
612
|
+
views.set(uid, element2());
|
|
613
|
+
};
|
|
614
|
+
const handlers = {
|
|
615
|
+
"Css.addCssStyleSheet": setCss,
|
|
616
|
+
"Css.removeCssStyleSheet": (uid) => {
|
|
617
|
+
sheets.delete(uid);
|
|
618
|
+
},
|
|
619
|
+
"Viewlet.addCss": setCss,
|
|
620
|
+
"Viewlet.append": appendView,
|
|
621
|
+
"Viewlet.appendToBody": (uid) => {
|
|
622
|
+
const view = views.get(uid);
|
|
623
|
+
if (view) append(frame.dom, view);
|
|
624
|
+
},
|
|
625
|
+
"Viewlet.appendToRoot": (uid, root) => {
|
|
626
|
+
const view = views.get(uid);
|
|
627
|
+
const parent = find2(frame.dom, `#${root}`);
|
|
628
|
+
if (view && parent) append(parent, view);
|
|
629
|
+
},
|
|
630
|
+
"Viewlet.commitPending": commit,
|
|
631
|
+
"Viewlet.create": create,
|
|
632
|
+
"Viewlet.createFunctionalRoot": create,
|
|
633
|
+
"Viewlet.createPlaceholder": (uid, parentId, top, left, width, height) => {
|
|
634
|
+
views.set(uid, element2());
|
|
635
|
+
property2(views.get(uid), "className", `Viewlet ${uid}`);
|
|
636
|
+
setBounds(uid, left, top, width, height);
|
|
637
|
+
appendView(parentId, uid);
|
|
638
|
+
},
|
|
639
|
+
"Viewlet.dispose": (uid) => {
|
|
640
|
+
const view = views.get(uid);
|
|
641
|
+
if (view) detach(view);
|
|
642
|
+
views.delete(uid);
|
|
643
|
+
sheets.delete(uid);
|
|
644
|
+
},
|
|
645
|
+
"Viewlet.executeCommands": execute,
|
|
646
|
+
"Viewlet.patchCss": (uid, start, count, replacement) => {
|
|
647
|
+
const text = sheets.get(uid);
|
|
648
|
+
if (typeof text === "string") sheets.set(uid, text.slice(0, start) + replacement + text.slice(start + count));
|
|
649
|
+
},
|
|
650
|
+
"Viewlet.replaceChildren": (uid, children) => {
|
|
651
|
+
const view = views.get(uid);
|
|
652
|
+
if (!view) return;
|
|
653
|
+
clear(view);
|
|
654
|
+
for (const id of children) {
|
|
655
|
+
const child = views.get(id);
|
|
656
|
+
if (child) append(view, child);
|
|
657
|
+
}
|
|
658
|
+
},
|
|
659
|
+
"Viewlet.scrollSelectorBy": (uid, selector, delta) => {
|
|
660
|
+
const view = views.get(uid);
|
|
661
|
+
const node = view && find2(view, selector);
|
|
662
|
+
if (node) property2(node, "scrollLeft", (node.scroll?.[0] || 0) + delta);
|
|
663
|
+
},
|
|
664
|
+
"Viewlet.sendMultiple": execute,
|
|
665
|
+
"Viewlet.setBounds": setBounds,
|
|
666
|
+
"Viewlet.setCheckBoxValue": (uid, name, value) => setProperty(uid, `[name="${name}"]`, "checked", value),
|
|
667
|
+
"Viewlet.setComponentDom": setDom,
|
|
668
|
+
"Viewlet.setCss": setCss,
|
|
669
|
+
"Viewlet.setDom": (uid, nodes) => {
|
|
670
|
+
const view = views.get(uid);
|
|
671
|
+
if (!view) return;
|
|
672
|
+
clear(view);
|
|
673
|
+
const children = render(nodes);
|
|
674
|
+
for (const child of children) append(view, child);
|
|
675
|
+
},
|
|
676
|
+
"Viewlet.setDom2": setDom,
|
|
677
|
+
"Viewlet.setInputValues": (uid, items) => {
|
|
678
|
+
for (const { name, value } of items) setProperty(uid, `[name="${name}"]`, "value", value);
|
|
679
|
+
},
|
|
680
|
+
"Viewlet.setPatches": (uid, patches) => {
|
|
681
|
+
if (patches.length === 1 && patches[0].type === 6) setDom(uid, patches[0].nodes);
|
|
682
|
+
else patch(uid, patches);
|
|
683
|
+
},
|
|
684
|
+
"Viewlet.setProperty": setProperty,
|
|
685
|
+
"Viewlet.setTreePatches": patch,
|
|
686
|
+
"Viewlet.setValueByName": (uid, name, value) => setProperty(uid, `[name="${name}"]`, "value", value),
|
|
687
|
+
"Viewlet.show": (uid) => {
|
|
688
|
+
const view = views.get(uid);
|
|
689
|
+
if (view) append(find2(frame.dom, "#Workbench") || frame.dom, view);
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
return {
|
|
693
|
+
accept(data) {
|
|
694
|
+
if (!data?.renderer || !data.message || typeof data.message !== "object") return;
|
|
695
|
+
const { connection, direction, message } = data;
|
|
696
|
+
const key = `${connection}:${message.id}`;
|
|
697
|
+
if (direction === "to-renderer") {
|
|
698
|
+
if (message.method === "Viewlet.queueCommands") calls.set(key, message.params);
|
|
699
|
+
else apply(message.method, message.params);
|
|
700
|
+
} else if (calls.has(key)) {
|
|
701
|
+
const [uid, commands2] = calls.get(key);
|
|
702
|
+
calls.delete(key);
|
|
703
|
+
if (Number.isSafeInteger(message.result)) batches.set(message.result, { commands: commands2, committed: false, uid });
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
frame() {
|
|
707
|
+
return { ...frame, styles: [...sheets.values()] };
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
};
|
|
711
|
+
|
|
1
712
|
// ../session-replay-worker/src/protocol.ts
|
|
2
713
|
var version = 1;
|
|
3
714
|
var maxEventBytes = 75e4;
|
|
@@ -23,8 +734,23 @@ var loadContent = (value) => {
|
|
|
23
734
|
const frames = session.events.filter((event) => event.type === "frame");
|
|
24
735
|
if (frames.length === 0) throw new Error("This session has no visual frames");
|
|
25
736
|
const duration = session.events.at(-1)?.timestamp || 0;
|
|
737
|
+
let visual = createVisualState(frames[0].data);
|
|
738
|
+
let eventIndex = 0;
|
|
739
|
+
let lastPosition = -1;
|
|
26
740
|
const seek = (timestamp) => {
|
|
27
741
|
const position = Math.max(0, Math.min(duration, timestamp || 0));
|
|
742
|
+
if (frames[0].data.commandReplay) {
|
|
743
|
+
if (position < lastPosition) {
|
|
744
|
+
visual = createVisualState(frames[0].data);
|
|
745
|
+
eventIndex = 0;
|
|
746
|
+
}
|
|
747
|
+
while (eventIndex < session.events.length && session.events[eventIndex].timestamp <= position) {
|
|
748
|
+
const event = session.events[eventIndex++];
|
|
749
|
+
if (event.type === "message") visual.accept(event.data);
|
|
750
|
+
}
|
|
751
|
+
lastPosition = position;
|
|
752
|
+
return { duration, frame: structuredClone(visual.frame()), position };
|
|
753
|
+
}
|
|
28
754
|
let low = 0;
|
|
29
755
|
let high = frames.length;
|
|
30
756
|
while (low < high) {
|
|
@@ -37,6 +763,87 @@ var loadContent = (value) => {
|
|
|
37
763
|
return { duration, seek };
|
|
38
764
|
};
|
|
39
765
|
|
|
766
|
+
// ../session-replay-worker/src/proxy.ts
|
|
767
|
+
var wrapPorts = (value, replacePort, seen = /* @__PURE__ */ new Map()) => {
|
|
768
|
+
if (!value || typeof value !== "object") return value;
|
|
769
|
+
if (seen.has(value)) return seen.get(value);
|
|
770
|
+
if (value instanceof MessagePort) {
|
|
771
|
+
const replacement = replacePort(value);
|
|
772
|
+
seen.set(value, replacement);
|
|
773
|
+
return replacement;
|
|
774
|
+
}
|
|
775
|
+
seen.set(value, value);
|
|
776
|
+
if (value instanceof Map) {
|
|
777
|
+
const entries = [...value];
|
|
778
|
+
value.clear();
|
|
779
|
+
for (const [key, entry] of entries) value.set(wrapPorts(key, replacePort, seen), wrapPorts(entry, replacePort, seen));
|
|
780
|
+
} else if (value instanceof Set) {
|
|
781
|
+
const entries = [...value];
|
|
782
|
+
value.clear();
|
|
783
|
+
for (const entry of entries) value.add(wrapPorts(entry, replacePort, seen));
|
|
784
|
+
} else if (Array.isArray(value) || Object.prototype.toString.call(value) === "[object Object]") {
|
|
785
|
+
const object = value;
|
|
786
|
+
for (const key of Object.keys(object)) object[key] = wrapPorts(object[key], replacePort, seen);
|
|
787
|
+
}
|
|
788
|
+
return value;
|
|
789
|
+
};
|
|
790
|
+
var createProxyRegistry = ({
|
|
791
|
+
record,
|
|
792
|
+
report: report2 = () => {
|
|
793
|
+
}
|
|
794
|
+
}) => {
|
|
795
|
+
const connections = /* @__PURE__ */ new Set();
|
|
796
|
+
let nextId = 0;
|
|
797
|
+
const createNestedPort = (connection, renderer, port) => create(port, `${connection}/port`, renderer);
|
|
798
|
+
const create = (port, label = "renderer", renderer = true) => {
|
|
799
|
+
const channel = new MessageChannel();
|
|
800
|
+
const peer = channel.port1;
|
|
801
|
+
const connection = ++nextId;
|
|
802
|
+
const close = () => {
|
|
803
|
+
for (const endpoint of [port, peer]) {
|
|
804
|
+
endpoint.removeEventListener("close", close);
|
|
805
|
+
endpoint.onmessage = null;
|
|
806
|
+
endpoint.onmessageerror = null;
|
|
807
|
+
endpoint.close();
|
|
808
|
+
}
|
|
809
|
+
connections.delete(close);
|
|
810
|
+
};
|
|
811
|
+
connections.add(close);
|
|
812
|
+
const ignoredReplies = { "from-renderer": /* @__PURE__ */ new Set(), "to-renderer": /* @__PURE__ */ new Set() };
|
|
813
|
+
const forward = (source, target, direction) => {
|
|
814
|
+
source.onmessage = ({ data }) => {
|
|
815
|
+
const opposite = direction === "to-renderer" ? "from-renderer" : "to-renderer";
|
|
816
|
+
const ignored = typeof data?.method === "string" && data.method.startsWith("SessionReplay.");
|
|
817
|
+
if (ignored && data.id !== void 0) ignoredReplies[opposite].add(data.id);
|
|
818
|
+
const ignoredReply = !data?.method && ignoredReplies[direction].delete(data?.id);
|
|
819
|
+
if (!ignored && !ignoredReply) {
|
|
820
|
+
try {
|
|
821
|
+
record({ connection, direction, label, message: data, renderer });
|
|
822
|
+
} catch (error) {
|
|
823
|
+
report2(error);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
const directRenderer = renderer && data?.method === "HandleMessagePort.handleMessagePort";
|
|
827
|
+
const message = wrapPorts(data, createNestedPort.bind(null, connection, directRenderer));
|
|
828
|
+
target.postMessage(message, getTransferrables(message));
|
|
829
|
+
if (data?.method === "Exit.exit") close();
|
|
830
|
+
};
|
|
831
|
+
source.onmessageerror = () => report2(new Error(`Cannot decode session replay proxy message (${connection})`));
|
|
832
|
+
source.addEventListener("close", close);
|
|
833
|
+
source.start();
|
|
834
|
+
};
|
|
835
|
+
forward(port, peer, "to-renderer");
|
|
836
|
+
forward(peer, port, "from-renderer");
|
|
837
|
+
return channel.port2;
|
|
838
|
+
};
|
|
839
|
+
return {
|
|
840
|
+
create,
|
|
841
|
+
dispose() {
|
|
842
|
+
for (const close of connections) close();
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
};
|
|
846
|
+
|
|
40
847
|
// ../session-replay-worker/src/recorder.ts
|
|
41
848
|
var createRecorder = ({
|
|
42
849
|
fetch: request = globalThis.fetch,
|
|
@@ -46,7 +853,7 @@ var createRecorder = ({
|
|
|
46
853
|
let metadata;
|
|
47
854
|
let options;
|
|
48
855
|
const events = [];
|
|
49
|
-
const
|
|
856
|
+
const pending2 = [];
|
|
50
857
|
let size = 0;
|
|
51
858
|
let origin = 0;
|
|
52
859
|
let remote;
|
|
@@ -70,14 +877,14 @@ var createRecorder = ({
|
|
|
70
877
|
throw new Error("Session replay storage limit reached; download this session and start a new one");
|
|
71
878
|
size += eventSize;
|
|
72
879
|
events.push(event);
|
|
73
|
-
if (options.upload)
|
|
880
|
+
if (options.upload) pending2.push(event);
|
|
74
881
|
if (options.local) {
|
|
75
882
|
await storage2.save(metadata, [event]);
|
|
76
883
|
saved++;
|
|
77
884
|
}
|
|
78
885
|
};
|
|
79
886
|
const doUpload = async () => {
|
|
80
|
-
if (!options?.upload ||
|
|
887
|
+
if (!options?.upload || pending2.length === 0) return;
|
|
81
888
|
const endpoint = new URL(options.endpoint);
|
|
82
889
|
if (!["https:", "http:"].includes(endpoint.protocol)) throw new Error("Invalid session replay backend URL");
|
|
83
890
|
const headers = { "Content-Type": "application/json", ...options.token && { Authorization: `Bearer ${options.token}` } };
|
|
@@ -93,10 +900,10 @@ var createRecorder = ({
|
|
|
93
900
|
return response.json();
|
|
94
901
|
};
|
|
95
902
|
if (!remote) remote = await send(endpoint, { createdAt: metadata.createdAt, version });
|
|
96
|
-
while (
|
|
903
|
+
while (pending2.length > 0) {
|
|
97
904
|
const batch = [];
|
|
98
905
|
let batchBytes = 0;
|
|
99
|
-
for (const event of
|
|
906
|
+
for (const event of pending2) {
|
|
100
907
|
const length = bytes(event);
|
|
101
908
|
if (batch.length > 0 && (batchBytes + length > 8e5 || batch.length >= 250)) break;
|
|
102
909
|
batch.push(event);
|
|
@@ -105,7 +912,7 @@ var createRecorder = ({
|
|
|
105
912
|
const url = new URL(endpoint);
|
|
106
913
|
url.pathname = `${url.pathname.replace(/\/$/, "")}/${encodeURIComponent(remote.id)}/events`;
|
|
107
914
|
await send(url, { events: batch, uploadToken: remote.uploadToken });
|
|
108
|
-
|
|
915
|
+
pending2.splice(0, batch.length);
|
|
109
916
|
uploaded += batch.length;
|
|
110
917
|
}
|
|
111
918
|
};
|
|
@@ -133,13 +940,106 @@ var createRecorder = ({
|
|
|
133
940
|
error: lastError,
|
|
134
941
|
events: events.length,
|
|
135
942
|
id: metadata?.id,
|
|
136
|
-
pending:
|
|
943
|
+
pending: pending2.length,
|
|
137
944
|
saved,
|
|
138
945
|
uploaded
|
|
139
946
|
})
|
|
140
947
|
};
|
|
141
948
|
};
|
|
142
949
|
|
|
950
|
+
// ../session-replay-worker/src/api/capture.ts
|
|
951
|
+
var serializeMessage = (message) => {
|
|
952
|
+
const ancestors = [];
|
|
953
|
+
let count = 0;
|
|
954
|
+
return JSON.parse(
|
|
955
|
+
JSON.stringify(message, function(key, value) {
|
|
956
|
+
if (++count > 2e5) throw new Error("Session replay message is too complex");
|
|
957
|
+
if (/password|token|secret|authorization|cookie/i.test(key)) return "[redacted]";
|
|
958
|
+
if (typeof value === "bigint") return String(value);
|
|
959
|
+
if (typeof value !== "object" || value === null) return value;
|
|
960
|
+
while (ancestors.length > 0 && ancestors.at(-1) !== this) ancestors.pop();
|
|
961
|
+
if (ancestors.includes(value)) return "[circular]";
|
|
962
|
+
ancestors.push(value);
|
|
963
|
+
if (value instanceof Error) return { message: value.message, name: value.name, stack: value.stack };
|
|
964
|
+
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) return { byteLength: value.byteLength, type: value.constructor.name };
|
|
965
|
+
if (value.constructor?.name === "MessagePort") return { type: "MessagePort" };
|
|
966
|
+
return value;
|
|
967
|
+
})
|
|
968
|
+
);
|
|
969
|
+
};
|
|
970
|
+
|
|
971
|
+
// ../session-replay-worker/src/serializeProxyMessage.ts
|
|
972
|
+
var redacted = "[redacted]";
|
|
973
|
+
var isMasked = (node) => node.inputType === "password" || Object.hasOwn(node, "data-session-replay-mask") || Object.hasOwn(node, "data-session-replay-ignore");
|
|
974
|
+
var structuralKeys = /* @__PURE__ */ new Set(["type", "childCount", "uid"]);
|
|
975
|
+
var redactNode = (node) => {
|
|
976
|
+
for (const key of Object.keys(node)) {
|
|
977
|
+
if (structuralKeys.has(key)) continue;
|
|
978
|
+
if (["text", "value", "textContent"].includes(key)) node[key] = redacted;
|
|
979
|
+
else if (key === "inputType" && node[key] === "password") continue;
|
|
980
|
+
else if (["data-session-replay-mask", "data-session-replay-ignore"].includes(key)) node[key] = "";
|
|
981
|
+
else delete node[key];
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
var redactUpdates = (method, params) => {
|
|
985
|
+
if (method === "Viewlet.setValueByName") params[2] = redacted;
|
|
986
|
+
else if (method === "Viewlet.setProperty") params[3] = redacted;
|
|
987
|
+
const updates = params[1];
|
|
988
|
+
if (!Array.isArray(updates)) return;
|
|
989
|
+
if (method === "Viewlet.setInputValues") for (const item of updates) item.value = redacted;
|
|
990
|
+
if (!["Viewlet.setPatches", "Viewlet.setTreePatches"].includes(method)) return;
|
|
991
|
+
for (const patch of updates) {
|
|
992
|
+
if ([1, 3].includes(patch.type)) patch.value = redacted;
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
var createMessageSerializer = () => {
|
|
996
|
+
const maskedViews = /* @__PURE__ */ new Set();
|
|
997
|
+
const sanitizeCommand = (method, params, masked) => {
|
|
998
|
+
if (!method.startsWith("Viewlet.") || typeof params[0] !== "number") return;
|
|
999
|
+
const uid = params[0];
|
|
1000
|
+
const patches = params[1];
|
|
1001
|
+
const masksInput = Array.isArray(patches) && patches.some((patch) => patch?.key === "inputType" && patch.value === "password");
|
|
1002
|
+
if (masked || masksInput) maskedViews.add(uid);
|
|
1003
|
+
if (maskedViews.has(uid)) redactUpdates(method, params);
|
|
1004
|
+
};
|
|
1005
|
+
const sanitizeArray = (array) => {
|
|
1006
|
+
let remaining = 0;
|
|
1007
|
+
let masked = false;
|
|
1008
|
+
for (const entry of array) {
|
|
1009
|
+
if (entry && typeof entry === "object" && !Array.isArray(entry)) {
|
|
1010
|
+
const node = entry;
|
|
1011
|
+
if (remaining > 0 || isMasked(node)) {
|
|
1012
|
+
remaining = Math.max(0, remaining - 1) + (typeof node.childCount === "number" ? node.childCount : 0);
|
|
1013
|
+
redactNode(node);
|
|
1014
|
+
masked = true;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
masked = sanitize(entry) || masked;
|
|
1018
|
+
}
|
|
1019
|
+
if (typeof array[0] === "string" && array[0].startsWith("Viewlet.")) {
|
|
1020
|
+
const params = array.slice(1);
|
|
1021
|
+
sanitizeCommand(array[0], params, masked);
|
|
1022
|
+
array.splice(1, array.length - 1, ...params);
|
|
1023
|
+
}
|
|
1024
|
+
return masked;
|
|
1025
|
+
};
|
|
1026
|
+
const sanitize = (value) => {
|
|
1027
|
+
if (!value || typeof value !== "object") return false;
|
|
1028
|
+
if (Array.isArray(value)) return sanitizeArray(value);
|
|
1029
|
+
const object = value;
|
|
1030
|
+
let masked = isMasked(object);
|
|
1031
|
+
if (masked) redactNode(object);
|
|
1032
|
+
for (const child of Object.values(object)) masked = sanitize(child) || masked;
|
|
1033
|
+
if (typeof object.method === "string" && Array.isArray(object.params)) sanitizeCommand(object.method, object.params, masked);
|
|
1034
|
+
return masked;
|
|
1035
|
+
};
|
|
1036
|
+
return (message) => {
|
|
1037
|
+
const result = serializeMessage(message);
|
|
1038
|
+
sanitize(result);
|
|
1039
|
+
return result;
|
|
1040
|
+
};
|
|
1041
|
+
};
|
|
1042
|
+
|
|
143
1043
|
// ../session-replay-worker/src/storage.ts
|
|
144
1044
|
var withoutSessionId = ({ sessionId, ...event }) => event;
|
|
145
1045
|
var open = () => new Promise((resolve, reject) => {
|
|
@@ -182,8 +1082,37 @@ var content;
|
|
|
182
1082
|
var queue = Promise.resolve();
|
|
183
1083
|
var timer;
|
|
184
1084
|
var getStorage = async () => storage ||= await createStorage();
|
|
1085
|
+
var recording = false;
|
|
1086
|
+
var captureError = "";
|
|
1087
|
+
var pending = 0;
|
|
1088
|
+
var writes = Promise.resolve();
|
|
1089
|
+
var report = (error) => {
|
|
1090
|
+
captureError = error instanceof Error ? error.message : String(error);
|
|
1091
|
+
recording = false;
|
|
1092
|
+
};
|
|
1093
|
+
var serializeMessage2 = createMessageSerializer();
|
|
1094
|
+
var proxies = createProxyRegistry({
|
|
1095
|
+
record(message) {
|
|
1096
|
+
if (!recording) return;
|
|
1097
|
+
if (pending >= 500) {
|
|
1098
|
+
report(new Error("Recording cannot keep up with worker messages"));
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
const data = serializeMessage2(message);
|
|
1102
|
+
pending++;
|
|
1103
|
+
const write = recorder.record("message", data).catch(report).finally(() => {
|
|
1104
|
+
pending--;
|
|
1105
|
+
});
|
|
1106
|
+
writes = Promise.all([writes, write]).then(() => {
|
|
1107
|
+
});
|
|
1108
|
+
},
|
|
1109
|
+
report
|
|
1110
|
+
});
|
|
185
1111
|
var commands = {
|
|
186
|
-
export: () =>
|
|
1112
|
+
export: async () => {
|
|
1113
|
+
await writes;
|
|
1114
|
+
return recorder.export();
|
|
1115
|
+
},
|
|
187
1116
|
flush: () => recorder.flush(),
|
|
188
1117
|
async load(source) {
|
|
189
1118
|
let session;
|
|
@@ -198,11 +1127,15 @@ var commands = {
|
|
|
198
1127
|
content = loadContent(session);
|
|
199
1128
|
return content.seek(0);
|
|
200
1129
|
},
|
|
1130
|
+
proxy: (port) => proxies.create(port),
|
|
201
1131
|
record: (...params) => recorder.record(...params),
|
|
202
1132
|
seek: (timestamp) => content.seek(timestamp),
|
|
203
|
-
async start(options) {
|
|
1133
|
+
async start(options, initialFrame) {
|
|
1134
|
+
if (recorder) throw new Error("Reload the window to start a new command recording");
|
|
204
1135
|
recorder = createRecorder({ storage: options.local ? await getStorage() : void 0 });
|
|
205
1136
|
const id = await recorder.start(options);
|
|
1137
|
+
if (initialFrame) await recorder.record("frame", { ...initialFrame, commandReplay: true });
|
|
1138
|
+
recording = true;
|
|
206
1139
|
clearInterval(timer);
|
|
207
1140
|
timer = setInterval(() => {
|
|
208
1141
|
void recorder.flush().catch(() => {
|
|
@@ -210,18 +1143,20 @@ var commands = {
|
|
|
210
1143
|
}, 2e3);
|
|
211
1144
|
return id;
|
|
212
1145
|
},
|
|
213
|
-
status: () => recorder.status(),
|
|
1146
|
+
status: () => ({ ...recorder.status(), error: captureError || recorder.status().error }),
|
|
214
1147
|
async stop() {
|
|
215
1148
|
clearInterval(timer);
|
|
1149
|
+
recording = false;
|
|
1150
|
+
await writes;
|
|
216
1151
|
await recorder?.flush();
|
|
217
|
-
storage?.close();
|
|
218
1152
|
}
|
|
219
1153
|
};
|
|
220
1154
|
globalThis.onmessage = ({ data: { id, method, params = [] } }) => {
|
|
221
1155
|
queue = queue.then(async () => {
|
|
222
1156
|
try {
|
|
223
1157
|
if (!Object.hasOwn(commands, method)) throw new Error("Unknown session replay command");
|
|
224
|
-
|
|
1158
|
+
const result = await commands[method](...params);
|
|
1159
|
+
globalThis.postMessage({ id, result }, { transfer: getTransferrables(result) });
|
|
225
1160
|
} catch (error) {
|
|
226
1161
|
globalThis.postMessage({ error: error instanceof Error ? error.message : String(error), id });
|
|
227
1162
|
}
|