electrobun 1.18.4-beta.3 → 1.18.4-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/api/browser/global.d.ts +5 -0
- package/dist/api/browser/index.ts +64 -22
- package/dist/api/bun/ElectrobunConfig.ts +25 -1
- package/dist/api/bun/core/BrowserView.ts +67 -8
- package/dist/api/bun/core/BrowserWindow.ts +5 -22
- package/dist/api/bun/core/GpuWindow.ts +7 -1
- package/dist/api/bun/core/Socket.ts +13 -196
- package/dist/api/bun/core/Utils.ts +2 -4
- package/dist/api/bun/core/WGPUView.ts +43 -13
- package/dist/api/bun/index.ts +35 -0
- package/dist/api/bun/preload/.generated/compiled.ts +1 -1
- package/dist/api/bun/preload/globals.d.ts +7 -0
- package/dist/api/bun/preload/index.ts +18 -8
- package/dist/api/bun/preload/webviewTag.ts +32 -3
- package/dist/api/bun/proc/native.ts +240 -98
- package/dist/api/bun/webGPU.ts +1 -1
- package/dist/preload-full.js +38 -10
- package/dist/zig-sdk/electrobun.zig +18 -4
- package/package.json +1 -1
- package/src/cli/index.ts +97 -4
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { join } from "path";
|
|
1
|
+
import { dirname, join } from "path";
|
|
2
|
+
import { createReadStream } from "node:fs";
|
|
2
3
|
import electrobunEventEmitter from "../events/eventEmitter";
|
|
3
4
|
import ElectrobunEvent from "../events/event";
|
|
4
5
|
import { BrowserView } from "../core/BrowserView";
|
|
5
6
|
import { WGPUView } from "../core/WGPUView";
|
|
6
|
-
import { rpcPort } from "../core/Socket";
|
|
7
7
|
import {
|
|
8
8
|
preloadScript,
|
|
9
9
|
preloadScriptSandboxed,
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
// Menu data reference system to avoid serialization overhead
|
|
13
13
|
const menuDataRegistry = new Map<string, any>();
|
|
14
14
|
let menuDataCounter = 0;
|
|
15
|
-
|
|
16
15
|
function storeMenuData(data: any): string {
|
|
17
16
|
const id = `menuData_${++menuDataCounter}`;
|
|
18
17
|
menuDataRegistry.set(id, data);
|
|
@@ -71,6 +70,30 @@ import {
|
|
|
71
70
|
type Pointer,
|
|
72
71
|
} from "bun:ffi";
|
|
73
72
|
|
|
73
|
+
function getElectrobunLibraryPathCandidates(fileName: string) {
|
|
74
|
+
const candidates = new Set<string>();
|
|
75
|
+
candidates.add(join(process.cwd(), fileName));
|
|
76
|
+
if (process.argv0) {
|
|
77
|
+
candidates.add(join(dirname(process.argv0), fileName));
|
|
78
|
+
}
|
|
79
|
+
return Array.from(candidates);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function tryDlopenCandidates<T extends Record<string, { args: FFIType[]; returns: FFIType }>>(
|
|
83
|
+
fileName: string,
|
|
84
|
+
symbols: T,
|
|
85
|
+
) {
|
|
86
|
+
let lastError: unknown = null;
|
|
87
|
+
for (const candidatePath of getElectrobunLibraryPathCandidates(fileName)) {
|
|
88
|
+
try {
|
|
89
|
+
return dlopen(candidatePath, symbols);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
lastError = error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
throw lastError ?? new Error(`Failed to load ${fileName}`);
|
|
95
|
+
}
|
|
96
|
+
|
|
74
97
|
function getWindowPtr(winId: number) {
|
|
75
98
|
return core?.symbols.getWindowPointer(winId) || null;
|
|
76
99
|
}
|
|
@@ -93,7 +116,7 @@ function ensureWebviewRuntimeConfigured() {
|
|
|
93
116
|
}
|
|
94
117
|
|
|
95
118
|
const configured = core?.symbols.configureWebviewRuntime(
|
|
96
|
-
|
|
119
|
+
0,
|
|
97
120
|
toCString(preloadScript),
|
|
98
121
|
toCString(preloadScriptSandboxed),
|
|
99
122
|
);
|
|
@@ -107,13 +130,11 @@ function ensureWebviewRuntimeConfigured() {
|
|
|
107
130
|
|
|
108
131
|
const core = (() => {
|
|
109
132
|
try {
|
|
110
|
-
const
|
|
111
|
-
process.cwd(),
|
|
133
|
+
const coreFileName =
|
|
112
134
|
process.platform === "win32"
|
|
113
135
|
? "ElectrobunCore.dll"
|
|
114
|
-
: `libElectrobunCore.${suffix}
|
|
115
|
-
|
|
116
|
-
return dlopen(corePath, {
|
|
136
|
+
: `libElectrobunCore.${suffix}`;
|
|
137
|
+
return tryDlopenCandidates(coreFileName, {
|
|
117
138
|
electrobun_core_last_error: {
|
|
118
139
|
args: [],
|
|
119
140
|
returns: FFIType.cstring,
|
|
@@ -367,6 +388,26 @@ const core = (() => {
|
|
|
367
388
|
args: [FFIType.u32, FFIType.cstring],
|
|
368
389
|
returns: FFIType.void,
|
|
369
390
|
},
|
|
391
|
+
sendHostMessageToWebviewViaTransport: {
|
|
392
|
+
args: [FFIType.u32, FFIType.cstring],
|
|
393
|
+
returns: FFIType.bool,
|
|
394
|
+
},
|
|
395
|
+
popNextQueuedHostMessage: {
|
|
396
|
+
args: [FFIType.ptr],
|
|
397
|
+
returns: FFIType.ptr,
|
|
398
|
+
},
|
|
399
|
+
getHostMessageWakeupReadFD: {
|
|
400
|
+
args: [],
|
|
401
|
+
returns: FFIType.int,
|
|
402
|
+
},
|
|
403
|
+
freeCoreString: {
|
|
404
|
+
args: [FFIType.ptr],
|
|
405
|
+
returns: FFIType.void,
|
|
406
|
+
},
|
|
407
|
+
clearWebviewHostTransport: {
|
|
408
|
+
args: [FFIType.u32],
|
|
409
|
+
returns: FFIType.void,
|
|
410
|
+
},
|
|
370
411
|
dispatchHostWebviewEvent: {
|
|
371
412
|
args: [FFIType.u32, FFIType.cstring, FFIType.cstring],
|
|
372
413
|
returns: FFIType.bool,
|
|
@@ -395,6 +436,55 @@ const core = (() => {
|
|
|
395
436
|
args: [FFIType.u32],
|
|
396
437
|
returns: FFIType.f64,
|
|
397
438
|
},
|
|
439
|
+
createWGPUView: {
|
|
440
|
+
args: [
|
|
441
|
+
FFIType.u32,
|
|
442
|
+
FFIType.f64,
|
|
443
|
+
FFIType.f64,
|
|
444
|
+
FFIType.f64,
|
|
445
|
+
FFIType.f64,
|
|
446
|
+
FFIType.bool,
|
|
447
|
+
FFIType.bool,
|
|
448
|
+
FFIType.bool,
|
|
449
|
+
],
|
|
450
|
+
returns: FFIType.u32,
|
|
451
|
+
},
|
|
452
|
+
getWGPUViewPointer: {
|
|
453
|
+
args: [FFIType.u32],
|
|
454
|
+
returns: FFIType.ptr,
|
|
455
|
+
},
|
|
456
|
+
setWGPUViewFrame: {
|
|
457
|
+
args: [FFIType.u32, FFIType.f64, FFIType.f64, FFIType.f64, FFIType.f64],
|
|
458
|
+
returns: FFIType.void,
|
|
459
|
+
},
|
|
460
|
+
resizeWGPUView: {
|
|
461
|
+
args: [FFIType.u32, FFIType.f64, FFIType.f64, FFIType.f64, FFIType.f64, FFIType.cstring],
|
|
462
|
+
returns: FFIType.void,
|
|
463
|
+
},
|
|
464
|
+
setWGPUViewTransparent: {
|
|
465
|
+
args: [FFIType.u32, FFIType.bool],
|
|
466
|
+
returns: FFIType.void,
|
|
467
|
+
},
|
|
468
|
+
setWGPUViewPassthrough: {
|
|
469
|
+
args: [FFIType.u32, FFIType.bool],
|
|
470
|
+
returns: FFIType.void,
|
|
471
|
+
},
|
|
472
|
+
setWGPUViewHidden: {
|
|
473
|
+
args: [FFIType.u32, FFIType.bool],
|
|
474
|
+
returns: FFIType.void,
|
|
475
|
+
},
|
|
476
|
+
removeWGPUView: {
|
|
477
|
+
args: [FFIType.u32],
|
|
478
|
+
returns: FFIType.void,
|
|
479
|
+
},
|
|
480
|
+
getWGPUViewNativeHandle: {
|
|
481
|
+
args: [FFIType.u32],
|
|
482
|
+
returns: FFIType.ptr,
|
|
483
|
+
},
|
|
484
|
+
runWGPUViewTest: {
|
|
485
|
+
args: [FFIType.u32],
|
|
486
|
+
returns: FFIType.void,
|
|
487
|
+
},
|
|
398
488
|
createTray: {
|
|
399
489
|
args: [
|
|
400
490
|
FFIType.cstring,
|
|
@@ -537,6 +627,18 @@ const core = (() => {
|
|
|
537
627
|
args: [],
|
|
538
628
|
returns: FFIType.bool,
|
|
539
629
|
},
|
|
630
|
+
setExitOnLastWindowClosed: {
|
|
631
|
+
args: [FFIType.bool],
|
|
632
|
+
returns: FFIType.void,
|
|
633
|
+
},
|
|
634
|
+
setQuitRequestedHandler: {
|
|
635
|
+
args: [FFIType.function],
|
|
636
|
+
returns: FFIType.void,
|
|
637
|
+
},
|
|
638
|
+
quitGracefully: {
|
|
639
|
+
args: [FFIType.i32, FFIType.i32],
|
|
640
|
+
returns: FFIType.void,
|
|
641
|
+
},
|
|
540
642
|
});
|
|
541
643
|
} catch {
|
|
542
644
|
return null;
|
|
@@ -545,10 +647,8 @@ const core = (() => {
|
|
|
545
647
|
|
|
546
648
|
export const native = (() => {
|
|
547
649
|
try {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
const nativeWrapperPath = join(process.cwd(), `libNativeWrapper.${suffix}`);
|
|
551
|
-
return dlopen(nativeWrapperPath, {
|
|
650
|
+
const nativeWrapperFileName = `libNativeWrapper.${suffix}`;
|
|
651
|
+
return tryDlopenCandidates(nativeWrapperFileName, {
|
|
552
652
|
// webview
|
|
553
653
|
initWebview: {
|
|
554
654
|
args: [
|
|
@@ -565,13 +665,13 @@ export const native = (() => {
|
|
|
565
665
|
FFIType.function, // decideNavigation: *const fn (u32, [*:0]const u8) callconv(.C) bool,
|
|
566
666
|
FFIType.function, // webviewEventHandler: *const fn (u32, [*:0]const u8, [*:0]const u8) callconv(.C) void,
|
|
567
667
|
FFIType.function, // eventBridgeHandler: *const fn (u32, [*:0]const u8) callconv(.C) void (events only, always active)
|
|
568
|
-
FFIType.function, //
|
|
668
|
+
FFIType.function, // hostBridgePostmessageHandler: *const fn (u32, [*:0]const u8) callconv(.C) void (user RPC, disabled in sandbox)
|
|
569
669
|
FFIType.function, // internalBridgeHandler: *const fn (u32, [*:0]const u8) callconv(.C) void (internal RPC, disabled in sandbox)
|
|
570
670
|
FFIType.cstring, // electrobunPreloadScript
|
|
571
671
|
FFIType.cstring, // customPreloadScript
|
|
572
672
|
FFIType.cstring, // viewsRoot
|
|
573
673
|
FFIType.bool, // transparent
|
|
574
|
-
FFIType.bool, // sandbox - when true,
|
|
674
|
+
FFIType.bool, // sandbox - when true, hostBridge and internalBridge are not set up
|
|
575
675
|
],
|
|
576
676
|
returns: FFIType.ptr,
|
|
577
677
|
},
|
|
@@ -992,7 +1092,14 @@ function createFfiRequestProxy(ffiRequest: Record<string, Function>): Record<str
|
|
|
992
1092
|
return new Proxy(ffiRequest, {
|
|
993
1093
|
get(target, method: string) {
|
|
994
1094
|
if (typeof method !== "string") return target[method];
|
|
995
|
-
return (params?: unknown) =>
|
|
1095
|
+
return (params?: unknown) => {
|
|
1096
|
+
if (!bridge) {
|
|
1097
|
+
throw new Error(
|
|
1098
|
+
`Electrobun FFI is unavailable and no host bridge exists for request ${method}`,
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
return bridge.requestHost(method, params);
|
|
1102
|
+
};
|
|
996
1103
|
},
|
|
997
1104
|
});
|
|
998
1105
|
}
|
|
@@ -1006,6 +1113,70 @@ function createFfiRequestProxy(ffiRequest: Record<string, Function>): Record<str
|
|
|
1006
1113
|
// Non-null accessor for use inside _ffiImpl — these methods are only called when hasFFI is true.
|
|
1007
1114
|
const core_ = core!;
|
|
1008
1115
|
const native_ = native!;
|
|
1116
|
+
const queuedHostMessageWebviewIdBuf = new Uint32Array(1);
|
|
1117
|
+
|
|
1118
|
+
const drainQueuedHostMessages = () => {
|
|
1119
|
+
if (!core) {
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
for (;;) {
|
|
1124
|
+
const messagePtr = core_.symbols.popNextQueuedHostMessage(
|
|
1125
|
+
ptr(queuedHostMessageWebviewIdBuf),
|
|
1126
|
+
) as Pointer | null;
|
|
1127
|
+
|
|
1128
|
+
if (!messagePtr) {
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
try {
|
|
1133
|
+
const rawMessage = new CString(messagePtr).toString();
|
|
1134
|
+
if (!rawMessage) {
|
|
1135
|
+
continue;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
const webview = BrowserView.ensureWrapped(
|
|
1139
|
+
queuedHostMessageWebviewIdBuf[0]!,
|
|
1140
|
+
);
|
|
1141
|
+
if (!webview) {
|
|
1142
|
+
continue;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
webview.rpcHandler?.(JSON.parse(rawMessage));
|
|
1146
|
+
} catch (err) {
|
|
1147
|
+
console.error("error draining queued host message:", err);
|
|
1148
|
+
} finally {
|
|
1149
|
+
core_.symbols.freeCoreString(messagePtr);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
|
|
1154
|
+
if (core) {
|
|
1155
|
+
const wakeupReadFd = core_.symbols.getHostMessageWakeupReadFD();
|
|
1156
|
+
|
|
1157
|
+
if (typeof wakeupReadFd === "number" && wakeupReadFd >= 0) {
|
|
1158
|
+
try {
|
|
1159
|
+
const wakeupStream = createReadStream("/dev/null", {
|
|
1160
|
+
fd: wakeupReadFd,
|
|
1161
|
+
autoClose: false,
|
|
1162
|
+
});
|
|
1163
|
+
wakeupStream.on("data", () => {
|
|
1164
|
+
drainQueuedHostMessages();
|
|
1165
|
+
});
|
|
1166
|
+
wakeupStream.on("error", (error) => {
|
|
1167
|
+
console.error("host message wakeup stream failed, falling back to polling:", error);
|
|
1168
|
+
setInterval(drainQueuedHostMessages, 16);
|
|
1169
|
+
});
|
|
1170
|
+
} catch (error) {
|
|
1171
|
+
console.error("failed to start host message wakeup stream, falling back to polling:", error);
|
|
1172
|
+
setInterval(drainQueuedHostMessages, 16);
|
|
1173
|
+
}
|
|
1174
|
+
} else {
|
|
1175
|
+
setInterval(drainQueuedHostMessages, 16);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
drainQueuedHostMessages();
|
|
1179
|
+
}
|
|
1009
1180
|
|
|
1010
1181
|
const _ffiImpl = {
|
|
1011
1182
|
request: {
|
|
@@ -1446,12 +1617,12 @@ const _ffiImpl = {
|
|
|
1446
1617
|
webviewDecideNavigation,
|
|
1447
1618
|
webviewEventJSCallback,
|
|
1448
1619
|
eventBridgeHandler,
|
|
1449
|
-
|
|
1620
|
+
hostBridgePostmessageHandler,
|
|
1450
1621
|
internalBridgeHandler,
|
|
1451
1622
|
toCString(secretKey),
|
|
1452
1623
|
toCString(preload || ""),
|
|
1453
1624
|
toCString(viewsRoot || ""),
|
|
1454
|
-
sandbox, // When true,
|
|
1625
|
+
sandbox, // When true, hostBridge and internalBridge are not set up in native code
|
|
1455
1626
|
startTransparent,
|
|
1456
1627
|
startPassthrough,
|
|
1457
1628
|
);
|
|
@@ -1543,7 +1714,6 @@ const _ffiImpl = {
|
|
|
1543
1714
|
},
|
|
1544
1715
|
|
|
1545
1716
|
createWGPUView: (params: {
|
|
1546
|
-
id: number;
|
|
1547
1717
|
windowId: number;
|
|
1548
1718
|
frame: {
|
|
1549
1719
|
x: number;
|
|
@@ -1554,9 +1724,8 @@ const _ffiImpl = {
|
|
|
1554
1724
|
autoResize: boolean;
|
|
1555
1725
|
startTransparent: boolean;
|
|
1556
1726
|
startPassthrough: boolean;
|
|
1557
|
-
}):
|
|
1727
|
+
}): number => {
|
|
1558
1728
|
const {
|
|
1559
|
-
id,
|
|
1560
1729
|
windowId,
|
|
1561
1730
|
frame: { x, y, width, height },
|
|
1562
1731
|
autoResize,
|
|
@@ -1564,14 +1733,8 @@ const _ffiImpl = {
|
|
|
1564
1733
|
startPassthrough,
|
|
1565
1734
|
} = params;
|
|
1566
1735
|
|
|
1567
|
-
const
|
|
1568
|
-
|
|
1569
|
-
throw `Can't add WGPUView to window. window no longer exists`;
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
|
-
const viewPtr = native_.symbols.initWGPUView(
|
|
1573
|
-
id,
|
|
1574
|
-
windowPtr,
|
|
1736
|
+
const viewId = core_.symbols.createWGPUView(
|
|
1737
|
+
windowId,
|
|
1575
1738
|
x,
|
|
1576
1739
|
y,
|
|
1577
1740
|
width,
|
|
@@ -1581,11 +1744,14 @@ const _ffiImpl = {
|
|
|
1581
1744
|
startPassthrough,
|
|
1582
1745
|
);
|
|
1583
1746
|
|
|
1584
|
-
if (!
|
|
1747
|
+
if (!viewId) {
|
|
1585
1748
|
throw "Failed to create WGPUView";
|
|
1586
1749
|
}
|
|
1587
1750
|
|
|
1588
|
-
return
|
|
1751
|
+
return viewId;
|
|
1752
|
+
},
|
|
1753
|
+
getWGPUViewPointer: (params: { id: number }): Pointer | null => {
|
|
1754
|
+
return core_.symbols.getWGPUViewPointer(params.id) || null;
|
|
1589
1755
|
},
|
|
1590
1756
|
|
|
1591
1757
|
wgpuViewSetFrame: (params: {
|
|
@@ -1595,16 +1761,8 @@ const _ffiImpl = {
|
|
|
1595
1761
|
width: number;
|
|
1596
1762
|
height: number;
|
|
1597
1763
|
}) => {
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
console.error(
|
|
1601
|
-
`wgpuViewSetFrame: WGPUView not found or has no ptr for id ${params.id}`,
|
|
1602
|
-
);
|
|
1603
|
-
return;
|
|
1604
|
-
}
|
|
1605
|
-
|
|
1606
|
-
native_.symbols.wgpuViewSetFrame(
|
|
1607
|
-
view.ptr,
|
|
1764
|
+
core_.symbols.setWGPUViewFrame(
|
|
1765
|
+
params.id,
|
|
1608
1766
|
params.x,
|
|
1609
1767
|
params.y,
|
|
1610
1768
|
params.width,
|
|
@@ -1613,66 +1771,28 @@ const _ffiImpl = {
|
|
|
1613
1771
|
},
|
|
1614
1772
|
|
|
1615
1773
|
wgpuViewSetTransparent: (params: { id: number; transparent: boolean }) => {
|
|
1616
|
-
|
|
1617
|
-
if (!view?.ptr) {
|
|
1618
|
-
console.error(
|
|
1619
|
-
`wgpuViewSetTransparent: WGPUView not found or has no ptr for id ${params.id}`,
|
|
1620
|
-
);
|
|
1621
|
-
return;
|
|
1622
|
-
}
|
|
1623
|
-
|
|
1624
|
-
native_.symbols.wgpuViewSetTransparent(view.ptr, params.transparent);
|
|
1774
|
+
core_.symbols.setWGPUViewTransparent(params.id, params.transparent);
|
|
1625
1775
|
},
|
|
1626
1776
|
|
|
1627
1777
|
wgpuViewSetPassthrough: (params: {
|
|
1628
1778
|
id: number;
|
|
1629
1779
|
passthrough: boolean;
|
|
1630
1780
|
}) => {
|
|
1631
|
-
|
|
1632
|
-
if (!view?.ptr) {
|
|
1633
|
-
console.error(
|
|
1634
|
-
`wgpuViewSetPassthrough: WGPUView not found or has no ptr for id ${params.id}`,
|
|
1635
|
-
);
|
|
1636
|
-
return;
|
|
1637
|
-
}
|
|
1638
|
-
|
|
1639
|
-
native_.symbols.wgpuViewSetPassthrough(view.ptr, params.passthrough);
|
|
1781
|
+
core_.symbols.setWGPUViewPassthrough(params.id, params.passthrough);
|
|
1640
1782
|
},
|
|
1641
1783
|
|
|
1642
1784
|
wgpuViewSetHidden: (params: { id: number; hidden: boolean }) => {
|
|
1643
|
-
|
|
1644
|
-
if (!view?.ptr) {
|
|
1645
|
-
console.error(
|
|
1646
|
-
`wgpuViewSetHidden: WGPUView not found or has no ptr for id ${params.id}`,
|
|
1647
|
-
);
|
|
1648
|
-
return;
|
|
1649
|
-
}
|
|
1650
|
-
|
|
1651
|
-
native_.symbols.wgpuViewSetHidden(view.ptr, params.hidden);
|
|
1785
|
+
core_.symbols.setWGPUViewHidden(params.id, params.hidden);
|
|
1652
1786
|
},
|
|
1653
1787
|
|
|
1654
1788
|
wgpuViewRemove: (params: { id: number }) => {
|
|
1655
|
-
|
|
1656
|
-
if (!view?.ptr) {
|
|
1657
|
-
console.error(
|
|
1658
|
-
`wgpuViewRemove: WGPUView not found or has no ptr for id ${params.id}`,
|
|
1659
|
-
);
|
|
1660
|
-
return;
|
|
1661
|
-
}
|
|
1662
|
-
|
|
1663
|
-
native_.symbols.wgpuViewRemove(view.ptr);
|
|
1789
|
+
core_.symbols.removeWGPUView(params.id);
|
|
1664
1790
|
},
|
|
1665
1791
|
wgpuViewGetNativeHandle: (params: { id: number }): Pointer | null => {
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
);
|
|
1671
|
-
return null;
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
const handle = native_.symbols.wgpuViewGetNativeHandle(view.ptr);
|
|
1675
|
-
return handle || null;
|
|
1792
|
+
return core_.symbols.getWGPUViewNativeHandle(params.id) || null;
|
|
1793
|
+
},
|
|
1794
|
+
runWGPUViewTest: (params: { id: number }) => {
|
|
1795
|
+
core_.symbols.runWGPUViewTest(params.id);
|
|
1676
1796
|
},
|
|
1677
1797
|
|
|
1678
1798
|
evaluateJavascriptWithNoCompletion: (params: {
|
|
@@ -1684,6 +1804,18 @@ const _ffiImpl = {
|
|
|
1684
1804
|
toCString(params.js),
|
|
1685
1805
|
);
|
|
1686
1806
|
},
|
|
1807
|
+
sendHostMessageToWebviewViaTransport: (params: {
|
|
1808
|
+
id: number;
|
|
1809
|
+
messageJson: string;
|
|
1810
|
+
}): boolean => {
|
|
1811
|
+
return core_.symbols.sendHostMessageToWebviewViaTransport(
|
|
1812
|
+
params.id,
|
|
1813
|
+
toCString(params.messageJson),
|
|
1814
|
+
);
|
|
1815
|
+
},
|
|
1816
|
+
clearWebviewHostTransport: (params: { id: number }) => {
|
|
1817
|
+
core_.symbols.clearWebviewHostTransport(params.id);
|
|
1818
|
+
},
|
|
1687
1819
|
webviewOpenDevTools: (params: { id: number }) => {
|
|
1688
1820
|
core_.symbols.webviewOpenDevTools(params.id);
|
|
1689
1821
|
},
|
|
@@ -1699,6 +1831,12 @@ const _ffiImpl = {
|
|
|
1699
1831
|
webviewGetPageZoom: (params: { id: number }): number => {
|
|
1700
1832
|
return core_.symbols.webviewGetPageZoom(params.id);
|
|
1701
1833
|
},
|
|
1834
|
+
setExitOnLastWindowClosed: (params: { enabled: boolean }) => {
|
|
1835
|
+
core_.symbols.setExitOnLastWindowClosed(params.enabled);
|
|
1836
|
+
},
|
|
1837
|
+
quitGracefully: (params: { code: number; timeoutMs: number }) => {
|
|
1838
|
+
core_.symbols.quitGracefully(params.code, params.timeoutMs);
|
|
1839
|
+
},
|
|
1702
1840
|
|
|
1703
1841
|
createTray: (params: {
|
|
1704
1842
|
title: string;
|
|
@@ -2243,7 +2381,7 @@ const getMimeType = new JSCallback(
|
|
|
2243
2381
|
|
|
2244
2382
|
const getHTMLForWebviewSync = new JSCallback(
|
|
2245
2383
|
(webviewId) => {
|
|
2246
|
-
const webview = BrowserView.
|
|
2384
|
+
const webview = BrowserView.ensureWrapped(webviewId);
|
|
2247
2385
|
|
|
2248
2386
|
return toCString(webview?.html || "");
|
|
2249
2387
|
},
|
|
@@ -2296,7 +2434,7 @@ if (native) {
|
|
|
2296
2434
|
},
|
|
2297
2435
|
{ args: [], returns: "void", threadsafe: true },
|
|
2298
2436
|
);
|
|
2299
|
-
|
|
2437
|
+
core_.symbols.setQuitRequestedHandler(quitRequestedCallback);
|
|
2300
2438
|
|
|
2301
2439
|
const globalShortcutCallback = new JSCallback(
|
|
2302
2440
|
(acceleratorPtr) => {
|
|
@@ -2592,6 +2730,8 @@ const webviewDecideNavigation = new JSCallback(
|
|
|
2592
2730
|
);
|
|
2593
2731
|
|
|
2594
2732
|
const webviewEventHandler = (id: number, eventName: string, detail: string) => {
|
|
2733
|
+
BrowserView.ensureWrapped(id);
|
|
2734
|
+
|
|
2595
2735
|
core_.symbols.dispatchHostWebviewEvent(
|
|
2596
2736
|
id,
|
|
2597
2737
|
toCString(eventName),
|
|
@@ -2690,7 +2830,7 @@ const webviewEventJSCallback = new JSCallback(
|
|
|
2690
2830
|
},
|
|
2691
2831
|
);
|
|
2692
2832
|
|
|
2693
|
-
const
|
|
2833
|
+
const hostBridgePostmessageHandler = new JSCallback(
|
|
2694
2834
|
(id, msg) => {
|
|
2695
2835
|
try {
|
|
2696
2836
|
const msgStr = new CString(msg);
|
|
@@ -2704,12 +2844,14 @@ const bunBridgePostmessageHandler = new JSCallback(
|
|
|
2704
2844
|
}
|
|
2705
2845
|
const msgJson = JSON.parse(rawMessage);
|
|
2706
2846
|
|
|
2707
|
-
const webview = BrowserView.
|
|
2708
|
-
if (!webview)
|
|
2847
|
+
const webview = BrowserView.ensureWrapped(id);
|
|
2848
|
+
if (!webview) {
|
|
2849
|
+
return;
|
|
2850
|
+
}
|
|
2709
2851
|
|
|
2710
2852
|
webview.rpcHandler?.(msgJson);
|
|
2711
2853
|
} catch (err) {
|
|
2712
|
-
console.error("error sending message to
|
|
2854
|
+
console.error("error sending message to host: ", err);
|
|
2713
2855
|
}
|
|
2714
2856
|
},
|
|
2715
2857
|
{
|
|
@@ -3030,14 +3172,14 @@ export const internalRpcHandlers = {
|
|
|
3030
3172
|
);
|
|
3031
3173
|
},
|
|
3032
3174
|
webviewTagUpdateSrc: (params: { id: number; url: string }) => {
|
|
3033
|
-
const webview = BrowserView.
|
|
3175
|
+
const webview = BrowserView.ensureWrapped(params.id);
|
|
3034
3176
|
if (webview) {
|
|
3035
3177
|
webview.url = params.url;
|
|
3036
3178
|
}
|
|
3037
3179
|
core_.symbols.loadURLInWebView(params.id, toCString(params.url));
|
|
3038
3180
|
},
|
|
3039
3181
|
webviewTagUpdateHtml: (params: { id: number; html: string }) => {
|
|
3040
|
-
const webview = BrowserView.
|
|
3182
|
+
const webview = BrowserView.ensureWrapped(params.id);
|
|
3041
3183
|
if (!webview) {
|
|
3042
3184
|
console.error(`webviewTagUpdateHtml: BrowserView not found for id ${params.id}`);
|
|
3043
3185
|
return;
|
|
@@ -3047,7 +3189,7 @@ export const internalRpcHandlers = {
|
|
|
3047
3189
|
webview.html = params.html;
|
|
3048
3190
|
},
|
|
3049
3191
|
webviewTagUpdatePreload: (params: { id: number; preload: string }) => {
|
|
3050
|
-
const webview = BrowserView.
|
|
3192
|
+
const webview = BrowserView.ensureWrapped(params.id);
|
|
3051
3193
|
if (webview) {
|
|
3052
3194
|
webview.preload = params.preload;
|
|
3053
3195
|
}
|
|
@@ -3068,7 +3210,7 @@ export const internalRpcHandlers = {
|
|
|
3068
3210
|
core_.symbols.webviewReload(params.id);
|
|
3069
3211
|
},
|
|
3070
3212
|
webviewTagRemove: (params: { id: number }) => {
|
|
3071
|
-
const webview = BrowserView.
|
|
3213
|
+
const webview = BrowserView.ensureWrapped(params.id);
|
|
3072
3214
|
if (!webview) {
|
|
3073
3215
|
console.error(`webviewTagRemove: BrowserView not found for id ${params.id}`);
|
|
3074
3216
|
return;
|
|
@@ -3157,7 +3299,7 @@ export const internalRpcHandlers = {
|
|
|
3157
3299
|
},
|
|
3158
3300
|
webviewTagSetNavigationRules: (params: { id: number; rules: string[] }) => {
|
|
3159
3301
|
const rulesJson = JSON.stringify(params.rules);
|
|
3160
|
-
const webview = BrowserView.
|
|
3302
|
+
const webview = BrowserView.ensureWrapped(params.id);
|
|
3161
3303
|
if (webview) {
|
|
3162
3304
|
webview.navigationRules = rulesJson;
|
|
3163
3305
|
}
|
package/dist/api/bun/webGPU.ts
CHANGED
|
@@ -291,7 +291,7 @@ const WGPU_LIB_NAMES: Record<string, string[]> = {
|
|
|
291
291
|
};
|
|
292
292
|
|
|
293
293
|
function findWgpuLibraryPath(): string | null {
|
|
294
|
-
const envPath = process.env[
|
|
294
|
+
const envPath = process.env["ELECTROBUN_WGPU_PATH"];
|
|
295
295
|
if (envPath && existsSync(envPath)) return envPath;
|
|
296
296
|
|
|
297
297
|
const names = WGPU_LIB_NAMES[process.platform] ?? ["libwebgpu_dawn." + suffix];
|
package/dist/preload-full.js
CHANGED
|
@@ -236,6 +236,26 @@ class ElectrobunWebviewTag extends HTMLElement {
|
|
|
236
236
|
if (this._sync)
|
|
237
237
|
this._sync.stop();
|
|
238
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
|
+
}
|
|
239
259
|
async initWebview() {
|
|
240
260
|
const rect = this.getBoundingClientRect();
|
|
241
261
|
const initialRect = {
|
|
@@ -250,6 +270,7 @@ class ElectrobunWebviewTag extends HTMLElement {
|
|
|
250
270
|
const partition = this.getAttribute("partition");
|
|
251
271
|
const renderer = this.getAttribute("renderer") || "native";
|
|
252
272
|
const masks = this.getAttribute("masks");
|
|
273
|
+
const navigationRules = this.getInitialNavigationRules();
|
|
253
274
|
const sandbox = this.hasAttribute("sandbox");
|
|
254
275
|
this.sandboxed = sandbox;
|
|
255
276
|
const transparent = this.hasAttribute("transparent");
|
|
@@ -264,7 +285,7 @@ class ElectrobunWebviewTag extends HTMLElement {
|
|
|
264
285
|
masks.split(",").forEach((s) => this.maskSelectors.add(s.trim()));
|
|
265
286
|
}
|
|
266
287
|
try {
|
|
267
|
-
const
|
|
288
|
+
const webviewInitParams = {
|
|
268
289
|
hostWebviewId: window.__electrobunWebviewId,
|
|
269
290
|
windowId: window.__electrobunWindowId,
|
|
270
291
|
renderer,
|
|
@@ -278,11 +299,12 @@ class ElectrobunWebviewTag extends HTMLElement {
|
|
|
278
299
|
x: rect.x,
|
|
279
300
|
y: rect.y
|
|
280
301
|
},
|
|
281
|
-
navigationRules: null,
|
|
282
302
|
sandbox,
|
|
283
303
|
transparent,
|
|
284
|
-
passthrough
|
|
285
|
-
|
|
304
|
+
passthrough,
|
|
305
|
+
...navigationRules === null ? {} : { navigationRules }
|
|
306
|
+
};
|
|
307
|
+
const webviewId = await request("webviewTagInit", webviewInitParams);
|
|
286
308
|
this.webviewId = webviewId;
|
|
287
309
|
this.id = `electrobun-webview-${webviewId}`;
|
|
288
310
|
webviewRegistry[webviewId] = this;
|
|
@@ -859,18 +881,24 @@ initEncryption().catch((err) => console.error("Failed to initialize encryption:"
|
|
|
859
881
|
var internalMessageHandler = (msg) => {
|
|
860
882
|
handleResponse(msg);
|
|
861
883
|
};
|
|
884
|
+
var defaultUserMessageHandler = (msg) => {
|
|
885
|
+
if (!window.__electrobunPendingHostMessages) {
|
|
886
|
+
window.__electrobunPendingHostMessages = [];
|
|
887
|
+
}
|
|
888
|
+
window.__electrobunPendingHostMessages.push(msg);
|
|
889
|
+
};
|
|
862
890
|
if (!window.__electrobun) {
|
|
863
891
|
window.__electrobun = {
|
|
892
|
+
receiveInternalMessageFromHost: internalMessageHandler,
|
|
893
|
+
receiveMessageFromHost: defaultUserMessageHandler,
|
|
864
894
|
receiveInternalMessageFromBun: internalMessageHandler,
|
|
865
|
-
receiveMessageFromBun:
|
|
866
|
-
console.log("receiveMessageFromBun (no handler):", msg);
|
|
867
|
-
}
|
|
895
|
+
receiveMessageFromBun: defaultUserMessageHandler
|
|
868
896
|
};
|
|
869
897
|
} else {
|
|
898
|
+
window.__electrobun.receiveInternalMessageFromHost = internalMessageHandler;
|
|
899
|
+
window.__electrobun.receiveMessageFromHost = defaultUserMessageHandler;
|
|
870
900
|
window.__electrobun.receiveInternalMessageFromBun = internalMessageHandler;
|
|
871
|
-
window.__electrobun.receiveMessageFromBun =
|
|
872
|
-
console.log("receiveMessageFromBun (no handler):", msg);
|
|
873
|
-
};
|
|
901
|
+
window.__electrobun.receiveMessageFromBun = defaultUserMessageHandler;
|
|
874
902
|
}
|
|
875
903
|
window.__electrobunSendToHost = (message) => {
|
|
876
904
|
emitWebviewEvent("host-message", JSON.stringify(message));
|