@lvce-editor/renderer-process 30.57.2 → 30.58.1
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 +4145 -4151
- package/dist/sessionReplayWorkerMain.js +961 -12
- package/package.json +1 -1
|
@@ -1,3 +1,728 @@
|
|
|
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", "translate", "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 expandPatches = (patches) => patches.flatMap((value) => {
|
|
434
|
+
if (value.type !== 18) return [value];
|
|
435
|
+
const { navigations } = value;
|
|
436
|
+
if (!Array.isArray(navigations) || navigations.length % 2 !== 0) throw new Error("Invalid compact replay navigation");
|
|
437
|
+
const result = [];
|
|
438
|
+
for (let index = 0; index < navigations.length; index += 2) {
|
|
439
|
+
const type = navigations[index];
|
|
440
|
+
const childIndex = navigations[index + 1];
|
|
441
|
+
if (![7, 8, 10].includes(type) || !Number.isSafeInteger(childIndex) || childIndex < 0) throw new Error("Invalid compact replay navigation");
|
|
442
|
+
result.push({ ...value, index: childIndex, type });
|
|
443
|
+
}
|
|
444
|
+
return result;
|
|
445
|
+
});
|
|
446
|
+
var createVisualDom = () => {
|
|
447
|
+
const views = /* @__PURE__ */ new Map();
|
|
448
|
+
const parents = /* @__PURE__ */ new WeakMap();
|
|
449
|
+
const owners = /* @__PURE__ */ new WeakMap();
|
|
450
|
+
let nodeCount = 0;
|
|
451
|
+
const detach = (node) => {
|
|
452
|
+
const parent = parents.get(node);
|
|
453
|
+
if (parent) parent.children.splice(parent.children.indexOf(node), 1);
|
|
454
|
+
parents.delete(node);
|
|
455
|
+
};
|
|
456
|
+
const clear = (node) => {
|
|
457
|
+
while (node.children?.length) detach(node.children.at(0));
|
|
458
|
+
};
|
|
459
|
+
const append = (parent, node, index) => {
|
|
460
|
+
let depth = 0;
|
|
461
|
+
for (let ancestor = parent; ancestor; ancestor = parents.get(ancestor)) {
|
|
462
|
+
if (ancestor === node || ++depth > 150) throw new Error("Invalid replay DOM reference or depth");
|
|
463
|
+
}
|
|
464
|
+
const oldParent = parents.get(node);
|
|
465
|
+
const oldIndex = oldParent?.children?.indexOf(node);
|
|
466
|
+
if (oldParent === parent && index !== void 0 && oldIndex !== void 0 && oldIndex < index) index--;
|
|
467
|
+
detach(node);
|
|
468
|
+
parent.children ||= [];
|
|
469
|
+
parent.children.splice(index ?? parent.children.length, 0, node);
|
|
470
|
+
parents.set(node, parent);
|
|
471
|
+
};
|
|
472
|
+
const replace = (node, next) => {
|
|
473
|
+
if (node === next) return next;
|
|
474
|
+
const parent = parents.get(node);
|
|
475
|
+
const index = parent?.children.indexOf(node);
|
|
476
|
+
detach(node);
|
|
477
|
+
if (parent) append(parent, next, index);
|
|
478
|
+
const uid = owners.get(node);
|
|
479
|
+
if (uid !== void 0) {
|
|
480
|
+
views.set(uid, next);
|
|
481
|
+
owners.set(next, uid);
|
|
482
|
+
}
|
|
483
|
+
return next;
|
|
484
|
+
};
|
|
485
|
+
const renderNode = (value) => {
|
|
486
|
+
let node;
|
|
487
|
+
if (value.type === VirtualDomElements_exports.Reference) node = views.get(value.uid) || { text: "Reference node not found" };
|
|
488
|
+
else if (value.type === VirtualDomElements_exports.Text) node = { text: value.text };
|
|
489
|
+
else {
|
|
490
|
+
node = element(ElementTagMap_exports.getElementTag(value.type));
|
|
491
|
+
for (const [key, entry] of Object.entries(value)) property(node, key, entry);
|
|
492
|
+
}
|
|
493
|
+
return node;
|
|
494
|
+
};
|
|
495
|
+
const render = (nodes) => {
|
|
496
|
+
const roots = [];
|
|
497
|
+
const stack = [];
|
|
498
|
+
for (const value of nodes) {
|
|
499
|
+
if (++nodeCount > 2e6) throw new Error("Session replay DOM operation limit reached");
|
|
500
|
+
while (stack.at(-1)?.remaining === 0) stack.pop();
|
|
501
|
+
const node = renderNode(value);
|
|
502
|
+
const parent = stack.at(-1);
|
|
503
|
+
if (parent) {
|
|
504
|
+
append(parent.node, node);
|
|
505
|
+
parent.remaining--;
|
|
506
|
+
} else roots.push(node);
|
|
507
|
+
const childCount = value.childCount || 0;
|
|
508
|
+
if (!Number.isSafeInteger(childCount) || childCount < 0 || stack.length > 150) throw new Error("Invalid virtual DOM child count or depth");
|
|
509
|
+
if (childCount) stack.push({ node, remaining: childCount });
|
|
510
|
+
}
|
|
511
|
+
if (stack.some((entry) => entry.remaining !== 0)) throw new Error("Incomplete replay virtual DOM");
|
|
512
|
+
return roots;
|
|
513
|
+
};
|
|
514
|
+
const patch = (uid, input) => {
|
|
515
|
+
const patches = expandPatches(input);
|
|
516
|
+
let current = views.get(uid);
|
|
517
|
+
if (!current) return;
|
|
518
|
+
owners.set(current, uid);
|
|
519
|
+
const mutations = {
|
|
520
|
+
1: (node, value) => {
|
|
521
|
+
node.text = String(value.value);
|
|
522
|
+
return node;
|
|
523
|
+
},
|
|
524
|
+
10: (node, value) => parents.get(node)?.children?.[value.index],
|
|
525
|
+
11: (node, value) => {
|
|
526
|
+
const next = views.get(value.uid);
|
|
527
|
+
return next ? replace(node, next) : node;
|
|
528
|
+
},
|
|
529
|
+
2: (node, value) => {
|
|
530
|
+
const next = render(value.nodes)[0];
|
|
531
|
+
if (next) return replace(node, next);
|
|
532
|
+
detach(node);
|
|
533
|
+
return node;
|
|
534
|
+
},
|
|
535
|
+
3: (node, value) => {
|
|
536
|
+
property(node, value.key, value.value);
|
|
537
|
+
return node;
|
|
538
|
+
},
|
|
539
|
+
4: (node, value) => {
|
|
540
|
+
property(node, value.key, void 0);
|
|
541
|
+
return node;
|
|
542
|
+
},
|
|
543
|
+
6: (node, value) => {
|
|
544
|
+
const children = render(value.nodes);
|
|
545
|
+
for (const child of children) append(node, child);
|
|
546
|
+
return node;
|
|
547
|
+
},
|
|
548
|
+
7: (node, value) => node.children?.[value.index],
|
|
549
|
+
8: (node) => parents.get(node),
|
|
550
|
+
9: (node, value) => {
|
|
551
|
+
if (node.children?.[value.index]) detach(node.children[value.index]);
|
|
552
|
+
return node;
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
for (let index = 0; index < patches.length; index++) {
|
|
556
|
+
const value = patches[index];
|
|
557
|
+
if (value.type === 7 && value.index === current.children?.length && [2, 11].includes(patches[index + 1]?.type)) append(current, element());
|
|
558
|
+
if (!mutations[value.type]) continue;
|
|
559
|
+
current = mutations[value.type](current, value);
|
|
560
|
+
if (!current) return;
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
return { append, clear, detach, element, find, patch, property, render, replace, views };
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
// ../session-replay-worker/src/visualState.ts
|
|
567
|
+
var createVisualState = (initial) => {
|
|
568
|
+
const frame = structuredClone(initial);
|
|
569
|
+
const dom = createVisualDom();
|
|
570
|
+
const { append, clear, detach, element: element2, find: find2, patch, property: property2, render, replace, views } = dom;
|
|
571
|
+
const sheets = new Map((frame.styles || []).map((text, index) => [`initial-${index}`, text]));
|
|
572
|
+
const calls = /* @__PURE__ */ new Map();
|
|
573
|
+
const batches = /* @__PURE__ */ new Map();
|
|
574
|
+
const setDom = (uid, nodes) => {
|
|
575
|
+
const view = views.get(uid);
|
|
576
|
+
if (!view) return;
|
|
577
|
+
const next = render(nodes)[0];
|
|
578
|
+
if (next) {
|
|
579
|
+
replace(view, next);
|
|
580
|
+
views.set(uid, next);
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
const apply = (method, params = []) => {
|
|
584
|
+
if (method && Object.hasOwn(handlers, method)) handlers[method](...params);
|
|
585
|
+
};
|
|
586
|
+
const execute = (commands2) => {
|
|
587
|
+
for (const [method, ...params] of commands2) apply(method, params);
|
|
588
|
+
};
|
|
589
|
+
const commit = (uid, transaction) => {
|
|
590
|
+
const batch = batches.get(transaction);
|
|
591
|
+
if (!batch || batch.uid !== uid) return;
|
|
592
|
+
batch.committed = true;
|
|
593
|
+
for (const [key, pending2] of batches) {
|
|
594
|
+
if (pending2.uid !== uid) continue;
|
|
595
|
+
if (!pending2.committed) return;
|
|
596
|
+
execute(pending2.commands);
|
|
597
|
+
batches.delete(key);
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
const appendView = (uid, childId, references) => {
|
|
601
|
+
const view = views.get(uid);
|
|
602
|
+
const child = views.get(childId);
|
|
603
|
+
if (!view || !child) return;
|
|
604
|
+
const nextReferences = references?.slice(references.indexOf(childId) + 1) || [];
|
|
605
|
+
const next = nextReferences.map((id) => views.get(id)).find((node) => node && view.children?.includes(node));
|
|
606
|
+
append(view, child, next ? view.children.indexOf(next) : void 0);
|
|
607
|
+
};
|
|
608
|
+
const setProperty = (uid, selector, key, value) => {
|
|
609
|
+
const view = views.get(uid);
|
|
610
|
+
const node = view && find2(view, selector);
|
|
611
|
+
if (!node) return;
|
|
612
|
+
if (key === "textContent") {
|
|
613
|
+
clear(node);
|
|
614
|
+
append(node, { text: String(value) });
|
|
615
|
+
} else property2(node, key, value);
|
|
616
|
+
};
|
|
617
|
+
const setBounds = (uid, left, top, width, height) => {
|
|
618
|
+
const view = views.get(uid);
|
|
619
|
+
const bounds = Object.entries({ height, left, top, width });
|
|
620
|
+
for (const [key, value] of bounds) property2(view, key, value);
|
|
621
|
+
};
|
|
622
|
+
const setCss = (uid, text) => {
|
|
623
|
+
sheets.set(uid, text);
|
|
624
|
+
};
|
|
625
|
+
const create = (_id, uid = Number(_id)) => {
|
|
626
|
+
views.set(uid, element2());
|
|
627
|
+
};
|
|
628
|
+
const handlers = {
|
|
629
|
+
"Css.addCssStyleSheet": setCss,
|
|
630
|
+
"Css.removeCssStyleSheet": (uid) => {
|
|
631
|
+
sheets.delete(uid);
|
|
632
|
+
},
|
|
633
|
+
"Viewlet.addCss": setCss,
|
|
634
|
+
"Viewlet.append": appendView,
|
|
635
|
+
"Viewlet.appendToBody": (uid) => {
|
|
636
|
+
const view = views.get(uid);
|
|
637
|
+
if (view) append(frame.dom, view);
|
|
638
|
+
},
|
|
639
|
+
"Viewlet.appendToRoot": (uid, root) => {
|
|
640
|
+
const view = views.get(uid);
|
|
641
|
+
const parent = find2(frame.dom, `#${root}`);
|
|
642
|
+
if (view && parent) append(parent, view);
|
|
643
|
+
},
|
|
644
|
+
"Viewlet.commitPending": commit,
|
|
645
|
+
"Viewlet.create": create,
|
|
646
|
+
"Viewlet.createFunctionalRoot": create,
|
|
647
|
+
"Viewlet.createPlaceholder": (uid, parentId, top, left, width, height) => {
|
|
648
|
+
views.set(uid, element2());
|
|
649
|
+
property2(views.get(uid), "className", `Viewlet ${uid}`);
|
|
650
|
+
setBounds(uid, left, top, width, height);
|
|
651
|
+
appendView(parentId, uid);
|
|
652
|
+
},
|
|
653
|
+
"Viewlet.dispose": (uid) => {
|
|
654
|
+
const view = views.get(uid);
|
|
655
|
+
if (view) detach(view);
|
|
656
|
+
views.delete(uid);
|
|
657
|
+
sheets.delete(uid);
|
|
658
|
+
},
|
|
659
|
+
"Viewlet.executeCommands": execute,
|
|
660
|
+
"Viewlet.patchCss": (uid, start, count, replacement) => {
|
|
661
|
+
const text = sheets.get(uid);
|
|
662
|
+
if (typeof text === "string") sheets.set(uid, text.slice(0, start) + replacement + text.slice(start + count));
|
|
663
|
+
},
|
|
664
|
+
"Viewlet.replaceChildren": (uid, children) => {
|
|
665
|
+
const view = views.get(uid);
|
|
666
|
+
if (!view) return;
|
|
667
|
+
clear(view);
|
|
668
|
+
for (const id of children) {
|
|
669
|
+
const child = views.get(id);
|
|
670
|
+
if (child) append(view, child);
|
|
671
|
+
}
|
|
672
|
+
},
|
|
673
|
+
"Viewlet.scrollSelectorBy": (uid, selector, delta) => {
|
|
674
|
+
const view = views.get(uid);
|
|
675
|
+
const node = view && find2(view, selector);
|
|
676
|
+
if (node) property2(node, "scrollLeft", (node.scroll?.[0] || 0) + delta);
|
|
677
|
+
},
|
|
678
|
+
"Viewlet.sendMultiple": execute,
|
|
679
|
+
"Viewlet.setBounds": setBounds,
|
|
680
|
+
"Viewlet.setCheckBoxValue": (uid, name, value) => setProperty(uid, `[name="${name}"]`, "checked", value),
|
|
681
|
+
"Viewlet.setComponentDom": setDom,
|
|
682
|
+
"Viewlet.setCss": setCss,
|
|
683
|
+
"Viewlet.setDom": (uid, nodes) => {
|
|
684
|
+
const view = views.get(uid);
|
|
685
|
+
if (!view) return;
|
|
686
|
+
clear(view);
|
|
687
|
+
const children = render(nodes);
|
|
688
|
+
for (const child of children) append(view, child);
|
|
689
|
+
},
|
|
690
|
+
"Viewlet.setDom2": setDom,
|
|
691
|
+
"Viewlet.setInputValues": (uid, items) => {
|
|
692
|
+
for (const { name, value } of items) setProperty(uid, `[name="${name}"]`, "value", value);
|
|
693
|
+
},
|
|
694
|
+
"Viewlet.setPatches": (uid, patches) => {
|
|
695
|
+
if (patches.length === 1 && patches[0].type === 6) setDom(uid, patches[0].nodes);
|
|
696
|
+
else patch(uid, patches);
|
|
697
|
+
},
|
|
698
|
+
"Viewlet.setProperty": setProperty,
|
|
699
|
+
"Viewlet.setTreePatches": patch,
|
|
700
|
+
"Viewlet.setValueByName": (uid, name, value) => setProperty(uid, `[name="${name}"]`, "value", value),
|
|
701
|
+
"Viewlet.show": (uid) => {
|
|
702
|
+
const view = views.get(uid);
|
|
703
|
+
if (view) append(find2(frame.dom, "#Workbench") || frame.dom, view);
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
return {
|
|
707
|
+
accept(data) {
|
|
708
|
+
if (!data?.renderer || !data.message || typeof data.message !== "object") return;
|
|
709
|
+
const { connection, direction, message } = data;
|
|
710
|
+
const key = `${connection}:${message.id}`;
|
|
711
|
+
if (direction === "to-renderer") {
|
|
712
|
+
if (message.method === "Viewlet.queueCommands") calls.set(key, message.params);
|
|
713
|
+
else apply(message.method, message.params);
|
|
714
|
+
} else if (calls.has(key)) {
|
|
715
|
+
const [uid, commands2] = calls.get(key);
|
|
716
|
+
calls.delete(key);
|
|
717
|
+
if (Number.isSafeInteger(message.result)) batches.set(message.result, { commands: commands2, committed: false, uid });
|
|
718
|
+
}
|
|
719
|
+
},
|
|
720
|
+
frame() {
|
|
721
|
+
return { ...frame, styles: [...sheets.values()] };
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
};
|
|
725
|
+
|
|
1
726
|
// ../session-replay-worker/src/protocol.ts
|
|
2
727
|
var version = 1;
|
|
3
728
|
var maxEventBytes = 75e4;
|
|
@@ -23,8 +748,23 @@ var loadContent = (value) => {
|
|
|
23
748
|
const frames = session.events.filter((event) => event.type === "frame");
|
|
24
749
|
if (frames.length === 0) throw new Error("This session has no visual frames");
|
|
25
750
|
const duration = session.events.at(-1)?.timestamp || 0;
|
|
751
|
+
let visual = createVisualState(frames[0].data);
|
|
752
|
+
let eventIndex = 0;
|
|
753
|
+
let lastPosition = -1;
|
|
26
754
|
const seek = (timestamp) => {
|
|
27
755
|
const position = Math.max(0, Math.min(duration, timestamp || 0));
|
|
756
|
+
if (frames[0].data.commandReplay) {
|
|
757
|
+
if (position < lastPosition) {
|
|
758
|
+
visual = createVisualState(frames[0].data);
|
|
759
|
+
eventIndex = 0;
|
|
760
|
+
}
|
|
761
|
+
while (eventIndex < session.events.length && session.events[eventIndex].timestamp <= position) {
|
|
762
|
+
const event = session.events[eventIndex++];
|
|
763
|
+
if (event.type === "message") visual.accept(event.data);
|
|
764
|
+
}
|
|
765
|
+
lastPosition = position;
|
|
766
|
+
return { duration, frame: structuredClone(visual.frame()), position };
|
|
767
|
+
}
|
|
28
768
|
let low = 0;
|
|
29
769
|
let high = frames.length;
|
|
30
770
|
while (low < high) {
|
|
@@ -37,6 +777,87 @@ var loadContent = (value) => {
|
|
|
37
777
|
return { duration, seek };
|
|
38
778
|
};
|
|
39
779
|
|
|
780
|
+
// ../session-replay-worker/src/proxy.ts
|
|
781
|
+
var wrapPorts = (value, replacePort, seen = /* @__PURE__ */ new Map()) => {
|
|
782
|
+
if (!value || typeof value !== "object") return value;
|
|
783
|
+
if (seen.has(value)) return seen.get(value);
|
|
784
|
+
if (value instanceof MessagePort) {
|
|
785
|
+
const replacement = replacePort(value);
|
|
786
|
+
seen.set(value, replacement);
|
|
787
|
+
return replacement;
|
|
788
|
+
}
|
|
789
|
+
seen.set(value, value);
|
|
790
|
+
if (value instanceof Map) {
|
|
791
|
+
const entries = [...value];
|
|
792
|
+
value.clear();
|
|
793
|
+
for (const [key, entry] of entries) value.set(wrapPorts(key, replacePort, seen), wrapPorts(entry, replacePort, seen));
|
|
794
|
+
} else if (value instanceof Set) {
|
|
795
|
+
const entries = [...value];
|
|
796
|
+
value.clear();
|
|
797
|
+
for (const entry of entries) value.add(wrapPorts(entry, replacePort, seen));
|
|
798
|
+
} else if (Array.isArray(value) || Object.prototype.toString.call(value) === "[object Object]") {
|
|
799
|
+
const object = value;
|
|
800
|
+
for (const key of Object.keys(object)) object[key] = wrapPorts(object[key], replacePort, seen);
|
|
801
|
+
}
|
|
802
|
+
return value;
|
|
803
|
+
};
|
|
804
|
+
var createProxyRegistry = ({
|
|
805
|
+
record,
|
|
806
|
+
report: report2 = () => {
|
|
807
|
+
}
|
|
808
|
+
}) => {
|
|
809
|
+
const connections = /* @__PURE__ */ new Set();
|
|
810
|
+
let nextId = 0;
|
|
811
|
+
const createNestedPort = (connection, renderer, port) => create(port, `${connection}/port`, renderer);
|
|
812
|
+
const create = (port, label = "renderer", renderer = true) => {
|
|
813
|
+
const channel = new MessageChannel();
|
|
814
|
+
const peer = channel.port1;
|
|
815
|
+
const connection = ++nextId;
|
|
816
|
+
const close = () => {
|
|
817
|
+
for (const endpoint of [port, peer]) {
|
|
818
|
+
endpoint.removeEventListener("close", close);
|
|
819
|
+
endpoint.onmessage = null;
|
|
820
|
+
endpoint.onmessageerror = null;
|
|
821
|
+
endpoint.close();
|
|
822
|
+
}
|
|
823
|
+
connections.delete(close);
|
|
824
|
+
};
|
|
825
|
+
connections.add(close);
|
|
826
|
+
const ignoredReplies = { "from-renderer": /* @__PURE__ */ new Set(), "to-renderer": /* @__PURE__ */ new Set() };
|
|
827
|
+
const forward = (source, target, direction) => {
|
|
828
|
+
source.onmessage = ({ data }) => {
|
|
829
|
+
const opposite = direction === "to-renderer" ? "from-renderer" : "to-renderer";
|
|
830
|
+
const ignored = typeof data?.method === "string" && data.method.startsWith("SessionReplay.");
|
|
831
|
+
if (ignored && data.id !== void 0) ignoredReplies[opposite].add(data.id);
|
|
832
|
+
const ignoredReply = !data?.method && ignoredReplies[direction].delete(data?.id);
|
|
833
|
+
if (!ignored && !ignoredReply) {
|
|
834
|
+
try {
|
|
835
|
+
record({ connection, direction, label, message: data, renderer });
|
|
836
|
+
} catch (error) {
|
|
837
|
+
report2(error);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
const directRenderer = renderer && data?.method === "HandleMessagePort.handleMessagePort";
|
|
841
|
+
const message = wrapPorts(data, createNestedPort.bind(null, connection, directRenderer));
|
|
842
|
+
target.postMessage(message, getTransferrables(message));
|
|
843
|
+
if (data?.method === "Exit.exit") close();
|
|
844
|
+
};
|
|
845
|
+
source.onmessageerror = () => report2(new Error(`Cannot decode session replay proxy message (${connection})`));
|
|
846
|
+
source.addEventListener("close", close);
|
|
847
|
+
source.start();
|
|
848
|
+
};
|
|
849
|
+
forward(port, peer, "to-renderer");
|
|
850
|
+
forward(peer, port, "from-renderer");
|
|
851
|
+
return channel.port2;
|
|
852
|
+
};
|
|
853
|
+
return {
|
|
854
|
+
create,
|
|
855
|
+
dispose() {
|
|
856
|
+
for (const close of connections) close();
|
|
857
|
+
}
|
|
858
|
+
};
|
|
859
|
+
};
|
|
860
|
+
|
|
40
861
|
// ../session-replay-worker/src/recorder.ts
|
|
41
862
|
var createRecorder = ({
|
|
42
863
|
fetch: request = globalThis.fetch,
|
|
@@ -46,7 +867,7 @@ var createRecorder = ({
|
|
|
46
867
|
let metadata;
|
|
47
868
|
let options;
|
|
48
869
|
const events = [];
|
|
49
|
-
const
|
|
870
|
+
const pending2 = [];
|
|
50
871
|
let size = 0;
|
|
51
872
|
let origin = 0;
|
|
52
873
|
let remote;
|
|
@@ -70,14 +891,14 @@ var createRecorder = ({
|
|
|
70
891
|
throw new Error("Session replay storage limit reached; download this session and start a new one");
|
|
71
892
|
size += eventSize;
|
|
72
893
|
events.push(event);
|
|
73
|
-
if (options.upload)
|
|
894
|
+
if (options.upload) pending2.push(event);
|
|
74
895
|
if (options.local) {
|
|
75
896
|
await storage2.save(metadata, [event]);
|
|
76
897
|
saved++;
|
|
77
898
|
}
|
|
78
899
|
};
|
|
79
900
|
const doUpload = async () => {
|
|
80
|
-
if (!options?.upload ||
|
|
901
|
+
if (!options?.upload || pending2.length === 0) return;
|
|
81
902
|
const endpoint = new URL(options.endpoint);
|
|
82
903
|
if (!["https:", "http:"].includes(endpoint.protocol)) throw new Error("Invalid session replay backend URL");
|
|
83
904
|
const headers = { "Content-Type": "application/json", ...options.token && { Authorization: `Bearer ${options.token}` } };
|
|
@@ -93,10 +914,10 @@ var createRecorder = ({
|
|
|
93
914
|
return response.json();
|
|
94
915
|
};
|
|
95
916
|
if (!remote) remote = await send(endpoint, { createdAt: metadata.createdAt, version });
|
|
96
|
-
while (
|
|
917
|
+
while (pending2.length > 0) {
|
|
97
918
|
const batch = [];
|
|
98
919
|
let batchBytes = 0;
|
|
99
|
-
for (const event of
|
|
920
|
+
for (const event of pending2) {
|
|
100
921
|
const length = bytes(event);
|
|
101
922
|
if (batch.length > 0 && (batchBytes + length > 8e5 || batch.length >= 250)) break;
|
|
102
923
|
batch.push(event);
|
|
@@ -105,7 +926,7 @@ var createRecorder = ({
|
|
|
105
926
|
const url = new URL(endpoint);
|
|
106
927
|
url.pathname = `${url.pathname.replace(/\/$/, "")}/${encodeURIComponent(remote.id)}/events`;
|
|
107
928
|
await send(url, { events: batch, uploadToken: remote.uploadToken });
|
|
108
|
-
|
|
929
|
+
pending2.splice(0, batch.length);
|
|
109
930
|
uploaded += batch.length;
|
|
110
931
|
}
|
|
111
932
|
};
|
|
@@ -133,13 +954,106 @@ var createRecorder = ({
|
|
|
133
954
|
error: lastError,
|
|
134
955
|
events: events.length,
|
|
135
956
|
id: metadata?.id,
|
|
136
|
-
pending:
|
|
957
|
+
pending: pending2.length,
|
|
137
958
|
saved,
|
|
138
959
|
uploaded
|
|
139
960
|
})
|
|
140
961
|
};
|
|
141
962
|
};
|
|
142
963
|
|
|
964
|
+
// ../session-replay-worker/src/api/capture.ts
|
|
965
|
+
var serializeMessage = (message) => {
|
|
966
|
+
const ancestors = [];
|
|
967
|
+
let count = 0;
|
|
968
|
+
return JSON.parse(
|
|
969
|
+
JSON.stringify(message, function(key, value) {
|
|
970
|
+
if (++count > 2e5) throw new Error("Session replay message is too complex");
|
|
971
|
+
if (/password|token|secret|authorization|cookie/i.test(key)) return "[redacted]";
|
|
972
|
+
if (typeof value === "bigint") return String(value);
|
|
973
|
+
if (typeof value !== "object" || value === null) return value;
|
|
974
|
+
while (ancestors.length > 0 && ancestors.at(-1) !== this) ancestors.pop();
|
|
975
|
+
if (ancestors.includes(value)) return "[circular]";
|
|
976
|
+
ancestors.push(value);
|
|
977
|
+
if (value instanceof Error) return { message: value.message, name: value.name, stack: value.stack };
|
|
978
|
+
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) return { byteLength: value.byteLength, type: value.constructor.name };
|
|
979
|
+
if (value.constructor?.name === "MessagePort") return { type: "MessagePort" };
|
|
980
|
+
return value;
|
|
981
|
+
})
|
|
982
|
+
);
|
|
983
|
+
};
|
|
984
|
+
|
|
985
|
+
// ../session-replay-worker/src/serializeProxyMessage.ts
|
|
986
|
+
var redacted = "[redacted]";
|
|
987
|
+
var isMasked = (node) => node.inputType === "password" || Object.hasOwn(node, "data-session-replay-mask") || Object.hasOwn(node, "data-session-replay-ignore");
|
|
988
|
+
var structuralKeys = /* @__PURE__ */ new Set(["type", "childCount", "uid"]);
|
|
989
|
+
var redactNode = (node) => {
|
|
990
|
+
for (const key of Object.keys(node)) {
|
|
991
|
+
if (structuralKeys.has(key)) continue;
|
|
992
|
+
if (["text", "value", "textContent"].includes(key)) node[key] = redacted;
|
|
993
|
+
else if (key === "inputType" && node[key] === "password") continue;
|
|
994
|
+
else if (["data-session-replay-mask", "data-session-replay-ignore"].includes(key)) node[key] = "";
|
|
995
|
+
else delete node[key];
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
var redactUpdates = (method, params) => {
|
|
999
|
+
if (method === "Viewlet.setValueByName") params[2] = redacted;
|
|
1000
|
+
else if (method === "Viewlet.setProperty") params[3] = redacted;
|
|
1001
|
+
const updates = params[1];
|
|
1002
|
+
if (!Array.isArray(updates)) return;
|
|
1003
|
+
if (method === "Viewlet.setInputValues") for (const item of updates) item.value = redacted;
|
|
1004
|
+
if (!["Viewlet.setPatches", "Viewlet.setTreePatches"].includes(method)) return;
|
|
1005
|
+
for (const patch of updates) {
|
|
1006
|
+
if ([1, 3].includes(patch.type)) patch.value = redacted;
|
|
1007
|
+
}
|
|
1008
|
+
};
|
|
1009
|
+
var createMessageSerializer = () => {
|
|
1010
|
+
const maskedViews = /* @__PURE__ */ new Set();
|
|
1011
|
+
const sanitizeCommand = (method, params, masked) => {
|
|
1012
|
+
if (!method.startsWith("Viewlet.") || typeof params[0] !== "number") return;
|
|
1013
|
+
const uid = params[0];
|
|
1014
|
+
const patches = params[1];
|
|
1015
|
+
const masksInput = Array.isArray(patches) && patches.some((patch) => patch?.key === "inputType" && patch.value === "password");
|
|
1016
|
+
if (masked || masksInput) maskedViews.add(uid);
|
|
1017
|
+
if (maskedViews.has(uid)) redactUpdates(method, params);
|
|
1018
|
+
};
|
|
1019
|
+
const sanitizeArray = (array) => {
|
|
1020
|
+
let remaining = 0;
|
|
1021
|
+
let masked = false;
|
|
1022
|
+
for (const entry of array) {
|
|
1023
|
+
if (entry && typeof entry === "object" && !Array.isArray(entry)) {
|
|
1024
|
+
const node = entry;
|
|
1025
|
+
if (remaining > 0 || isMasked(node)) {
|
|
1026
|
+
remaining = Math.max(0, remaining - 1) + (typeof node.childCount === "number" ? node.childCount : 0);
|
|
1027
|
+
redactNode(node);
|
|
1028
|
+
masked = true;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
masked = sanitize(entry) || masked;
|
|
1032
|
+
}
|
|
1033
|
+
if (typeof array[0] === "string" && array[0].startsWith("Viewlet.")) {
|
|
1034
|
+
const params = array.slice(1);
|
|
1035
|
+
sanitizeCommand(array[0], params, masked);
|
|
1036
|
+
array.splice(1, array.length - 1, ...params);
|
|
1037
|
+
}
|
|
1038
|
+
return masked;
|
|
1039
|
+
};
|
|
1040
|
+
const sanitize = (value) => {
|
|
1041
|
+
if (!value || typeof value !== "object") return false;
|
|
1042
|
+
if (Array.isArray(value)) return sanitizeArray(value);
|
|
1043
|
+
const object = value;
|
|
1044
|
+
let masked = isMasked(object);
|
|
1045
|
+
if (masked) redactNode(object);
|
|
1046
|
+
for (const child of Object.values(object)) masked = sanitize(child) || masked;
|
|
1047
|
+
if (typeof object.method === "string" && Array.isArray(object.params)) sanitizeCommand(object.method, object.params, masked);
|
|
1048
|
+
return masked;
|
|
1049
|
+
};
|
|
1050
|
+
return (message) => {
|
|
1051
|
+
const result = serializeMessage(message);
|
|
1052
|
+
sanitize(result);
|
|
1053
|
+
return result;
|
|
1054
|
+
};
|
|
1055
|
+
};
|
|
1056
|
+
|
|
143
1057
|
// ../session-replay-worker/src/storage.ts
|
|
144
1058
|
var withoutSessionId = ({ sessionId, ...event }) => event;
|
|
145
1059
|
var open = () => new Promise((resolve, reject) => {
|
|
@@ -182,8 +1096,37 @@ var content;
|
|
|
182
1096
|
var queue = Promise.resolve();
|
|
183
1097
|
var timer;
|
|
184
1098
|
var getStorage = async () => storage ||= await createStorage();
|
|
1099
|
+
var recording = false;
|
|
1100
|
+
var captureError = "";
|
|
1101
|
+
var pending = 0;
|
|
1102
|
+
var writes = Promise.resolve();
|
|
1103
|
+
var report = (error) => {
|
|
1104
|
+
captureError = error instanceof Error ? error.message : String(error);
|
|
1105
|
+
recording = false;
|
|
1106
|
+
};
|
|
1107
|
+
var serializeMessage2 = createMessageSerializer();
|
|
1108
|
+
var proxies = createProxyRegistry({
|
|
1109
|
+
record(message) {
|
|
1110
|
+
if (!recording) return;
|
|
1111
|
+
if (pending >= 500) {
|
|
1112
|
+
report(new Error("Recording cannot keep up with worker messages"));
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
const data = serializeMessage2(message);
|
|
1116
|
+
pending++;
|
|
1117
|
+
const write = recorder.record("message", data).catch(report).finally(() => {
|
|
1118
|
+
pending--;
|
|
1119
|
+
});
|
|
1120
|
+
writes = Promise.all([writes, write]).then(() => {
|
|
1121
|
+
});
|
|
1122
|
+
},
|
|
1123
|
+
report
|
|
1124
|
+
});
|
|
185
1125
|
var commands = {
|
|
186
|
-
export: () =>
|
|
1126
|
+
export: async () => {
|
|
1127
|
+
await writes;
|
|
1128
|
+
return recorder.export();
|
|
1129
|
+
},
|
|
187
1130
|
flush: () => recorder.flush(),
|
|
188
1131
|
async load(source) {
|
|
189
1132
|
let session;
|
|
@@ -198,11 +1141,15 @@ var commands = {
|
|
|
198
1141
|
content = loadContent(session);
|
|
199
1142
|
return content.seek(0);
|
|
200
1143
|
},
|
|
1144
|
+
proxy: (port) => proxies.create(port),
|
|
201
1145
|
record: (...params) => recorder.record(...params),
|
|
202
1146
|
seek: (timestamp) => content.seek(timestamp),
|
|
203
|
-
async start(options) {
|
|
1147
|
+
async start(options, initialFrame) {
|
|
1148
|
+
if (recorder) throw new Error("Reload the window to start a new command recording");
|
|
204
1149
|
recorder = createRecorder({ storage: options.local ? await getStorage() : void 0 });
|
|
205
1150
|
const id = await recorder.start(options);
|
|
1151
|
+
if (initialFrame) await recorder.record("frame", { ...initialFrame, commandReplay: true });
|
|
1152
|
+
recording = true;
|
|
206
1153
|
clearInterval(timer);
|
|
207
1154
|
timer = setInterval(() => {
|
|
208
1155
|
void recorder.flush().catch(() => {
|
|
@@ -210,18 +1157,20 @@ var commands = {
|
|
|
210
1157
|
}, 2e3);
|
|
211
1158
|
return id;
|
|
212
1159
|
},
|
|
213
|
-
status: () => recorder.status(),
|
|
1160
|
+
status: () => ({ ...recorder.status(), error: captureError || recorder.status().error }),
|
|
214
1161
|
async stop() {
|
|
215
1162
|
clearInterval(timer);
|
|
1163
|
+
recording = false;
|
|
1164
|
+
await writes;
|
|
216
1165
|
await recorder?.flush();
|
|
217
|
-
storage?.close();
|
|
218
1166
|
}
|
|
219
1167
|
};
|
|
220
1168
|
globalThis.onmessage = ({ data: { id, method, params = [] } }) => {
|
|
221
1169
|
queue = queue.then(async () => {
|
|
222
1170
|
try {
|
|
223
1171
|
if (!Object.hasOwn(commands, method)) throw new Error("Unknown session replay command");
|
|
224
|
-
|
|
1172
|
+
const result = await commands[method](...params);
|
|
1173
|
+
globalThis.postMessage({ id, result }, { transfer: getTransferrables(result) });
|
|
225
1174
|
} catch (error) {
|
|
226
1175
|
globalThis.postMessage({ error: error instanceof Error ? error.message : String(error), id });
|
|
227
1176
|
}
|