@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.
@@ -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 pending = [];
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) pending.push(event);
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 || pending.length === 0) return;
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 (pending.length > 0) {
917
+ while (pending2.length > 0) {
97
918
  const batch = [];
98
919
  let batchBytes = 0;
99
- for (const event of pending) {
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
- pending.splice(0, batch.length);
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: pending.length,
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: () => recorder.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
- globalThis.postMessage({ id, result: await commands[method](...params) });
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
  }