electrobun 1.18.1 → 1.18.4-beta.5

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.
@@ -0,0 +1,913 @@
1
+ (function(){// src/bun/preload/encryption.ts
2
+ function base64ToUint8Array(base64) {
3
+ return new Uint8Array(atob(base64).split("").map((char) => char.charCodeAt(0)));
4
+ }
5
+ function uint8ArrayToBase64(uint8Array) {
6
+ let binary = "";
7
+ for (let i = 0;i < uint8Array.length; i++) {
8
+ binary += String.fromCharCode(uint8Array[i]);
9
+ }
10
+ return btoa(binary);
11
+ }
12
+ async function generateKeyFromBytes(rawKey) {
13
+ return await window.crypto.subtle.importKey("raw", rawKey, { name: "AES-GCM" }, true, ["encrypt", "decrypt"]);
14
+ }
15
+ async function initEncryption() {
16
+ const secretKey = await generateKeyFromBytes(new Uint8Array(window.__electrobunSecretKeyBytes));
17
+ const encryptString = async (plaintext) => {
18
+ const encoder = new TextEncoder;
19
+ const encodedText = encoder.encode(plaintext);
20
+ const iv = window.crypto.getRandomValues(new Uint8Array(12));
21
+ const encryptedBuffer = await window.crypto.subtle.encrypt({ name: "AES-GCM", iv }, secretKey, encodedText);
22
+ const encryptedData = new Uint8Array(encryptedBuffer.slice(0, -16));
23
+ const tag = new Uint8Array(encryptedBuffer.slice(-16));
24
+ return {
25
+ encryptedData: uint8ArrayToBase64(encryptedData),
26
+ iv: uint8ArrayToBase64(iv),
27
+ tag: uint8ArrayToBase64(tag)
28
+ };
29
+ };
30
+ const decryptString = async (encryptedDataB64, ivB64, tagB64) => {
31
+ const encryptedData = base64ToUint8Array(encryptedDataB64);
32
+ const iv = base64ToUint8Array(ivB64);
33
+ const tag = base64ToUint8Array(tagB64);
34
+ const combinedData = new Uint8Array(encryptedData.length + tag.length);
35
+ combinedData.set(encryptedData);
36
+ combinedData.set(tag, encryptedData.length);
37
+ const decryptedBuffer = await window.crypto.subtle.decrypt({ name: "AES-GCM", iv }, secretKey, combinedData);
38
+ const decoder = new TextDecoder;
39
+ return decoder.decode(decryptedBuffer);
40
+ };
41
+ window.__electrobun_encrypt = encryptString;
42
+ window.__electrobun_decrypt = decryptString;
43
+ }
44
+
45
+ // src/bun/preload/internalRpc.ts
46
+ var pendingRequests = {};
47
+ var requestId = 0;
48
+ var isProcessingQueue = false;
49
+ var sendQueue = [];
50
+ function processQueue() {
51
+ if (isProcessingQueue) {
52
+ setTimeout(processQueue);
53
+ return;
54
+ }
55
+ if (sendQueue.length === 0)
56
+ return;
57
+ isProcessingQueue = true;
58
+ const batch = JSON.stringify(sendQueue);
59
+ sendQueue.length = 0;
60
+ window.__electrobunInternalBridge?.postMessage(batch);
61
+ setTimeout(() => {
62
+ isProcessingQueue = false;
63
+ }, 2);
64
+ }
65
+ function send(type, payload) {
66
+ sendQueue.push(JSON.stringify({ type: "message", id: type, payload }));
67
+ processQueue();
68
+ }
69
+ function request(type, payload) {
70
+ return new Promise((resolve, reject) => {
71
+ const id = `req_${++requestId}_${Date.now()}`;
72
+ pendingRequests[id] = { resolve, reject };
73
+ sendQueue.push(JSON.stringify({
74
+ type: "request",
75
+ method: type,
76
+ id,
77
+ params: payload,
78
+ hostWebviewId: window.__electrobunWebviewId
79
+ }));
80
+ processQueue();
81
+ setTimeout(() => {
82
+ if (pendingRequests[id]) {
83
+ delete pendingRequests[id];
84
+ reject(new Error(`Request timeout: ${type}`));
85
+ }
86
+ }, 1e4);
87
+ });
88
+ }
89
+ function handleResponse(msg) {
90
+ if (msg && msg.type === "response" && msg.id) {
91
+ const pending = pendingRequests[msg.id];
92
+ if (pending) {
93
+ delete pendingRequests[msg.id];
94
+ if (msg.success)
95
+ pending.resolve(msg.payload);
96
+ else
97
+ pending.reject(msg.payload);
98
+ }
99
+ }
100
+ }
101
+
102
+ // src/bun/preload/dragRegions.ts
103
+ function isAppRegionDrag(e) {
104
+ const target = e.target;
105
+ if (!target || !target.closest)
106
+ return false;
107
+ if (target.closest(".electrobun-webkit-app-region-no-drag") || target.closest('[style*="app-region"][style*="no-drag"]')) {
108
+ return false;
109
+ }
110
+ const draggableByStyle = target.closest('[style*="app-region"][style*="drag"]');
111
+ const draggableByClass = target.closest(".electrobun-webkit-app-region-drag");
112
+ return !!(draggableByStyle || draggableByClass);
113
+ }
114
+ function initDragRegions() {
115
+ document.addEventListener("mousedown", (e) => {
116
+ if (isAppRegionDrag(e)) {
117
+ send("startWindowMove", { id: window.__electrobunWindowId });
118
+ }
119
+ });
120
+ document.addEventListener("mouseup", (e) => {
121
+ if (isAppRegionDrag(e)) {
122
+ send("stopWindowMove", { id: window.__electrobunWindowId });
123
+ }
124
+ });
125
+ }
126
+
127
+ // src/bun/preload/overlaySync.ts
128
+ class OverlaySyncController {
129
+ element;
130
+ options;
131
+ lastRect = { x: 0, y: 0, width: 0, height: 0 };
132
+ resizeObserver = null;
133
+ positionLoop = null;
134
+ resizeHandler = null;
135
+ burstUntil = 0;
136
+ constructor(element, options) {
137
+ this.element = element;
138
+ this.options = {
139
+ onSync: options.onSync,
140
+ getMasks: options.getMasks ?? (() => []),
141
+ burstIntervalMs: options.burstIntervalMs ?? 50,
142
+ baseIntervalMs: options.baseIntervalMs ?? 100,
143
+ burstDurationMs: options.burstDurationMs ?? 500
144
+ };
145
+ }
146
+ start() {
147
+ this.resizeObserver = new ResizeObserver(() => this.sync());
148
+ this.resizeObserver.observe(this.element);
149
+ const loop = () => {
150
+ this.sync();
151
+ const now = performance.now();
152
+ const interval = now < this.burstUntil ? this.options.burstIntervalMs : this.options.baseIntervalMs;
153
+ this.positionLoop = setTimeout(loop, interval);
154
+ };
155
+ this.positionLoop = setTimeout(loop, this.options.baseIntervalMs);
156
+ this.resizeHandler = () => this.sync(true);
157
+ window.addEventListener("resize", this.resizeHandler);
158
+ }
159
+ stop() {
160
+ if (this.resizeObserver)
161
+ this.resizeObserver.disconnect();
162
+ if (this.positionLoop)
163
+ clearTimeout(this.positionLoop);
164
+ if (this.resizeHandler) {
165
+ window.removeEventListener("resize", this.resizeHandler);
166
+ }
167
+ this.resizeObserver = null;
168
+ this.positionLoop = null;
169
+ this.resizeHandler = null;
170
+ }
171
+ forceSync() {
172
+ this.sync(true);
173
+ }
174
+ setLastRect(rect) {
175
+ this.lastRect = rect;
176
+ }
177
+ sync(force = false) {
178
+ const rect = this.element.getBoundingClientRect();
179
+ const newRect = {
180
+ x: rect.x,
181
+ y: rect.y,
182
+ width: rect.width,
183
+ height: rect.height
184
+ };
185
+ if (newRect.width === 0 && newRect.height === 0) {
186
+ return;
187
+ }
188
+ if (!force && newRect.x === this.lastRect.x && newRect.y === this.lastRect.y && newRect.width === this.lastRect.width && newRect.height === this.lastRect.height) {
189
+ return;
190
+ }
191
+ this.burstUntil = performance.now() + this.options.burstDurationMs;
192
+ this.lastRect = newRect;
193
+ const masks = this.options.getMasks();
194
+ this.options.onSync(newRect, JSON.stringify(masks));
195
+ }
196
+ }
197
+
198
+ // src/bun/preload/webviewTag.ts
199
+ var webviewRegistry = {};
200
+
201
+ class ElectrobunWebviewTag extends HTMLElement {
202
+ webviewId = null;
203
+ maskSelectors = new Set;
204
+ _sync = null;
205
+ transparent = false;
206
+ passthroughEnabled = false;
207
+ hidden = false;
208
+ sandboxed = false;
209
+ _eventListeners = {};
210
+ static get observedAttributes() {
211
+ return ["src", "html"];
212
+ }
213
+ constructor() {
214
+ super();
215
+ }
216
+ connectedCallback() {
217
+ requestAnimationFrame(() => this.initWebview());
218
+ }
219
+ attributeChangedCallback(name, oldValue, newValue) {
220
+ if (oldValue === newValue)
221
+ return;
222
+ if (newValue === null)
223
+ return;
224
+ if (this.webviewId === null)
225
+ return;
226
+ if (name === "src")
227
+ this.loadURL(newValue);
228
+ else if (name === "html")
229
+ this.loadHTML(newValue);
230
+ }
231
+ disconnectedCallback() {
232
+ if (this.webviewId !== null) {
233
+ send("webviewTagRemove", { id: this.webviewId });
234
+ delete webviewRegistry[this.webviewId];
235
+ }
236
+ if (this._sync)
237
+ this._sync.stop();
238
+ }
239
+ getInitialNavigationRules() {
240
+ const rawRules = this.getAttribute("navigation-rules");
241
+ if (rawRules === null) {
242
+ return null;
243
+ }
244
+ const trimmed = rawRules.trim();
245
+ if (!trimmed) {
246
+ return [];
247
+ }
248
+ try {
249
+ const parsed = JSON.parse(trimmed);
250
+ if (!Array.isArray(parsed) || !parsed.every((rule) => typeof rule === "string")) {
251
+ throw new Error("navigation-rules must be a JSON string array");
252
+ }
253
+ return parsed;
254
+ } catch (error) {
255
+ console.error("Invalid navigation-rules attribute:", error);
256
+ return [];
257
+ }
258
+ }
259
+ async initWebview() {
260
+ const rect = this.getBoundingClientRect();
261
+ const initialRect = {
262
+ x: rect.x,
263
+ y: rect.y,
264
+ width: rect.width,
265
+ height: rect.height
266
+ };
267
+ const url = this.getAttribute("src");
268
+ const html = this.getAttribute("html");
269
+ const preload = this.getAttribute("preload");
270
+ const partition = this.getAttribute("partition");
271
+ const renderer = this.getAttribute("renderer") || "native";
272
+ const masks = this.getAttribute("masks");
273
+ const navigationRules = this.getInitialNavigationRules();
274
+ const sandbox = this.hasAttribute("sandbox");
275
+ this.sandboxed = sandbox;
276
+ const transparent = this.hasAttribute("transparent");
277
+ const passthrough = this.hasAttribute("passthrough");
278
+ this.transparent = transparent;
279
+ this.passthroughEnabled = passthrough;
280
+ if (transparent)
281
+ this.style.opacity = "0";
282
+ if (passthrough)
283
+ this.style.pointerEvents = "none";
284
+ if (masks) {
285
+ masks.split(",").forEach((s) => this.maskSelectors.add(s.trim()));
286
+ }
287
+ try {
288
+ const webviewInitParams = {
289
+ hostWebviewId: window.__electrobunWebviewId,
290
+ windowId: window.__electrobunWindowId,
291
+ renderer,
292
+ url,
293
+ html,
294
+ preload,
295
+ partition,
296
+ frame: {
297
+ width: rect.width,
298
+ height: rect.height,
299
+ x: rect.x,
300
+ y: rect.y
301
+ },
302
+ sandbox,
303
+ transparent,
304
+ passthrough,
305
+ ...navigationRules === null ? {} : { navigationRules }
306
+ };
307
+ const webviewId = await request("webviewTagInit", webviewInitParams);
308
+ this.webviewId = webviewId;
309
+ this.id = `electrobun-webview-${webviewId}`;
310
+ webviewRegistry[webviewId] = this;
311
+ this.setupObservers(initialRect);
312
+ this.syncDimensions(true);
313
+ requestAnimationFrame(() => {
314
+ Object.values(webviewRegistry).forEach((webview) => {
315
+ if (webview !== this && webview.webviewId !== null) {
316
+ webview.syncDimensions(true);
317
+ }
318
+ });
319
+ });
320
+ } catch (err) {
321
+ console.error("Failed to init webview:", err);
322
+ }
323
+ }
324
+ setupObservers(initialRect) {
325
+ const getMasks = () => {
326
+ const rect = this.getBoundingClientRect();
327
+ const masks = [];
328
+ this.maskSelectors.forEach((selector) => {
329
+ try {
330
+ document.querySelectorAll(selector).forEach((el) => {
331
+ const mr = el.getBoundingClientRect();
332
+ masks.push({
333
+ x: mr.x - rect.x,
334
+ y: mr.y - rect.y,
335
+ width: mr.width,
336
+ height: mr.height
337
+ });
338
+ });
339
+ } catch (_e) {}
340
+ });
341
+ return masks;
342
+ };
343
+ this._sync = new OverlaySyncController(this, {
344
+ onSync: (rect, masksJson) => {
345
+ if (this.webviewId === null)
346
+ return;
347
+ send("webviewTagResize", {
348
+ id: this.webviewId,
349
+ frame: rect,
350
+ masks: masksJson
351
+ });
352
+ },
353
+ getMasks,
354
+ burstIntervalMs: 10,
355
+ baseIntervalMs: 100,
356
+ burstDurationMs: 50
357
+ });
358
+ this._sync.setLastRect(initialRect);
359
+ this._sync.start();
360
+ }
361
+ syncDimensions(force = false) {
362
+ if (!this._sync)
363
+ return;
364
+ if (force) {
365
+ this._sync.forceSync();
366
+ }
367
+ }
368
+ loadURL(url) {
369
+ if (this.webviewId === null)
370
+ return;
371
+ this.setAttribute("src", url);
372
+ send("webviewTagUpdateSrc", { id: this.webviewId, url });
373
+ }
374
+ loadHTML(html) {
375
+ if (this.webviewId === null)
376
+ return;
377
+ send("webviewTagUpdateHtml", { id: this.webviewId, html });
378
+ }
379
+ reload() {
380
+ if (this.webviewId !== null)
381
+ send("webviewTagReload", { id: this.webviewId });
382
+ }
383
+ goBack() {
384
+ if (this.webviewId !== null)
385
+ send("webviewTagGoBack", { id: this.webviewId });
386
+ }
387
+ goForward() {
388
+ if (this.webviewId !== null)
389
+ send("webviewTagGoForward", { id: this.webviewId });
390
+ }
391
+ async canGoBack() {
392
+ if (this.webviewId === null)
393
+ return false;
394
+ return await request("webviewTagCanGoBack", {
395
+ id: this.webviewId
396
+ });
397
+ }
398
+ async canGoForward() {
399
+ if (this.webviewId === null)
400
+ return false;
401
+ return await request("webviewTagCanGoForward", {
402
+ id: this.webviewId
403
+ });
404
+ }
405
+ toggleTransparent(value) {
406
+ if (this.webviewId === null)
407
+ return;
408
+ this.transparent = value !== undefined ? value : !this.transparent;
409
+ this.style.opacity = this.transparent ? "0" : "";
410
+ send("webviewTagSetTransparent", {
411
+ id: this.webviewId,
412
+ transparent: this.transparent
413
+ });
414
+ }
415
+ togglePassthrough(value) {
416
+ if (this.webviewId === null)
417
+ return;
418
+ this.passthroughEnabled = value !== undefined ? value : !this.passthroughEnabled;
419
+ this.style.pointerEvents = this.passthroughEnabled ? "none" : "";
420
+ send("webviewTagSetPassthrough", {
421
+ id: this.webviewId,
422
+ enablePassthrough: this.passthroughEnabled
423
+ });
424
+ }
425
+ toggleHidden(value) {
426
+ if (this.webviewId === null)
427
+ return;
428
+ this.hidden = value !== undefined ? value : !this.hidden;
429
+ send("webviewTagSetHidden", { id: this.webviewId, hidden: this.hidden });
430
+ }
431
+ addMaskSelector(selector) {
432
+ this.maskSelectors.add(selector);
433
+ this.syncDimensions(true);
434
+ }
435
+ removeMaskSelector(selector) {
436
+ this.maskSelectors.delete(selector);
437
+ this.syncDimensions(true);
438
+ }
439
+ setNavigationRules(rules) {
440
+ if (this.webviewId !== null) {
441
+ send("webviewTagSetNavigationRules", { id: this.webviewId, rules });
442
+ }
443
+ }
444
+ findInPage(searchText, options) {
445
+ if (this.webviewId === null)
446
+ return;
447
+ const forward = options?.forward !== false;
448
+ const matchCase = options?.matchCase || false;
449
+ send("webviewTagFindInPage", {
450
+ id: this.webviewId,
451
+ searchText,
452
+ forward,
453
+ matchCase
454
+ });
455
+ }
456
+ stopFindInPage() {
457
+ if (this.webviewId !== null)
458
+ send("webviewTagStopFind", { id: this.webviewId });
459
+ }
460
+ openDevTools() {
461
+ if (this.webviewId !== null)
462
+ send("webviewTagOpenDevTools", { id: this.webviewId });
463
+ }
464
+ closeDevTools() {
465
+ if (this.webviewId !== null)
466
+ send("webviewTagCloseDevTools", { id: this.webviewId });
467
+ }
468
+ toggleDevTools() {
469
+ if (this.webviewId !== null)
470
+ send("webviewTagToggleDevTools", { id: this.webviewId });
471
+ }
472
+ executeJavascript(js) {
473
+ if (this.webviewId === null)
474
+ return;
475
+ send("webviewTagExecuteJavascript", { id: this.webviewId, js });
476
+ }
477
+ on(event, listener) {
478
+ if (!this._eventListeners[event])
479
+ this._eventListeners[event] = [];
480
+ this._eventListeners[event].push(listener);
481
+ }
482
+ off(event, listener) {
483
+ if (!this._eventListeners[event])
484
+ return;
485
+ const idx = this._eventListeners[event].indexOf(listener);
486
+ if (idx !== -1)
487
+ this._eventListeners[event].splice(idx, 1);
488
+ }
489
+ emit(event, detail) {
490
+ const listeners = this._eventListeners[event];
491
+ if (listeners) {
492
+ const customEvent = new CustomEvent(event, { detail });
493
+ listeners.forEach((fn) => fn(customEvent));
494
+ }
495
+ }
496
+ get src() {
497
+ return this.getAttribute("src");
498
+ }
499
+ set src(value) {
500
+ if (value) {
501
+ this.setAttribute("src", value);
502
+ } else {
503
+ this.removeAttribute("src");
504
+ }
505
+ }
506
+ get html() {
507
+ return this.getAttribute("html");
508
+ }
509
+ set html(value) {
510
+ if (value) {
511
+ this.setAttribute("html", value);
512
+ } else {
513
+ this.removeAttribute("html");
514
+ }
515
+ }
516
+ get preload() {
517
+ return this.getAttribute("preload");
518
+ }
519
+ set preload(value) {
520
+ if (value)
521
+ this.setAttribute("preload", value);
522
+ else
523
+ this.removeAttribute("preload");
524
+ }
525
+ get renderer() {
526
+ return this.getAttribute("renderer") || "native";
527
+ }
528
+ set renderer(value) {
529
+ this.setAttribute("renderer", value);
530
+ }
531
+ get sandbox() {
532
+ return this.sandboxed;
533
+ }
534
+ }
535
+ function initWebviewTag() {
536
+ if (!customElements.get("electrobun-webview")) {
537
+ customElements.define("electrobun-webview", ElectrobunWebviewTag);
538
+ }
539
+ const injectStyles = () => {
540
+ const style = document.createElement("style");
541
+ style.textContent = `
542
+ electrobun-webview {
543
+ display: block;
544
+ width: 800px;
545
+ height: 300px;
546
+ background: #fff;
547
+ background-repeat: no-repeat !important;
548
+ overflow: hidden;
549
+ }
550
+ `;
551
+ if (document.head?.firstChild) {
552
+ document.head.insertBefore(style, document.head.firstChild);
553
+ } else if (document.head) {
554
+ document.head.appendChild(style);
555
+ }
556
+ };
557
+ if (document.head) {
558
+ injectStyles();
559
+ } else {
560
+ document.addEventListener("DOMContentLoaded", injectStyles);
561
+ }
562
+ }
563
+
564
+ // src/bun/preload/wgpuTag.ts
565
+ var wgpuTagRegistry = {};
566
+
567
+ class ElectrobunWgpuTag extends HTMLElement {
568
+ wgpuViewId = null;
569
+ maskSelectors = new Set;
570
+ _sync = null;
571
+ transparent = false;
572
+ passthroughEnabled = false;
573
+ hidden = false;
574
+ _eventListeners = {};
575
+ constructor() {
576
+ super();
577
+ }
578
+ connectedCallback() {
579
+ requestAnimationFrame(() => this.initWgpuView());
580
+ }
581
+ disconnectedCallback() {
582
+ if (this.wgpuViewId !== null) {
583
+ send("wgpuTagRemove", { id: this.wgpuViewId });
584
+ delete wgpuTagRegistry[this.wgpuViewId];
585
+ }
586
+ if (this._sync)
587
+ this._sync.stop();
588
+ }
589
+ async initWgpuView() {
590
+ const rect = this.getBoundingClientRect();
591
+ const initialRect = {
592
+ x: rect.x,
593
+ y: rect.y,
594
+ width: rect.width,
595
+ height: rect.height
596
+ };
597
+ const transparent = this.hasAttribute("transparent");
598
+ const passthrough = this.hasAttribute("passthrough");
599
+ const hidden = this.hasAttribute("hidden");
600
+ const masks = this.getAttribute("masks");
601
+ this.transparent = transparent;
602
+ this.passthroughEnabled = passthrough;
603
+ this.hidden = hidden;
604
+ if (masks) {
605
+ masks.split(",").forEach((s) => this.maskSelectors.add(s.trim()));
606
+ }
607
+ if (transparent)
608
+ this.style.opacity = "0";
609
+ if (passthrough)
610
+ this.style.pointerEvents = "none";
611
+ try {
612
+ const wgpuViewId = await request("wgpuTagInit", {
613
+ windowId: window.__electrobunWindowId,
614
+ frame: {
615
+ width: rect.width,
616
+ height: rect.height,
617
+ x: rect.x,
618
+ y: rect.y
619
+ },
620
+ transparent,
621
+ passthrough
622
+ });
623
+ this.wgpuViewId = wgpuViewId;
624
+ this.id = `electrobun-wgpu-${wgpuViewId}`;
625
+ wgpuTagRegistry[wgpuViewId] = this;
626
+ this.setupObservers(initialRect);
627
+ this.syncDimensions(true);
628
+ if (hidden) {
629
+ this.toggleHidden(true);
630
+ }
631
+ requestAnimationFrame(() => {
632
+ Object.values(wgpuTagRegistry).forEach((view) => {
633
+ if (view !== this && view.wgpuViewId !== null) {
634
+ view.syncDimensions(true);
635
+ }
636
+ });
637
+ });
638
+ this.emit("ready", { id: wgpuViewId });
639
+ } catch (err) {
640
+ console.error("Failed to init WGPU view:", err);
641
+ }
642
+ }
643
+ setupObservers(initialRect) {
644
+ const getMasks = () => {
645
+ const rect = this.getBoundingClientRect();
646
+ const masks = [];
647
+ this.maskSelectors.forEach((selector) => {
648
+ try {
649
+ document.querySelectorAll(selector).forEach((el) => {
650
+ const mr = el.getBoundingClientRect();
651
+ masks.push({
652
+ x: mr.x - rect.x,
653
+ y: mr.y - rect.y,
654
+ width: mr.width,
655
+ height: mr.height
656
+ });
657
+ });
658
+ } catch (_e) {}
659
+ });
660
+ return masks;
661
+ };
662
+ this._sync = new OverlaySyncController(this, {
663
+ onSync: (rect, masksJson) => {
664
+ if (this.wgpuViewId === null)
665
+ return;
666
+ send("wgpuTagResize", {
667
+ id: this.wgpuViewId,
668
+ frame: rect,
669
+ masks: masksJson
670
+ });
671
+ },
672
+ getMasks,
673
+ burstIntervalMs: 10,
674
+ baseIntervalMs: 100,
675
+ burstDurationMs: 50
676
+ });
677
+ this._sync.setLastRect(initialRect);
678
+ this._sync.start();
679
+ }
680
+ syncDimensions(force = false) {
681
+ if (!this._sync)
682
+ return;
683
+ if (force) {
684
+ this._sync.forceSync();
685
+ }
686
+ }
687
+ toggleTransparent(value) {
688
+ if (this.wgpuViewId === null)
689
+ return;
690
+ this.transparent = value !== undefined ? value : !this.transparent;
691
+ this.style.opacity = this.transparent ? "0" : "";
692
+ send("wgpuTagSetTransparent", {
693
+ id: this.wgpuViewId,
694
+ transparent: this.transparent
695
+ });
696
+ }
697
+ togglePassthrough(value) {
698
+ if (this.wgpuViewId === null)
699
+ return;
700
+ this.passthroughEnabled = value !== undefined ? value : !this.passthroughEnabled;
701
+ this.style.pointerEvents = this.passthroughEnabled ? "none" : "";
702
+ send("wgpuTagSetPassthrough", {
703
+ id: this.wgpuViewId,
704
+ passthrough: this.passthroughEnabled
705
+ });
706
+ }
707
+ toggleHidden(value) {
708
+ if (this.wgpuViewId === null)
709
+ return;
710
+ this.hidden = value !== undefined ? value : !this.hidden;
711
+ send("wgpuTagSetHidden", { id: this.wgpuViewId, hidden: this.hidden });
712
+ }
713
+ runTest() {
714
+ if (this.wgpuViewId === null)
715
+ return;
716
+ send("wgpuTagRunTest", { id: this.wgpuViewId });
717
+ }
718
+ addMaskSelector(selector) {
719
+ this.maskSelectors.add(selector);
720
+ this.syncDimensions(true);
721
+ }
722
+ removeMaskSelector(selector) {
723
+ this.maskSelectors.delete(selector);
724
+ this.syncDimensions(true);
725
+ }
726
+ on(event, listener) {
727
+ if (!this._eventListeners[event])
728
+ this._eventListeners[event] = [];
729
+ this._eventListeners[event].push(listener);
730
+ }
731
+ off(event, listener) {
732
+ if (!this._eventListeners[event])
733
+ return;
734
+ const idx = this._eventListeners[event].indexOf(listener);
735
+ if (idx !== -1)
736
+ this._eventListeners[event].splice(idx, 1);
737
+ }
738
+ emit(event, detail) {
739
+ const listeners = this._eventListeners[event];
740
+ if (listeners) {
741
+ const customEvent = new CustomEvent(event, { detail });
742
+ listeners.forEach((fn) => fn(customEvent));
743
+ }
744
+ }
745
+ }
746
+ function initWgpuTag() {
747
+ if (!customElements.get("electrobun-wgpu")) {
748
+ customElements.define("electrobun-wgpu", ElectrobunWgpuTag);
749
+ }
750
+ const injectStyles = () => {
751
+ const style = document.createElement("style");
752
+ style.textContent = `
753
+ electrobun-wgpu {
754
+ display: block;
755
+ width: 800px;
756
+ height: 300px;
757
+ background: #000;
758
+ overflow: hidden;
759
+ }
760
+ `;
761
+ if (document.head?.firstChild) {
762
+ document.head.insertBefore(style, document.head.firstChild);
763
+ } else if (document.head) {
764
+ document.head.appendChild(style);
765
+ }
766
+ };
767
+ if (document.head) {
768
+ injectStyles();
769
+ } else {
770
+ document.addEventListener("DOMContentLoaded", injectStyles);
771
+ }
772
+ }
773
+
774
+ // src/bun/preload/events.ts
775
+ function emitWebviewEvent(eventName, detail) {
776
+ setTimeout(() => {
777
+ const bridge = window.__electrobunEventBridge || window.__electrobunInternalBridge;
778
+ bridge?.postMessage(JSON.stringify({
779
+ id: "webviewEvent",
780
+ type: "message",
781
+ payload: {
782
+ id: window.__electrobunWebviewId,
783
+ eventName,
784
+ detail
785
+ }
786
+ }));
787
+ });
788
+ }
789
+ function initLifecycleEvents() {
790
+ window.addEventListener("load", () => {
791
+ if (window === window.top) {
792
+ emitWebviewEvent("dom-ready", document.location.href);
793
+ }
794
+ });
795
+ window.addEventListener("popstate", () => {
796
+ emitWebviewEvent("did-navigate-in-page", window.location.href);
797
+ });
798
+ window.addEventListener("hashchange", () => {
799
+ emitWebviewEvent("did-navigate-in-page", window.location.href);
800
+ });
801
+ }
802
+ var cmdKeyHeld = false;
803
+ var cmdKeyTimestamp = 0;
804
+ var CMD_KEY_THRESHOLD_MS = 500;
805
+ function isCmdHeld() {
806
+ if (cmdKeyHeld)
807
+ return true;
808
+ return Date.now() - cmdKeyTimestamp < CMD_KEY_THRESHOLD_MS && cmdKeyTimestamp > 0;
809
+ }
810
+ function initCmdClickHandling() {
811
+ window.addEventListener("keydown", (event) => {
812
+ if (event.key === "Meta" || event.metaKey) {
813
+ cmdKeyHeld = true;
814
+ cmdKeyTimestamp = Date.now();
815
+ }
816
+ }, true);
817
+ window.addEventListener("keyup", (event) => {
818
+ if (event.key === "Meta") {
819
+ cmdKeyHeld = false;
820
+ cmdKeyTimestamp = Date.now();
821
+ }
822
+ }, true);
823
+ window.addEventListener("blur", () => {
824
+ cmdKeyHeld = false;
825
+ });
826
+ window.addEventListener("click", (event) => {
827
+ if (event.metaKey || event.ctrlKey) {
828
+ const anchor = event.target?.closest?.("a");
829
+ if (anchor && anchor.href) {
830
+ event.preventDefault();
831
+ event.stopPropagation();
832
+ event.stopImmediatePropagation();
833
+ emitWebviewEvent("new-window-open", JSON.stringify({
834
+ url: anchor.href,
835
+ isCmdClick: true,
836
+ isSPANavigation: false
837
+ }));
838
+ }
839
+ }
840
+ }, true);
841
+ }
842
+ function initSPANavigationInterception() {
843
+ const originalPushState = history.pushState;
844
+ const originalReplaceState = history.replaceState;
845
+ history.pushState = function(state, title, url) {
846
+ if (isCmdHeld() && url) {
847
+ const resolvedUrl = new URL(String(url), window.location.href).href;
848
+ emitWebviewEvent("new-window-open", JSON.stringify({
849
+ url: resolvedUrl,
850
+ isCmdClick: true,
851
+ isSPANavigation: true
852
+ }));
853
+ return;
854
+ }
855
+ return originalPushState.apply(this, [state, title, url]);
856
+ };
857
+ history.replaceState = function(state, title, url) {
858
+ if (isCmdHeld() && url) {
859
+ const resolvedUrl = new URL(String(url), window.location.href).href;
860
+ emitWebviewEvent("new-window-open", JSON.stringify({
861
+ url: resolvedUrl,
862
+ isCmdClick: true,
863
+ isSPANavigation: true
864
+ }));
865
+ return;
866
+ }
867
+ return originalReplaceState.apply(this, [state, title, url]);
868
+ };
869
+ }
870
+ function initOverscrollPrevention() {
871
+ document.addEventListener("DOMContentLoaded", () => {
872
+ const style = document.createElement("style");
873
+ style.type = "text/css";
874
+ style.appendChild(document.createTextNode("html, body { overscroll-behavior: none; }"));
875
+ document.head.appendChild(style);
876
+ });
877
+ }
878
+
879
+ // src/bun/preload/index.ts
880
+ initEncryption().catch((err) => console.error("Failed to initialize encryption:", err));
881
+ var internalMessageHandler = (msg) => {
882
+ handleResponse(msg);
883
+ };
884
+ var defaultUserMessageHandler = (msg) => {
885
+ if (!window.__electrobunPendingHostMessages) {
886
+ window.__electrobunPendingHostMessages = [];
887
+ }
888
+ window.__electrobunPendingHostMessages.push(msg);
889
+ };
890
+ if (!window.__electrobun) {
891
+ window.__electrobun = {
892
+ receiveInternalMessageFromHost: internalMessageHandler,
893
+ receiveMessageFromHost: defaultUserMessageHandler,
894
+ receiveInternalMessageFromBun: internalMessageHandler,
895
+ receiveMessageFromBun: defaultUserMessageHandler
896
+ };
897
+ } else {
898
+ window.__electrobun.receiveInternalMessageFromHost = internalMessageHandler;
899
+ window.__electrobun.receiveMessageFromHost = defaultUserMessageHandler;
900
+ window.__electrobun.receiveInternalMessageFromBun = internalMessageHandler;
901
+ window.__electrobun.receiveMessageFromBun = defaultUserMessageHandler;
902
+ }
903
+ window.__electrobunSendToHost = (message) => {
904
+ emitWebviewEvent("host-message", JSON.stringify(message));
905
+ };
906
+ initLifecycleEvents();
907
+ initCmdClickHandling();
908
+ initSPANavigationInterception();
909
+ initOverscrollPrevention();
910
+ initDragRegions();
911
+ initWebviewTag();
912
+ initWgpuTag();
913
+ })();