electrobun 1.18.1 → 1.18.4-beta.3

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,885 @@
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
+ async initWebview() {
240
+ const rect = this.getBoundingClientRect();
241
+ const initialRect = {
242
+ x: rect.x,
243
+ y: rect.y,
244
+ width: rect.width,
245
+ height: rect.height
246
+ };
247
+ const url = this.getAttribute("src");
248
+ const html = this.getAttribute("html");
249
+ const preload = this.getAttribute("preload");
250
+ const partition = this.getAttribute("partition");
251
+ const renderer = this.getAttribute("renderer") || "native";
252
+ const masks = this.getAttribute("masks");
253
+ const sandbox = this.hasAttribute("sandbox");
254
+ this.sandboxed = sandbox;
255
+ const transparent = this.hasAttribute("transparent");
256
+ const passthrough = this.hasAttribute("passthrough");
257
+ this.transparent = transparent;
258
+ this.passthroughEnabled = passthrough;
259
+ if (transparent)
260
+ this.style.opacity = "0";
261
+ if (passthrough)
262
+ this.style.pointerEvents = "none";
263
+ if (masks) {
264
+ masks.split(",").forEach((s) => this.maskSelectors.add(s.trim()));
265
+ }
266
+ try {
267
+ const webviewId = await request("webviewTagInit", {
268
+ hostWebviewId: window.__electrobunWebviewId,
269
+ windowId: window.__electrobunWindowId,
270
+ renderer,
271
+ url,
272
+ html,
273
+ preload,
274
+ partition,
275
+ frame: {
276
+ width: rect.width,
277
+ height: rect.height,
278
+ x: rect.x,
279
+ y: rect.y
280
+ },
281
+ navigationRules: null,
282
+ sandbox,
283
+ transparent,
284
+ passthrough
285
+ });
286
+ this.webviewId = webviewId;
287
+ this.id = `electrobun-webview-${webviewId}`;
288
+ webviewRegistry[webviewId] = this;
289
+ this.setupObservers(initialRect);
290
+ this.syncDimensions(true);
291
+ requestAnimationFrame(() => {
292
+ Object.values(webviewRegistry).forEach((webview) => {
293
+ if (webview !== this && webview.webviewId !== null) {
294
+ webview.syncDimensions(true);
295
+ }
296
+ });
297
+ });
298
+ } catch (err) {
299
+ console.error("Failed to init webview:", err);
300
+ }
301
+ }
302
+ setupObservers(initialRect) {
303
+ const getMasks = () => {
304
+ const rect = this.getBoundingClientRect();
305
+ const masks = [];
306
+ this.maskSelectors.forEach((selector) => {
307
+ try {
308
+ document.querySelectorAll(selector).forEach((el) => {
309
+ const mr = el.getBoundingClientRect();
310
+ masks.push({
311
+ x: mr.x - rect.x,
312
+ y: mr.y - rect.y,
313
+ width: mr.width,
314
+ height: mr.height
315
+ });
316
+ });
317
+ } catch (_e) {}
318
+ });
319
+ return masks;
320
+ };
321
+ this._sync = new OverlaySyncController(this, {
322
+ onSync: (rect, masksJson) => {
323
+ if (this.webviewId === null)
324
+ return;
325
+ send("webviewTagResize", {
326
+ id: this.webviewId,
327
+ frame: rect,
328
+ masks: masksJson
329
+ });
330
+ },
331
+ getMasks,
332
+ burstIntervalMs: 10,
333
+ baseIntervalMs: 100,
334
+ burstDurationMs: 50
335
+ });
336
+ this._sync.setLastRect(initialRect);
337
+ this._sync.start();
338
+ }
339
+ syncDimensions(force = false) {
340
+ if (!this._sync)
341
+ return;
342
+ if (force) {
343
+ this._sync.forceSync();
344
+ }
345
+ }
346
+ loadURL(url) {
347
+ if (this.webviewId === null)
348
+ return;
349
+ this.setAttribute("src", url);
350
+ send("webviewTagUpdateSrc", { id: this.webviewId, url });
351
+ }
352
+ loadHTML(html) {
353
+ if (this.webviewId === null)
354
+ return;
355
+ send("webviewTagUpdateHtml", { id: this.webviewId, html });
356
+ }
357
+ reload() {
358
+ if (this.webviewId !== null)
359
+ send("webviewTagReload", { id: this.webviewId });
360
+ }
361
+ goBack() {
362
+ if (this.webviewId !== null)
363
+ send("webviewTagGoBack", { id: this.webviewId });
364
+ }
365
+ goForward() {
366
+ if (this.webviewId !== null)
367
+ send("webviewTagGoForward", { id: this.webviewId });
368
+ }
369
+ async canGoBack() {
370
+ if (this.webviewId === null)
371
+ return false;
372
+ return await request("webviewTagCanGoBack", {
373
+ id: this.webviewId
374
+ });
375
+ }
376
+ async canGoForward() {
377
+ if (this.webviewId === null)
378
+ return false;
379
+ return await request("webviewTagCanGoForward", {
380
+ id: this.webviewId
381
+ });
382
+ }
383
+ toggleTransparent(value) {
384
+ if (this.webviewId === null)
385
+ return;
386
+ this.transparent = value !== undefined ? value : !this.transparent;
387
+ this.style.opacity = this.transparent ? "0" : "";
388
+ send("webviewTagSetTransparent", {
389
+ id: this.webviewId,
390
+ transparent: this.transparent
391
+ });
392
+ }
393
+ togglePassthrough(value) {
394
+ if (this.webviewId === null)
395
+ return;
396
+ this.passthroughEnabled = value !== undefined ? value : !this.passthroughEnabled;
397
+ this.style.pointerEvents = this.passthroughEnabled ? "none" : "";
398
+ send("webviewTagSetPassthrough", {
399
+ id: this.webviewId,
400
+ enablePassthrough: this.passthroughEnabled
401
+ });
402
+ }
403
+ toggleHidden(value) {
404
+ if (this.webviewId === null)
405
+ return;
406
+ this.hidden = value !== undefined ? value : !this.hidden;
407
+ send("webviewTagSetHidden", { id: this.webviewId, hidden: this.hidden });
408
+ }
409
+ addMaskSelector(selector) {
410
+ this.maskSelectors.add(selector);
411
+ this.syncDimensions(true);
412
+ }
413
+ removeMaskSelector(selector) {
414
+ this.maskSelectors.delete(selector);
415
+ this.syncDimensions(true);
416
+ }
417
+ setNavigationRules(rules) {
418
+ if (this.webviewId !== null) {
419
+ send("webviewTagSetNavigationRules", { id: this.webviewId, rules });
420
+ }
421
+ }
422
+ findInPage(searchText, options) {
423
+ if (this.webviewId === null)
424
+ return;
425
+ const forward = options?.forward !== false;
426
+ const matchCase = options?.matchCase || false;
427
+ send("webviewTagFindInPage", {
428
+ id: this.webviewId,
429
+ searchText,
430
+ forward,
431
+ matchCase
432
+ });
433
+ }
434
+ stopFindInPage() {
435
+ if (this.webviewId !== null)
436
+ send("webviewTagStopFind", { id: this.webviewId });
437
+ }
438
+ openDevTools() {
439
+ if (this.webviewId !== null)
440
+ send("webviewTagOpenDevTools", { id: this.webviewId });
441
+ }
442
+ closeDevTools() {
443
+ if (this.webviewId !== null)
444
+ send("webviewTagCloseDevTools", { id: this.webviewId });
445
+ }
446
+ toggleDevTools() {
447
+ if (this.webviewId !== null)
448
+ send("webviewTagToggleDevTools", { id: this.webviewId });
449
+ }
450
+ executeJavascript(js) {
451
+ if (this.webviewId === null)
452
+ return;
453
+ send("webviewTagExecuteJavascript", { id: this.webviewId, js });
454
+ }
455
+ on(event, listener) {
456
+ if (!this._eventListeners[event])
457
+ this._eventListeners[event] = [];
458
+ this._eventListeners[event].push(listener);
459
+ }
460
+ off(event, listener) {
461
+ if (!this._eventListeners[event])
462
+ return;
463
+ const idx = this._eventListeners[event].indexOf(listener);
464
+ if (idx !== -1)
465
+ this._eventListeners[event].splice(idx, 1);
466
+ }
467
+ emit(event, detail) {
468
+ const listeners = this._eventListeners[event];
469
+ if (listeners) {
470
+ const customEvent = new CustomEvent(event, { detail });
471
+ listeners.forEach((fn) => fn(customEvent));
472
+ }
473
+ }
474
+ get src() {
475
+ return this.getAttribute("src");
476
+ }
477
+ set src(value) {
478
+ if (value) {
479
+ this.setAttribute("src", value);
480
+ } else {
481
+ this.removeAttribute("src");
482
+ }
483
+ }
484
+ get html() {
485
+ return this.getAttribute("html");
486
+ }
487
+ set html(value) {
488
+ if (value) {
489
+ this.setAttribute("html", value);
490
+ } else {
491
+ this.removeAttribute("html");
492
+ }
493
+ }
494
+ get preload() {
495
+ return this.getAttribute("preload");
496
+ }
497
+ set preload(value) {
498
+ if (value)
499
+ this.setAttribute("preload", value);
500
+ else
501
+ this.removeAttribute("preload");
502
+ }
503
+ get renderer() {
504
+ return this.getAttribute("renderer") || "native";
505
+ }
506
+ set renderer(value) {
507
+ this.setAttribute("renderer", value);
508
+ }
509
+ get sandbox() {
510
+ return this.sandboxed;
511
+ }
512
+ }
513
+ function initWebviewTag() {
514
+ if (!customElements.get("electrobun-webview")) {
515
+ customElements.define("electrobun-webview", ElectrobunWebviewTag);
516
+ }
517
+ const injectStyles = () => {
518
+ const style = document.createElement("style");
519
+ style.textContent = `
520
+ electrobun-webview {
521
+ display: block;
522
+ width: 800px;
523
+ height: 300px;
524
+ background: #fff;
525
+ background-repeat: no-repeat !important;
526
+ overflow: hidden;
527
+ }
528
+ `;
529
+ if (document.head?.firstChild) {
530
+ document.head.insertBefore(style, document.head.firstChild);
531
+ } else if (document.head) {
532
+ document.head.appendChild(style);
533
+ }
534
+ };
535
+ if (document.head) {
536
+ injectStyles();
537
+ } else {
538
+ document.addEventListener("DOMContentLoaded", injectStyles);
539
+ }
540
+ }
541
+
542
+ // src/bun/preload/wgpuTag.ts
543
+ var wgpuTagRegistry = {};
544
+
545
+ class ElectrobunWgpuTag extends HTMLElement {
546
+ wgpuViewId = null;
547
+ maskSelectors = new Set;
548
+ _sync = null;
549
+ transparent = false;
550
+ passthroughEnabled = false;
551
+ hidden = false;
552
+ _eventListeners = {};
553
+ constructor() {
554
+ super();
555
+ }
556
+ connectedCallback() {
557
+ requestAnimationFrame(() => this.initWgpuView());
558
+ }
559
+ disconnectedCallback() {
560
+ if (this.wgpuViewId !== null) {
561
+ send("wgpuTagRemove", { id: this.wgpuViewId });
562
+ delete wgpuTagRegistry[this.wgpuViewId];
563
+ }
564
+ if (this._sync)
565
+ this._sync.stop();
566
+ }
567
+ async initWgpuView() {
568
+ const rect = this.getBoundingClientRect();
569
+ const initialRect = {
570
+ x: rect.x,
571
+ y: rect.y,
572
+ width: rect.width,
573
+ height: rect.height
574
+ };
575
+ const transparent = this.hasAttribute("transparent");
576
+ const passthrough = this.hasAttribute("passthrough");
577
+ const hidden = this.hasAttribute("hidden");
578
+ const masks = this.getAttribute("masks");
579
+ this.transparent = transparent;
580
+ this.passthroughEnabled = passthrough;
581
+ this.hidden = hidden;
582
+ if (masks) {
583
+ masks.split(",").forEach((s) => this.maskSelectors.add(s.trim()));
584
+ }
585
+ if (transparent)
586
+ this.style.opacity = "0";
587
+ if (passthrough)
588
+ this.style.pointerEvents = "none";
589
+ try {
590
+ const wgpuViewId = await request("wgpuTagInit", {
591
+ windowId: window.__electrobunWindowId,
592
+ frame: {
593
+ width: rect.width,
594
+ height: rect.height,
595
+ x: rect.x,
596
+ y: rect.y
597
+ },
598
+ transparent,
599
+ passthrough
600
+ });
601
+ this.wgpuViewId = wgpuViewId;
602
+ this.id = `electrobun-wgpu-${wgpuViewId}`;
603
+ wgpuTagRegistry[wgpuViewId] = this;
604
+ this.setupObservers(initialRect);
605
+ this.syncDimensions(true);
606
+ if (hidden) {
607
+ this.toggleHidden(true);
608
+ }
609
+ requestAnimationFrame(() => {
610
+ Object.values(wgpuTagRegistry).forEach((view) => {
611
+ if (view !== this && view.wgpuViewId !== null) {
612
+ view.syncDimensions(true);
613
+ }
614
+ });
615
+ });
616
+ this.emit("ready", { id: wgpuViewId });
617
+ } catch (err) {
618
+ console.error("Failed to init WGPU view:", err);
619
+ }
620
+ }
621
+ setupObservers(initialRect) {
622
+ const getMasks = () => {
623
+ const rect = this.getBoundingClientRect();
624
+ const masks = [];
625
+ this.maskSelectors.forEach((selector) => {
626
+ try {
627
+ document.querySelectorAll(selector).forEach((el) => {
628
+ const mr = el.getBoundingClientRect();
629
+ masks.push({
630
+ x: mr.x - rect.x,
631
+ y: mr.y - rect.y,
632
+ width: mr.width,
633
+ height: mr.height
634
+ });
635
+ });
636
+ } catch (_e) {}
637
+ });
638
+ return masks;
639
+ };
640
+ this._sync = new OverlaySyncController(this, {
641
+ onSync: (rect, masksJson) => {
642
+ if (this.wgpuViewId === null)
643
+ return;
644
+ send("wgpuTagResize", {
645
+ id: this.wgpuViewId,
646
+ frame: rect,
647
+ masks: masksJson
648
+ });
649
+ },
650
+ getMasks,
651
+ burstIntervalMs: 10,
652
+ baseIntervalMs: 100,
653
+ burstDurationMs: 50
654
+ });
655
+ this._sync.setLastRect(initialRect);
656
+ this._sync.start();
657
+ }
658
+ syncDimensions(force = false) {
659
+ if (!this._sync)
660
+ return;
661
+ if (force) {
662
+ this._sync.forceSync();
663
+ }
664
+ }
665
+ toggleTransparent(value) {
666
+ if (this.wgpuViewId === null)
667
+ return;
668
+ this.transparent = value !== undefined ? value : !this.transparent;
669
+ this.style.opacity = this.transparent ? "0" : "";
670
+ send("wgpuTagSetTransparent", {
671
+ id: this.wgpuViewId,
672
+ transparent: this.transparent
673
+ });
674
+ }
675
+ togglePassthrough(value) {
676
+ if (this.wgpuViewId === null)
677
+ return;
678
+ this.passthroughEnabled = value !== undefined ? value : !this.passthroughEnabled;
679
+ this.style.pointerEvents = this.passthroughEnabled ? "none" : "";
680
+ send("wgpuTagSetPassthrough", {
681
+ id: this.wgpuViewId,
682
+ passthrough: this.passthroughEnabled
683
+ });
684
+ }
685
+ toggleHidden(value) {
686
+ if (this.wgpuViewId === null)
687
+ return;
688
+ this.hidden = value !== undefined ? value : !this.hidden;
689
+ send("wgpuTagSetHidden", { id: this.wgpuViewId, hidden: this.hidden });
690
+ }
691
+ runTest() {
692
+ if (this.wgpuViewId === null)
693
+ return;
694
+ send("wgpuTagRunTest", { id: this.wgpuViewId });
695
+ }
696
+ addMaskSelector(selector) {
697
+ this.maskSelectors.add(selector);
698
+ this.syncDimensions(true);
699
+ }
700
+ removeMaskSelector(selector) {
701
+ this.maskSelectors.delete(selector);
702
+ this.syncDimensions(true);
703
+ }
704
+ on(event, listener) {
705
+ if (!this._eventListeners[event])
706
+ this._eventListeners[event] = [];
707
+ this._eventListeners[event].push(listener);
708
+ }
709
+ off(event, listener) {
710
+ if (!this._eventListeners[event])
711
+ return;
712
+ const idx = this._eventListeners[event].indexOf(listener);
713
+ if (idx !== -1)
714
+ this._eventListeners[event].splice(idx, 1);
715
+ }
716
+ emit(event, detail) {
717
+ const listeners = this._eventListeners[event];
718
+ if (listeners) {
719
+ const customEvent = new CustomEvent(event, { detail });
720
+ listeners.forEach((fn) => fn(customEvent));
721
+ }
722
+ }
723
+ }
724
+ function initWgpuTag() {
725
+ if (!customElements.get("electrobun-wgpu")) {
726
+ customElements.define("electrobun-wgpu", ElectrobunWgpuTag);
727
+ }
728
+ const injectStyles = () => {
729
+ const style = document.createElement("style");
730
+ style.textContent = `
731
+ electrobun-wgpu {
732
+ display: block;
733
+ width: 800px;
734
+ height: 300px;
735
+ background: #000;
736
+ overflow: hidden;
737
+ }
738
+ `;
739
+ if (document.head?.firstChild) {
740
+ document.head.insertBefore(style, document.head.firstChild);
741
+ } else if (document.head) {
742
+ document.head.appendChild(style);
743
+ }
744
+ };
745
+ if (document.head) {
746
+ injectStyles();
747
+ } else {
748
+ document.addEventListener("DOMContentLoaded", injectStyles);
749
+ }
750
+ }
751
+
752
+ // src/bun/preload/events.ts
753
+ function emitWebviewEvent(eventName, detail) {
754
+ setTimeout(() => {
755
+ const bridge = window.__electrobunEventBridge || window.__electrobunInternalBridge;
756
+ bridge?.postMessage(JSON.stringify({
757
+ id: "webviewEvent",
758
+ type: "message",
759
+ payload: {
760
+ id: window.__electrobunWebviewId,
761
+ eventName,
762
+ detail
763
+ }
764
+ }));
765
+ });
766
+ }
767
+ function initLifecycleEvents() {
768
+ window.addEventListener("load", () => {
769
+ if (window === window.top) {
770
+ emitWebviewEvent("dom-ready", document.location.href);
771
+ }
772
+ });
773
+ window.addEventListener("popstate", () => {
774
+ emitWebviewEvent("did-navigate-in-page", window.location.href);
775
+ });
776
+ window.addEventListener("hashchange", () => {
777
+ emitWebviewEvent("did-navigate-in-page", window.location.href);
778
+ });
779
+ }
780
+ var cmdKeyHeld = false;
781
+ var cmdKeyTimestamp = 0;
782
+ var CMD_KEY_THRESHOLD_MS = 500;
783
+ function isCmdHeld() {
784
+ if (cmdKeyHeld)
785
+ return true;
786
+ return Date.now() - cmdKeyTimestamp < CMD_KEY_THRESHOLD_MS && cmdKeyTimestamp > 0;
787
+ }
788
+ function initCmdClickHandling() {
789
+ window.addEventListener("keydown", (event) => {
790
+ if (event.key === "Meta" || event.metaKey) {
791
+ cmdKeyHeld = true;
792
+ cmdKeyTimestamp = Date.now();
793
+ }
794
+ }, true);
795
+ window.addEventListener("keyup", (event) => {
796
+ if (event.key === "Meta") {
797
+ cmdKeyHeld = false;
798
+ cmdKeyTimestamp = Date.now();
799
+ }
800
+ }, true);
801
+ window.addEventListener("blur", () => {
802
+ cmdKeyHeld = false;
803
+ });
804
+ window.addEventListener("click", (event) => {
805
+ if (event.metaKey || event.ctrlKey) {
806
+ const anchor = event.target?.closest?.("a");
807
+ if (anchor && anchor.href) {
808
+ event.preventDefault();
809
+ event.stopPropagation();
810
+ event.stopImmediatePropagation();
811
+ emitWebviewEvent("new-window-open", JSON.stringify({
812
+ url: anchor.href,
813
+ isCmdClick: true,
814
+ isSPANavigation: false
815
+ }));
816
+ }
817
+ }
818
+ }, true);
819
+ }
820
+ function initSPANavigationInterception() {
821
+ const originalPushState = history.pushState;
822
+ const originalReplaceState = history.replaceState;
823
+ history.pushState = function(state, title, url) {
824
+ if (isCmdHeld() && url) {
825
+ const resolvedUrl = new URL(String(url), window.location.href).href;
826
+ emitWebviewEvent("new-window-open", JSON.stringify({
827
+ url: resolvedUrl,
828
+ isCmdClick: true,
829
+ isSPANavigation: true
830
+ }));
831
+ return;
832
+ }
833
+ return originalPushState.apply(this, [state, title, url]);
834
+ };
835
+ history.replaceState = function(state, title, url) {
836
+ if (isCmdHeld() && url) {
837
+ const resolvedUrl = new URL(String(url), window.location.href).href;
838
+ emitWebviewEvent("new-window-open", JSON.stringify({
839
+ url: resolvedUrl,
840
+ isCmdClick: true,
841
+ isSPANavigation: true
842
+ }));
843
+ return;
844
+ }
845
+ return originalReplaceState.apply(this, [state, title, url]);
846
+ };
847
+ }
848
+ function initOverscrollPrevention() {
849
+ document.addEventListener("DOMContentLoaded", () => {
850
+ const style = document.createElement("style");
851
+ style.type = "text/css";
852
+ style.appendChild(document.createTextNode("html, body { overscroll-behavior: none; }"));
853
+ document.head.appendChild(style);
854
+ });
855
+ }
856
+
857
+ // src/bun/preload/index.ts
858
+ initEncryption().catch((err) => console.error("Failed to initialize encryption:", err));
859
+ var internalMessageHandler = (msg) => {
860
+ handleResponse(msg);
861
+ };
862
+ if (!window.__electrobun) {
863
+ window.__electrobun = {
864
+ receiveInternalMessageFromBun: internalMessageHandler,
865
+ receiveMessageFromBun: (msg) => {
866
+ console.log("receiveMessageFromBun (no handler):", msg);
867
+ }
868
+ };
869
+ } else {
870
+ window.__electrobun.receiveInternalMessageFromBun = internalMessageHandler;
871
+ window.__electrobun.receiveMessageFromBun = (msg) => {
872
+ console.log("receiveMessageFromBun (no handler):", msg);
873
+ };
874
+ }
875
+ window.__electrobunSendToHost = (message) => {
876
+ emitWebviewEvent("host-message", JSON.stringify(message));
877
+ };
878
+ initLifecycleEvents();
879
+ initCmdClickHandling();
880
+ initSPANavigationInterception();
881
+ initOverscrollPrevention();
882
+ initDragRegions();
883
+ initWebviewTag();
884
+ initWgpuTag();
885
+ })();