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