electrobun 1.16.0 → 1.17.0-beta.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.
@@ -705,30 +705,108 @@ export const native = (() => {
705
705
  // },
706
706
  });
707
707
  } catch (err) {
708
- console.log("FATAL Error opening native FFI:", (err as Error).message);
709
- console.log("This may be due to:");
710
- console.log(" - Missing libNativeWrapper.dll/so/dylib");
711
- console.log(" - Architecture mismatch (ARM64 vs x64)");
712
- console.log(" - Missing WebView2 or CEF dependencies");
713
- if (suffix === "so") {
714
- console.log(
715
- " - Missing system libraries (try: ldd ./libNativeWrapper.so)",
716
- );
717
- }
718
- console.log(
719
- "Check that the build process completed successfully for your architecture.",
720
- );
721
- process.exit();
708
+ // FFI not available running as a carrot inside Bunny Ears or in a build-only context.
709
+ return null;
722
710
  }
723
711
  })();
724
712
 
713
+ export const hasFFI = native !== null;
714
+
715
+ // PostMessage bridge for carrot workers (inter-carrot communication, host events).
716
+ // Created when __bunnyCarrotBootstrap exists, regardless of FFI availability.
717
+ class PostMessageBridge {
718
+ private requestId = 0;
719
+ private pendingRequests = new Map<number, {
720
+ resolve: (value: unknown) => void;
721
+ reject: (error: Error) => void;
722
+ }>();
723
+ private eventHandlers = new Map<string, Set<(payload: unknown) => void>>();
724
+
725
+ constructor() {
726
+ if (typeof self !== "undefined" && typeof self.addEventListener === "function") {
727
+ self.addEventListener("message", (event: MessageEvent) => {
728
+ this.handleMessage(event.data);
729
+ });
730
+ }
731
+ }
732
+
733
+ sendAction(action: string, payload?: unknown) {
734
+ self.postMessage({ type: "action", action, payload });
735
+ }
736
+
737
+ requestHost<T = unknown>(method: string, params?: unknown): Promise<T> {
738
+ const id = ++this.requestId;
739
+ self.postMessage({ type: "host-request", requestId: id, method, params });
740
+ return new Promise<T>((resolve, reject) => {
741
+ this.pendingRequests.set(id, {
742
+ resolve: (v) => resolve(v as T),
743
+ reject,
744
+ });
745
+ });
746
+ }
747
+
748
+ on(name: string, handler: (payload: unknown) => void) {
749
+ const handlers = this.eventHandlers.get(name) ?? new Set();
750
+ handlers.add(handler);
751
+ this.eventHandlers.set(name, handlers);
752
+ return () => {
753
+ handlers.delete(handler);
754
+ if (handlers.size === 0) this.eventHandlers.delete(name);
755
+ };
756
+ }
757
+
758
+ emit(name: string, payload: unknown) {
759
+ this.eventHandlers.get(name)?.forEach((h) => {
760
+ try { h(payload); } catch (e) { console.error(`[bridge] event handler failed: ${name}`, e); }
761
+ });
762
+ }
763
+
764
+ private handleMessage(message: any) {
765
+ if (!message || typeof message !== "object" || !("type" in message)) return;
766
+
767
+ if (message.type === "host-response") {
768
+ const pending = this.pendingRequests.get(message.requestId);
769
+ if (!pending) return;
770
+ this.pendingRequests.delete(message.requestId);
771
+ if (message.success) {
772
+ pending.resolve(message.payload);
773
+ } else {
774
+ pending.reject(new Error(message.error || "Host request failed"));
775
+ }
776
+ } else if (message.type === "event") {
777
+ this.emit(message.name, message.payload);
778
+ } else if (message.type === "init") {
779
+ this.emit("init", message);
780
+ }
781
+ }
782
+ }
783
+
784
+ const isCarrotWorker = !!(globalThis as any).__bunnyCarrotBootstrap;
785
+ export const bridge: PostMessageBridge | null = isCarrotWorker ? new PostMessageBridge() : null;
786
+
787
+ // Proxy wrapper: routes ffi.request calls through FFI when available,
788
+ // or through the postMessage bridge when running as a carrot without FFI.
789
+ function createFfiRequestProxy(ffiRequest: Record<string, Function>): Record<string, Function> {
790
+ if (hasFFI) return ffiRequest;
791
+
792
+ return new Proxy(ffiRequest, {
793
+ get(target, method: string) {
794
+ if (typeof method !== "string") return target[method];
795
+ return (params?: unknown) => bridge!.requestHost(method, params);
796
+ },
797
+ });
798
+ }
799
+
725
800
  // const _callbacks: unknown[] = [];
726
801
 
727
802
  // NOTE: Bun seems to hit limits on args or arg types. eg: trying to send 12 bools results
728
803
  // in only about 8 going through then params after that. I think it may be similar to
729
804
  // a zig bug I ran into last year. So check number of args in a signature when alignment issues occur.
730
805
 
731
- export const ffi = {
806
+ // Non-null accessor for use inside _ffiImpl — these methods are only called when hasFFI is true.
807
+ const native_ = native!;
808
+
809
+ const _ffiImpl = {
732
810
  request: {
733
811
  createWindow: (params: {
734
812
  id: number;
@@ -782,7 +860,7 @@ export const ffi = {
782
860
  hidden = false,
783
861
  } = params;
784
862
 
785
- const styleMask = native.symbols.getWindowStyle(
863
+ const styleMask = native_.symbols.getWindowStyle(
786
864
  Borderless,
787
865
  Titled,
788
866
  Closable,
@@ -797,7 +875,7 @@ export const ffi = {
797
875
  HUDWindow,
798
876
  );
799
877
 
800
- const windowPtr = native.symbols.createWindowWithFrameAndStyleFromWorker(
878
+ const windowPtr = native_.symbols.createWindowWithFrameAndStyleFromWorker(
801
879
  id,
802
880
  // frame
803
881
  x,
@@ -821,9 +899,9 @@ export const ffi = {
821
899
  throw "Failed to create window";
822
900
  }
823
901
 
824
- native.symbols.setWindowTitle(windowPtr, toCString(title));
902
+ native_.symbols.setWindowTitle(windowPtr, toCString(title));
825
903
  if (!hidden) {
826
- native.symbols.showWindow(windowPtr);
904
+ native_.symbols.showWindow(windowPtr);
827
905
  }
828
906
 
829
907
  return windowPtr;
@@ -836,7 +914,7 @@ export const ffi = {
836
914
  throw `Can't add webview to window. window no longer exists`;
837
915
  }
838
916
 
839
- native.symbols.setWindowTitle(windowPtr, toCString(title));
917
+ native_.symbols.setWindowTitle(windowPtr, toCString(title));
840
918
  },
841
919
 
842
920
  closeWindow: (params: { winId: number }) => {
@@ -848,7 +926,7 @@ export const ffi = {
848
926
  return;
849
927
  }
850
928
 
851
- native.symbols.closeWindow(windowPtr);
929
+ native_.symbols.closeWindow(windowPtr);
852
930
  // Note: Cleanup of BrowserWindowMap happens in the windowCloseCallback
853
931
  },
854
932
 
@@ -860,7 +938,7 @@ export const ffi = {
860
938
  throw `Can't focus window. Window no longer exists`;
861
939
  }
862
940
 
863
- native.symbols.showWindow(windowPtr);
941
+ native_.symbols.showWindow(windowPtr);
864
942
  },
865
943
 
866
944
  minimizeWindow: (params: { winId: number }) => {
@@ -871,7 +949,7 @@ export const ffi = {
871
949
  throw `Can't minimize window. Window no longer exists`;
872
950
  }
873
951
 
874
- native.symbols.minimizeWindow(windowPtr);
952
+ native_.symbols.minimizeWindow(windowPtr);
875
953
  },
876
954
 
877
955
  restoreWindow: (params: { winId: number }) => {
@@ -882,7 +960,7 @@ export const ffi = {
882
960
  throw `Can't restore window. Window no longer exists`;
883
961
  }
884
962
 
885
- native.symbols.restoreWindow(windowPtr);
963
+ native_.symbols.restoreWindow(windowPtr);
886
964
  },
887
965
 
888
966
  isWindowMinimized: (params: { winId: number }): boolean => {
@@ -893,7 +971,7 @@ export const ffi = {
893
971
  return false;
894
972
  }
895
973
 
896
- return native.symbols.isWindowMinimized(windowPtr);
974
+ return native_.symbols.isWindowMinimized(windowPtr);
897
975
  },
898
976
 
899
977
  maximizeWindow: (params: { winId: number }) => {
@@ -904,7 +982,7 @@ export const ffi = {
904
982
  throw `Can't maximize window. Window no longer exists`;
905
983
  }
906
984
 
907
- native.symbols.maximizeWindow(windowPtr);
985
+ native_.symbols.maximizeWindow(windowPtr);
908
986
  },
909
987
 
910
988
  unmaximizeWindow: (params: { winId: number }) => {
@@ -915,7 +993,7 @@ export const ffi = {
915
993
  throw `Can't unmaximize window. Window no longer exists`;
916
994
  }
917
995
 
918
- native.symbols.unmaximizeWindow(windowPtr);
996
+ native_.symbols.unmaximizeWindow(windowPtr);
919
997
  },
920
998
 
921
999
  isWindowMaximized: (params: { winId: number }): boolean => {
@@ -926,7 +1004,7 @@ export const ffi = {
926
1004
  return false;
927
1005
  }
928
1006
 
929
- return native.symbols.isWindowMaximized(windowPtr);
1007
+ return native_.symbols.isWindowMaximized(windowPtr);
930
1008
  },
931
1009
 
932
1010
  setWindowFullScreen: (params: { winId: number; fullScreen: boolean }) => {
@@ -937,7 +1015,7 @@ export const ffi = {
937
1015
  throw `Can't set fullscreen. Window no longer exists`;
938
1016
  }
939
1017
 
940
- native.symbols.setWindowFullScreen(windowPtr, fullScreen);
1018
+ native_.symbols.setWindowFullScreen(windowPtr, fullScreen);
941
1019
  },
942
1020
 
943
1021
  isWindowFullScreen: (params: { winId: number }): boolean => {
@@ -948,7 +1026,7 @@ export const ffi = {
948
1026
  return false;
949
1027
  }
950
1028
 
951
- return native.symbols.isWindowFullScreen(windowPtr);
1029
+ return native_.symbols.isWindowFullScreen(windowPtr);
952
1030
  },
953
1031
 
954
1032
  setWindowAlwaysOnTop: (params: { winId: number; alwaysOnTop: boolean }) => {
@@ -959,7 +1037,7 @@ export const ffi = {
959
1037
  throw `Can't set always on top. Window no longer exists`;
960
1038
  }
961
1039
 
962
- native.symbols.setWindowAlwaysOnTop(windowPtr, alwaysOnTop);
1040
+ native_.symbols.setWindowAlwaysOnTop(windowPtr, alwaysOnTop);
963
1041
  },
964
1042
 
965
1043
  isWindowAlwaysOnTop: (params: { winId: number }): boolean => {
@@ -970,7 +1048,7 @@ export const ffi = {
970
1048
  return false;
971
1049
  }
972
1050
 
973
- return native.symbols.isWindowAlwaysOnTop(windowPtr);
1051
+ return native_.symbols.isWindowAlwaysOnTop(windowPtr);
974
1052
  },
975
1053
 
976
1054
  setWindowVisibleOnAllWorkspaces: (params: {
@@ -984,7 +1062,7 @@ export const ffi = {
984
1062
  throw `Can't set visible on all workspaces. Window no longer exists`;
985
1063
  }
986
1064
 
987
- native.symbols.setWindowVisibleOnAllWorkspaces(
1065
+ native_.symbols.setWindowVisibleOnAllWorkspaces(
988
1066
  windowPtr,
989
1067
  visibleOnAllWorkspaces,
990
1068
  );
@@ -998,7 +1076,7 @@ export const ffi = {
998
1076
  return false;
999
1077
  }
1000
1078
 
1001
- return native.symbols.isWindowVisibleOnAllWorkspaces(windowPtr);
1079
+ return native_.symbols.isWindowVisibleOnAllWorkspaces(windowPtr);
1002
1080
  },
1003
1081
 
1004
1082
  setWindowPosition: (params: { winId: number; x: number; y: number }) => {
@@ -1009,7 +1087,7 @@ export const ffi = {
1009
1087
  throw `Can't set window position. Window no longer exists`;
1010
1088
  }
1011
1089
 
1012
- native.symbols.setWindowPosition(windowPtr, x, y);
1090
+ native_.symbols.setWindowPosition(windowPtr, x, y);
1013
1091
  },
1014
1092
 
1015
1093
  setWindowSize: (params: {
@@ -1024,7 +1102,7 @@ export const ffi = {
1024
1102
  throw `Can't set window size. Window no longer exists`;
1025
1103
  }
1026
1104
 
1027
- native.symbols.setWindowSize(windowPtr, width, height);
1105
+ native_.symbols.setWindowSize(windowPtr, width, height);
1028
1106
  },
1029
1107
 
1030
1108
  setWindowFrame: (params: {
@@ -1041,7 +1119,7 @@ export const ffi = {
1041
1119
  throw `Can't set window frame. Window no longer exists`;
1042
1120
  }
1043
1121
 
1044
- native.symbols.setWindowFrame(windowPtr, x, y, width, height);
1122
+ native_.symbols.setWindowFrame(windowPtr, x, y, width, height);
1045
1123
  },
1046
1124
 
1047
1125
  getWindowFrame: (params: {
@@ -1060,7 +1138,7 @@ export const ffi = {
1060
1138
  const widthBuf = new Float64Array(1);
1061
1139
  const heightBuf = new Float64Array(1);
1062
1140
 
1063
- native.symbols.getWindowFrame(
1141
+ native_.symbols.getWindowFrame(
1064
1142
  windowPtr,
1065
1143
  ptr(xBuf),
1066
1144
  ptr(yBuf),
@@ -1172,8 +1250,8 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1172
1250
  const customPreload = preload;
1173
1251
 
1174
1252
  // Pre-set flags before initWebview (workaround for FFI param count limits)
1175
- native.symbols.setNextWebviewFlags(startTransparent, startPassthrough);
1176
- const webviewPtr = native.symbols.initWebview(
1253
+ native_.symbols.setNextWebviewFlags(startTransparent, startPassthrough);
1254
+ const webviewPtr = native_.symbols.initWebview(
1177
1255
  id,
1178
1256
  windowPtr,
1179
1257
  toCString(renderer),
@@ -1230,7 +1308,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1230
1308
  throw `Can't add WGPUView to window. window no longer exists`;
1231
1309
  }
1232
1310
 
1233
- const viewPtr = native.symbols.initWGPUView(
1311
+ const viewPtr = native_.symbols.initWGPUView(
1234
1312
  id,
1235
1313
  windowPtr,
1236
1314
  x,
@@ -1264,7 +1342,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1264
1342
  return;
1265
1343
  }
1266
1344
 
1267
- native.symbols.wgpuViewSetFrame(
1345
+ native_.symbols.wgpuViewSetFrame(
1268
1346
  view.ptr,
1269
1347
  params.x,
1270
1348
  params.y,
@@ -1282,7 +1360,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1282
1360
  return;
1283
1361
  }
1284
1362
 
1285
- native.symbols.wgpuViewSetTransparent(view.ptr, params.transparent);
1363
+ native_.symbols.wgpuViewSetTransparent(view.ptr, params.transparent);
1286
1364
  },
1287
1365
 
1288
1366
  wgpuViewSetPassthrough: (params: {
@@ -1297,7 +1375,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1297
1375
  return;
1298
1376
  }
1299
1377
 
1300
- native.symbols.wgpuViewSetPassthrough(view.ptr, params.passthrough);
1378
+ native_.symbols.wgpuViewSetPassthrough(view.ptr, params.passthrough);
1301
1379
  },
1302
1380
 
1303
1381
  wgpuViewSetHidden: (params: { id: number; hidden: boolean }) => {
@@ -1309,7 +1387,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1309
1387
  return;
1310
1388
  }
1311
1389
 
1312
- native.symbols.wgpuViewSetHidden(view.ptr, params.hidden);
1390
+ native_.symbols.wgpuViewSetHidden(view.ptr, params.hidden);
1313
1391
  },
1314
1392
 
1315
1393
  wgpuViewRemove: (params: { id: number }) => {
@@ -1321,7 +1399,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1321
1399
  return;
1322
1400
  }
1323
1401
 
1324
- native.symbols.wgpuViewRemove(view.ptr);
1402
+ native_.symbols.wgpuViewRemove(view.ptr);
1325
1403
  },
1326
1404
  wgpuViewGetNativeHandle: (params: { id: number }): Pointer | null => {
1327
1405
  const view = WGPUView.getById(params.id);
@@ -1332,7 +1410,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1332
1410
  return null;
1333
1411
  }
1334
1412
 
1335
- const handle = native.symbols.wgpuViewGetNativeHandle(view.ptr);
1413
+ const handle = native_.symbols.wgpuViewGetNativeHandle(view.ptr);
1336
1414
  return handle || null;
1337
1415
  },
1338
1416
 
@@ -1347,7 +1425,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1347
1425
  return;
1348
1426
  }
1349
1427
 
1350
- native.symbols.evaluateJavaScriptWithNoCompletion(
1428
+ native_.symbols.evaluateJavaScriptWithNoCompletion(
1351
1429
  webview.ptr,
1352
1430
  toCString(js),
1353
1431
  );
@@ -1363,7 +1441,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1363
1441
  }): FFIType.ptr => {
1364
1442
  const { id, title, image, template, width, height } = params;
1365
1443
 
1366
- const trayPtr = native.symbols.createTray(
1444
+ const trayPtr = native_.symbols.createTray(
1367
1445
  id,
1368
1446
  toCString(title),
1369
1447
  toCString(image),
@@ -1385,7 +1463,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1385
1463
  const tray = Tray.getById(id);
1386
1464
  if (!tray) return;
1387
1465
 
1388
- native.symbols.setTrayTitle(tray.ptr, toCString(title));
1466
+ native_.symbols.setTrayTitle(tray.ptr, toCString(title));
1389
1467
  },
1390
1468
  setTrayImage: (params: { id: number; image: string }): void => {
1391
1469
  const { id, image } = params;
@@ -1393,7 +1471,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1393
1471
  const tray = Tray.getById(id);
1394
1472
  if (!tray) return;
1395
1473
 
1396
- native.symbols.setTrayImage(tray.ptr, toCString(image));
1474
+ native_.symbols.setTrayImage(tray.ptr, toCString(image));
1397
1475
  },
1398
1476
  setTrayMenu: (params: {
1399
1477
  id: number;
@@ -1405,7 +1483,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1405
1483
  const tray = Tray.getById(id);
1406
1484
  if (!tray) return;
1407
1485
 
1408
- native.symbols.setTrayMenu(tray.ptr, toCString(menuConfig));
1486
+ native_.symbols.setTrayMenu(tray.ptr, toCString(menuConfig));
1409
1487
  },
1410
1488
 
1411
1489
  removeTray: (params: { id: number }): void => {
@@ -1416,7 +1494,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1416
1494
  throw `Can't remove tray. Tray no longer exists`;
1417
1495
  }
1418
1496
 
1419
- native.symbols.removeTray(tray.ptr);
1497
+ native_.symbols.removeTray(tray.ptr);
1420
1498
  // The Tray class will handle removing from TrayMap
1421
1499
  },
1422
1500
  getTrayBounds: (params: { id: number }): Rectangle => {
@@ -1425,7 +1503,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1425
1503
  return { x: 0, y: 0, width: 0, height: 0 };
1426
1504
  }
1427
1505
 
1428
- const jsonStr = native.symbols.getTrayBounds(tray.ptr);
1506
+ const jsonStr = native_.symbols.getTrayBounds(tray.ptr);
1429
1507
  if (!jsonStr) {
1430
1508
  return { x: 0, y: 0, width: 0, height: 0 };
1431
1509
  }
@@ -1439,7 +1517,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1439
1517
  setApplicationMenu: (params: { menuConfig: string }): void => {
1440
1518
  const { menuConfig } = params;
1441
1519
 
1442
- native.symbols.setApplicationMenu(
1520
+ native_.symbols.setApplicationMenu(
1443
1521
  toCString(menuConfig),
1444
1522
  applicationMenuHandler,
1445
1523
  );
@@ -1447,25 +1525,25 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1447
1525
  showContextMenu: (params: { menuConfig: string }): void => {
1448
1526
  const { menuConfig } = params;
1449
1527
 
1450
- native.symbols.showContextMenu(toCString(menuConfig), contextMenuHandler);
1528
+ native_.symbols.showContextMenu(toCString(menuConfig), contextMenuHandler);
1451
1529
  },
1452
1530
  moveToTrash: (params: { path: string }): boolean => {
1453
1531
  const { path } = params;
1454
1532
 
1455
- return native.symbols.moveToTrash(toCString(path));
1533
+ return native_.symbols.moveToTrash(toCString(path));
1456
1534
  },
1457
1535
  showItemInFolder: (params: { path: string }): void => {
1458
1536
  const { path } = params;
1459
1537
 
1460
- native.symbols.showItemInFolder(toCString(path));
1538
+ native_.symbols.showItemInFolder(toCString(path));
1461
1539
  },
1462
1540
  openExternal: (params: { url: string }): boolean => {
1463
1541
  const { url } = params;
1464
- return native.symbols.openExternal(toCString(url));
1542
+ return native_.symbols.openExternal(toCString(url));
1465
1543
  },
1466
1544
  openPath: (params: { path: string }): boolean => {
1467
1545
  const { path } = params;
1468
- return native.symbols.openPath(toCString(path));
1546
+ return native_.symbols.openPath(toCString(path));
1469
1547
  },
1470
1548
  showNotification: (params: {
1471
1549
  title: string;
@@ -1474,7 +1552,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1474
1552
  silent?: boolean;
1475
1553
  }): void => {
1476
1554
  const { title, body = "", subtitle = "", silent = false } = params;
1477
- native.symbols.showNotification(
1555
+ native_.symbols.showNotification(
1478
1556
  toCString(title),
1479
1557
  toCString(body),
1480
1558
  toCString(subtitle),
@@ -1482,10 +1560,10 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1482
1560
  );
1483
1561
  },
1484
1562
  setDockIconVisible: (params: { visible: boolean }): void => {
1485
- native.symbols.setDockIconVisible(params.visible);
1563
+ native_.symbols.setDockIconVisible(params.visible);
1486
1564
  },
1487
1565
  isDockIconVisible: (): boolean => {
1488
- return native.symbols.isDockIconVisible();
1566
+ return native_.symbols.isDockIconVisible();
1489
1567
  },
1490
1568
  openFileDialog: (params: {
1491
1569
  startingFolder: string;
@@ -1501,7 +1579,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1501
1579
  canChooseDirectory,
1502
1580
  allowsMultipleSelection,
1503
1581
  } = params;
1504
- const filePath = native.symbols.openFileDialog(
1582
+ const filePath = native_.symbols.openFileDialog(
1505
1583
  toCString(startingFolder),
1506
1584
  toCString(allowedFileTypes),
1507
1585
  canChooseFiles ? 1 : 0,
@@ -1531,7 +1609,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1531
1609
  } = params;
1532
1610
  // Convert buttons array to comma-separated string
1533
1611
  const buttonsStr = buttons.join(",");
1534
- return native.symbols.showMessageBox(
1612
+ return native_.symbols.showMessageBox(
1535
1613
  toCString(type),
1536
1614
  toCString(title),
1537
1615
  toCString(message),
@@ -1544,17 +1622,17 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1544
1622
 
1545
1623
  // Clipboard API
1546
1624
  clipboardReadText: (): string | null => {
1547
- const result = native.symbols.clipboardReadText();
1625
+ const result = native_.symbols.clipboardReadText();
1548
1626
  if (!result) return null;
1549
1627
  return result.toString();
1550
1628
  },
1551
1629
  clipboardWriteText: (params: { text: string }): void => {
1552
- native.symbols.clipboardWriteText(toCString(params.text));
1630
+ native_.symbols.clipboardWriteText(toCString(params.text));
1553
1631
  },
1554
1632
  clipboardReadImage: (): Uint8Array | null => {
1555
1633
  // Allocate a buffer for the size output
1556
1634
  const sizeBuffer = new BigUint64Array(1);
1557
- const dataPtr = native.symbols.clipboardReadImage(ptr(sizeBuffer));
1635
+ const dataPtr = native_.symbols.clipboardReadImage(ptr(sizeBuffer));
1558
1636
 
1559
1637
  if (!dataPtr) return null;
1560
1638
 
@@ -1574,13 +1652,13 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1574
1652
  },
1575
1653
  clipboardWriteImage: (params: { pngData: Uint8Array }): void => {
1576
1654
  const { pngData } = params;
1577
- native.symbols.clipboardWriteImage(ptr(pngData), BigInt(pngData.length));
1655
+ native_.symbols.clipboardWriteImage(ptr(pngData), BigInt(pngData.length));
1578
1656
  },
1579
1657
  clipboardClear: (): void => {
1580
- native.symbols.clipboardClear();
1658
+ native_.symbols.clipboardClear();
1581
1659
  },
1582
1660
  clipboardAvailableFormats: (): string[] => {
1583
- const result = native.symbols.clipboardAvailableFormats();
1661
+ const result = native_.symbols.clipboardAvailableFormats();
1584
1662
  if (!result) return [];
1585
1663
  const formatsStr = result.toString();
1586
1664
  if (!formatsStr) return [];
@@ -1592,7 +1670,7 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1592
1670
 
1593
1671
  // } = params;
1594
1672
 
1595
- // native.symbols.ffifunc(
1673
+ // native_.symbols.ffifunc(
1596
1674
 
1597
1675
  // );
1598
1676
  // },
@@ -1607,27 +1685,32 @@ window.__electrobunBunBridge = window.__electrobunBunBridge || window.webkit?.me
1607
1685
  },
1608
1686
  };
1609
1687
 
1688
+ export const ffi = {
1689
+ request: createFfiRequestProxy(_ffiImpl.request as unknown as Record<string, Function>) as typeof _ffiImpl.request,
1690
+ internal: _ffiImpl.internal,
1691
+ };
1692
+
1610
1693
  export const WGPUBridge = {
1611
1694
  available: !!native?.symbols?.wgpuInstanceCreateSurfaceMainThread,
1612
1695
  instanceCreateSurface: (instancePtr: Pointer, descriptorPtr: Pointer): Pointer =>
1613
- native.symbols.wgpuInstanceCreateSurfaceMainThread(
1696
+ native_.symbols.wgpuInstanceCreateSurfaceMainThread(
1614
1697
  instancePtr as any,
1615
1698
  descriptorPtr as any,
1616
1699
  ) as Pointer,
1617
1700
  surfaceConfigure: (surfacePtr: Pointer, configPtr: Pointer) =>
1618
- native.symbols.wgpuSurfaceConfigureMainThread(
1701
+ native_.symbols.wgpuSurfaceConfigureMainThread(
1619
1702
  surfacePtr as any,
1620
1703
  configPtr as any,
1621
1704
  ),
1622
1705
  surfaceGetCurrentTexture: (surfacePtr: Pointer, surfaceTexturePtr: Pointer) =>
1623
- native.symbols.wgpuSurfaceGetCurrentTextureMainThread(
1706
+ native_.symbols.wgpuSurfaceGetCurrentTextureMainThread(
1624
1707
  surfacePtr as any,
1625
1708
  surfaceTexturePtr as any,
1626
1709
  ),
1627
1710
  surfacePresent: (surfacePtr: Pointer): number =>
1628
- native.symbols.wgpuSurfacePresentMainThread(surfacePtr as any),
1711
+ native_.symbols.wgpuSurfacePresentMainThread(surfacePtr as any),
1629
1712
  queueOnSubmittedWorkDone: (queuePtr: Pointer, callbackInfoPtr: Pointer): bigint =>
1630
- native.symbols.wgpuQueueOnSubmittedWorkDoneShim(
1713
+ native_.symbols.wgpuQueueOnSubmittedWorkDoneShim(
1631
1714
  queuePtr as any,
1632
1715
  callbackInfoPtr as any,
1633
1716
  ),
@@ -1638,7 +1721,7 @@ export const WGPUBridge = {
1638
1721
  size: bigint,
1639
1722
  callbackInfoPtr: Pointer,
1640
1723
  ): bigint =>
1641
- native.symbols.wgpuBufferMapAsyncShim(
1724
+ native_.symbols.wgpuBufferMapAsyncShim(
1642
1725
  bufferPtr as any,
1643
1726
  mode as any,
1644
1727
  offset as any,
@@ -1650,7 +1733,7 @@ export const WGPUBridge = {
1650
1733
  futureId: bigint,
1651
1734
  timeoutNs: bigint,
1652
1735
  ): number =>
1653
- native.symbols.wgpuInstanceWaitAnyShim(
1736
+ native_.symbols.wgpuInstanceWaitAnyShim(
1654
1737
  instancePtr as any,
1655
1738
  futureId as any,
1656
1739
  timeoutNs as any,
@@ -1663,7 +1746,7 @@ export const WGPUBridge = {
1663
1746
  timeoutNs: bigint,
1664
1747
  outSizePtr: Pointer,
1665
1748
  ): Pointer =>
1666
- native.symbols.wgpuBufferReadSyncShim(
1749
+ native_.symbols.wgpuBufferReadSyncShim(
1667
1750
  instancePtr as any,
1668
1751
  bufferPtr as any,
1669
1752
  offset as any,
@@ -1679,7 +1762,7 @@ export const WGPUBridge = {
1679
1762
  timeoutNs: bigint,
1680
1763
  dstPtr: Pointer,
1681
1764
  ): number =>
1682
- native.symbols.wgpuBufferReadSyncIntoShim(
1765
+ native_.symbols.wgpuBufferReadSyncIntoShim(
1683
1766
  instancePtr as any,
1684
1767
  bufferPtr as any,
1685
1768
  offset as any,
@@ -1693,16 +1776,16 @@ export const WGPUBridge = {
1693
1776
  size: bigint,
1694
1777
  dstPtr: Pointer,
1695
1778
  ): Pointer =>
1696
- native.symbols.wgpuBufferReadbackBeginShim(
1779
+ native_.symbols.wgpuBufferReadbackBeginShim(
1697
1780
  bufferPtr as any,
1698
1781
  offset as any,
1699
1782
  size as any,
1700
1783
  dstPtr as any,
1701
1784
  ) as Pointer,
1702
1785
  bufferReadbackStatus: (jobPtr: Pointer): number =>
1703
- native.symbols.wgpuBufferReadbackStatusShim(jobPtr as any),
1786
+ native_.symbols.wgpuBufferReadbackStatusShim(jobPtr as any),
1704
1787
  bufferReadbackFree: (jobPtr: Pointer) =>
1705
- native.symbols.wgpuBufferReadbackFreeShim(jobPtr as any),
1788
+ native_.symbols.wgpuBufferReadbackFreeShim(jobPtr as any),
1706
1789
  runTest: (viewId: number) => {
1707
1790
  const view = WGPUView.getById(viewId);
1708
1791
  if (!view?.ptr) {
@@ -1713,31 +1796,34 @@ export const WGPUBridge = {
1713
1796
  console.error("wgpuRunGPUTest not available");
1714
1797
  return;
1715
1798
  }
1716
- native.symbols.wgpuRunGPUTest(view.ptr);
1799
+ native_.symbols.wgpuRunGPUTest(view.ptr);
1717
1800
  },
1718
1801
  createAdapterDeviceMainThread: (
1719
1802
  instancePtr: Pointer,
1720
1803
  surfacePtr: Pointer,
1721
1804
  outAdapterDevicePtr: Pointer,
1722
1805
  ) =>
1723
- native.symbols.wgpuCreateAdapterDeviceMainThread(
1806
+ native_.symbols.wgpuCreateAdapterDeviceMainThread(
1724
1807
  instancePtr as any,
1725
1808
  surfacePtr as any,
1726
1809
  outAdapterDevicePtr as any,
1727
1810
  ),
1728
1811
  createSurfaceForView: (instancePtr: Pointer, viewPtr: Pointer): Pointer | null => {
1729
1812
  if (!native?.symbols?.wgpuCreateSurfaceForView) return null;
1730
- return native.symbols.wgpuCreateSurfaceForView(instancePtr as any, viewPtr as any) as Pointer;
1813
+ return native_.symbols.wgpuCreateSurfaceForView(instancePtr as any, viewPtr as any) as Pointer;
1731
1814
  },
1732
1815
  };
1733
1816
 
1734
1817
  // Worker management. Move to a different file
1735
1818
  process.on("uncaughtException", (err) => {
1736
1819
  console.error("Uncaught exception in worker:", err);
1737
- // Fast path for crashes - skip beforeQuit, just stop the event loop
1738
- native.symbols.stopEventLoop();
1739
- native.symbols.waitForShutdownComplete(5000);
1740
- native.symbols.forceExit(1);
1820
+ if (native) {
1821
+ native_.symbols.stopEventLoop();
1822
+ native_.symbols.waitForShutdownComplete(5000);
1823
+ native_.symbols.forceExit(1);
1824
+ } else {
1825
+ process.exit(1);
1826
+ }
1741
1827
  });
1742
1828
 
1743
1829
  process.on("unhandledRejection", (reason, _promise) => {
@@ -1919,89 +2005,61 @@ const getHTMLForWebviewSync = new JSCallback(
1919
2005
  },
1920
2006
  );
1921
2007
 
1922
- native.symbols.setJSUtils(getMimeType, getHTMLForWebviewSync);
2008
+ if (native) native_.symbols.setJSUtils(getMimeType, getHTMLForWebviewSync);
1923
2009
 
1924
- // URL scheme open handler (macOS only)
1925
- // Receives URLs when the app is opened via custom URL schemes (e.g., myapp://path)
1926
- const urlOpenCallback = new JSCallback(
1927
- (urlPtr) => {
1928
- const url = new CString(urlPtr).toString();
1929
- const handler = electrobunEventEmitter.events.app.openUrl;
1930
- const event = handler({ url });
1931
- electrobunEventEmitter.emitEvent(event);
1932
- },
1933
- {
1934
- args: [FFIType.cstring],
1935
- returns: "void",
1936
- threadsafe: true,
1937
- },
1938
- );
2010
+ // Native-only init: URL scheme handlers, quit handler, global shortcuts.
2011
+ // Skipped when running without FFI (carrot mode).
2012
+ const globalShortcutHandlers = new Map<string, () => void>();
1939
2013
 
1940
- // Register the URL open handler with native code (macOS only)
1941
- if (process.platform === "darwin") {
1942
- native.symbols.setURLOpenHandler(urlOpenCallback);
1943
- }
2014
+ if (native) {
2015
+ const urlOpenCallback = new JSCallback(
2016
+ (urlPtr) => {
2017
+ const url = new CString(urlPtr).toString();
2018
+ const handler = electrobunEventEmitter.events.app.openUrl;
2019
+ const event = handler({ url });
2020
+ electrobunEventEmitter.emitEvent(event);
2021
+ },
2022
+ { args: [FFIType.cstring], returns: "void", threadsafe: true },
2023
+ );
2024
+ if (process.platform === "darwin") {
2025
+ native_.symbols.setURLOpenHandler(urlOpenCallback);
2026
+ }
1944
2027
 
1945
- const appReopenCallback = new JSCallback(
1946
- () => {
1947
- if (process.platform === "darwin") {
1948
- native.symbols.setDockIconVisible(true);
1949
- }
2028
+ const appReopenCallback = new JSCallback(
2029
+ () => {
2030
+ if (process.platform === "darwin") {
2031
+ native_.symbols.setDockIconVisible(true);
2032
+ }
2033
+ const handler = electrobunEventEmitter.events.app.reopen;
2034
+ const event = handler({});
2035
+ electrobunEventEmitter.emitEvent(event);
2036
+ },
2037
+ { args: [], returns: "void", threadsafe: true },
2038
+ );
2039
+ if (process.platform === "darwin") {
2040
+ native_.symbols.setAppReopenHandler(appReopenCallback);
2041
+ }
1950
2042
 
1951
- const handler = electrobunEventEmitter.events.app.reopen;
1952
- const event = handler({});
1953
- electrobunEventEmitter.emitEvent(event);
1954
- },
1955
- {
1956
- args: [],
1957
- returns: "void",
1958
- threadsafe: true,
1959
- },
1960
- );
2043
+ const quitRequestedCallback = new JSCallback(
2044
+ () => {
2045
+ const { quit } = require("../core/Utils");
2046
+ quit();
2047
+ },
2048
+ { args: [], returns: "void", threadsafe: true },
2049
+ );
2050
+ native_.symbols.setQuitRequestedHandler(quitRequestedCallback);
1961
2051
 
1962
- if (process.platform === "darwin") {
1963
- native.symbols.setAppReopenHandler(appReopenCallback);
2052
+ const globalShortcutCallback = new JSCallback(
2053
+ (acceleratorPtr) => {
2054
+ const accelerator = new CString(acceleratorPtr).toString();
2055
+ const handler = globalShortcutHandlers.get(accelerator);
2056
+ if (handler) handler();
2057
+ },
2058
+ { args: [FFIType.cstring], returns: "void", threadsafe: true },
2059
+ );
2060
+ native_.symbols.setGlobalShortcutCallback(globalShortcutCallback);
1964
2061
  }
1965
2062
 
1966
- // Quit requested callback - invoked by native code when system quit is requested
1967
- // (dock icon quit, menu quit, console close, etc.)
1968
- const quitRequestedCallback = new JSCallback(
1969
- () => {
1970
- // Dynamic require to avoid circular dependency (Utils.ts imports from native.ts)
1971
- const { quit } = require("../core/Utils");
1972
- quit();
1973
- },
1974
- {
1975
- args: [],
1976
- returns: "void",
1977
- threadsafe: true,
1978
- },
1979
- );
1980
-
1981
- // Register the quit handler with native code (all platforms)
1982
- native.symbols.setQuitRequestedHandler(quitRequestedCallback);
1983
-
1984
- // Global shortcut storage and callback
1985
- const globalShortcutHandlers = new Map<string, () => void>();
1986
-
1987
- const globalShortcutCallback = new JSCallback(
1988
- (acceleratorPtr) => {
1989
- const accelerator = new CString(acceleratorPtr).toString();
1990
- const handler = globalShortcutHandlers.get(accelerator);
1991
- if (handler) {
1992
- handler();
1993
- }
1994
- },
1995
- {
1996
- args: [FFIType.cstring],
1997
- returns: "void",
1998
- threadsafe: true,
1999
- },
2000
- );
2001
-
2002
- // Set up the global shortcut callback
2003
- native.symbols.setGlobalShortcutCallback(globalShortcutCallback);
2004
-
2005
2063
  // GlobalShortcut module for external use
2006
2064
  export const GlobalShortcut = {
2007
2065
  /**
@@ -2011,49 +2069,24 @@ export const GlobalShortcut = {
2011
2069
  * @returns true if registered successfully, false otherwise
2012
2070
  */
2013
2071
  register: (accelerator: string, callback: () => void): boolean => {
2014
- if (globalShortcutHandlers.has(accelerator)) {
2015
- return false; // Already registered
2016
- }
2017
-
2018
- const result = native.symbols.registerGlobalShortcut(
2019
- toCString(accelerator),
2020
- );
2021
- if (result) {
2022
- globalShortcutHandlers.set(accelerator, callback);
2023
- }
2072
+ if (!native || globalShortcutHandlers.has(accelerator)) return false;
2073
+ const result = native_.symbols.registerGlobalShortcut(toCString(accelerator));
2074
+ if (result) globalShortcutHandlers.set(accelerator, callback);
2024
2075
  return result;
2025
2076
  },
2026
-
2027
- /**
2028
- * Unregister a global keyboard shortcut
2029
- * @param accelerator - The shortcut string to unregister
2030
- * @returns true if unregistered successfully, false otherwise
2031
- */
2032
2077
  unregister: (accelerator: string): boolean => {
2033
- const result = native.symbols.unregisterGlobalShortcut(
2034
- toCString(accelerator),
2035
- );
2036
- if (result) {
2037
- globalShortcutHandlers.delete(accelerator);
2038
- }
2078
+ if (!native) return false;
2079
+ const result = native_.symbols.unregisterGlobalShortcut(toCString(accelerator));
2080
+ if (result) globalShortcutHandlers.delete(accelerator);
2039
2081
  return result;
2040
2082
  },
2041
-
2042
- /**
2043
- * Unregister all global keyboard shortcuts
2044
- */
2045
2083
  unregisterAll: (): void => {
2046
- native.symbols.unregisterAllGlobalShortcuts();
2084
+ if (native) native_.symbols.unregisterAllGlobalShortcuts();
2047
2085
  globalShortcutHandlers.clear();
2048
2086
  },
2049
-
2050
- /**
2051
- * Check if a shortcut is registered
2052
- * @param accelerator - The shortcut string to check
2053
- * @returns true if registered, false otherwise
2054
- */
2055
2087
  isRegistered: (accelerator: string): boolean => {
2056
- return native.symbols.isGlobalShortcutRegistered(toCString(accelerator));
2088
+ if (!native) return false;
2089
+ return native_.symbols.isGlobalShortcutRegistered(toCString(accelerator));
2057
2090
  },
2058
2091
  };
2059
2092
 
@@ -2085,7 +2118,7 @@ export const Screen = {
2085
2118
  * @returns Display object for the primary monitor
2086
2119
  */
2087
2120
  getPrimaryDisplay: (): Display => {
2088
- const jsonStr = native.symbols.getPrimaryDisplay();
2121
+ const jsonStr = native ? native_.symbols.getPrimaryDisplay() : null;
2089
2122
  if (!jsonStr) {
2090
2123
  return {
2091
2124
  id: 0,
@@ -2113,7 +2146,7 @@ export const Screen = {
2113
2146
  * @returns Array of Display objects
2114
2147
  */
2115
2148
  getAllDisplays: (): Display[] => {
2116
- const jsonStr = native.symbols.getAllDisplays();
2149
+ const jsonStr = native ? native_.symbols.getAllDisplays() : null;
2117
2150
  if (!jsonStr) {
2118
2151
  return [];
2119
2152
  }
@@ -2129,7 +2162,7 @@ export const Screen = {
2129
2162
  * @returns Point with x and y coordinates
2130
2163
  */
2131
2164
  getCursorScreenPoint: (): Point => {
2132
- const jsonStr = native.symbols.getCursorScreenPoint();
2165
+ const jsonStr = native ? native_.symbols.getCursorScreenPoint() : null;
2133
2166
  if (!jsonStr) {
2134
2167
  return { x: 0, y: 0 };
2135
2168
  }
@@ -2145,7 +2178,7 @@ export const Screen = {
2145
2178
  */
2146
2179
  getMouseButtons: (): bigint => {
2147
2180
  try {
2148
- return native.symbols.getMouseButtons();
2181
+ return native ? native_.symbols.getMouseButtons() : BigInt(0);
2149
2182
  } catch {
2150
2183
  return 0n;
2151
2184
  }
@@ -2197,7 +2230,7 @@ class SessionCookies {
2197
2230
  */
2198
2231
  get(filter?: CookieFilter): Cookie[] {
2199
2232
  const filterJson = JSON.stringify(filter || {});
2200
- const result = native.symbols.sessionGetCookies(
2233
+ const result = native_.symbols.sessionGetCookies(
2201
2234
  toCString(this.partitionId),
2202
2235
  toCString(filterJson),
2203
2236
  );
@@ -2216,7 +2249,7 @@ class SessionCookies {
2216
2249
  */
2217
2250
  set(cookie: Cookie): boolean {
2218
2251
  const cookieJson = JSON.stringify(cookie);
2219
- return native.symbols.sessionSetCookie(
2252
+ return native_.symbols.sessionSetCookie(
2220
2253
  toCString(this.partitionId),
2221
2254
  toCString(cookieJson),
2222
2255
  );
@@ -2229,7 +2262,7 @@ class SessionCookies {
2229
2262
  * @returns true if the cookie was removed successfully
2230
2263
  */
2231
2264
  remove(url: string, name: string): boolean {
2232
- return native.symbols.sessionRemoveCookie(
2265
+ return native_.symbols.sessionRemoveCookie(
2233
2266
  toCString(this.partitionId),
2234
2267
  toCString(url),
2235
2268
  toCString(name),
@@ -2240,7 +2273,7 @@ class SessionCookies {
2240
2273
  * Clear all cookies for this session
2241
2274
  */
2242
2275
  clear(): void {
2243
- native.symbols.sessionClearCookies(toCString(this.partitionId));
2276
+ native_.symbols.sessionClearCookies(toCString(this.partitionId));
2244
2277
  }
2245
2278
  }
2246
2279
 
@@ -2260,7 +2293,7 @@ class SessionInstance {
2260
2293
  */
2261
2294
  clearStorageData(types: StorageType[] | "all" = "all"): void {
2262
2295
  const typesArray = types === "all" ? ["all"] : types;
2263
- native.symbols.sessionClearStorageData(
2296
+ native_.symbols.sessionClearStorageData(
2264
2297
  toCString(this.partition),
2265
2298
  toCString(JSON.stringify(typesArray)),
2266
2299
  );
@@ -2334,7 +2367,7 @@ const webviewEventHandler = (id: number, eventName: string, detail: string) => {
2334
2367
  js = `document.querySelector('#electrobun-webview-${id}').emit(${JSON.stringify(eventName)}, ${JSON.stringify(detail)});`;
2335
2368
  }
2336
2369
 
2337
- native.symbols.evaluateJavaScriptWithNoCompletion(
2370
+ native_.symbols.evaluateJavaScriptWithNoCompletion(
2338
2371
  hostWebview.ptr,
2339
2372
  toCString(js),
2340
2373
  );
@@ -2740,7 +2773,7 @@ export const internalRpcHandlers = {
2740
2773
  return false;
2741
2774
  }
2742
2775
 
2743
- return native.symbols.webviewCanGoBack(webviewPtr);
2776
+ return native_.symbols.webviewCanGoBack(webviewPtr);
2744
2777
  },
2745
2778
  webviewTagCanGoForward: (params: { id: number }) => {
2746
2779
  const { id } = params;
@@ -2750,7 +2783,7 @@ export const internalRpcHandlers = {
2750
2783
  return false;
2751
2784
  }
2752
2785
 
2753
- return native.symbols.webviewCanGoForward(webviewPtr);
2786
+ return native_.symbols.webviewCanGoForward(webviewPtr);
2754
2787
  },
2755
2788
  },
2756
2789
  message: {
@@ -2771,7 +2804,7 @@ export const internalRpcHandlers = {
2771
2804
  }
2772
2805
 
2773
2806
  const { x, y, width, height } = params.frame;
2774
- native.symbols.resizeWebview(
2807
+ native_.symbols.resizeWebview(
2775
2808
  webviewPtr,
2776
2809
  x,
2777
2810
  y,
@@ -2794,7 +2827,7 @@ export const internalRpcHandlers = {
2794
2827
  }
2795
2828
 
2796
2829
  const { x, y, width, height } = params.frame;
2797
- native.symbols.resizeWebview(
2830
+ native_.symbols.resizeWebview(
2798
2831
  view.ptr,
2799
2832
  x,
2800
2833
  y,
@@ -2811,7 +2844,7 @@ export const internalRpcHandlers = {
2811
2844
  );
2812
2845
  return;
2813
2846
  }
2814
- native.symbols.loadURLInWebView(webview.ptr, toCString(params.url));
2847
+ native_.symbols.loadURLInWebView(webview.ptr, toCString(params.url));
2815
2848
  },
2816
2849
  webviewTagUpdateHtml: (params: { id: number; html: string }) => {
2817
2850
  const webview = BrowserView.getById(params.id);
@@ -2823,7 +2856,7 @@ export const internalRpcHandlers = {
2823
2856
  }
2824
2857
 
2825
2858
  // Store HTML content in native map for scheme handlers
2826
- native.symbols.setWebviewHTMLContent(webview.id, toCString(params.html));
2859
+ native_.symbols.setWebviewHTMLContent(webview.id, toCString(params.html));
2827
2860
 
2828
2861
  webview.loadHTML(params.html);
2829
2862
  webview.html = params.html;
@@ -2836,7 +2869,7 @@ export const internalRpcHandlers = {
2836
2869
  );
2837
2870
  return;
2838
2871
  }
2839
- native.symbols.updatePreloadScriptToWebView(
2872
+ native_.symbols.updatePreloadScriptToWebView(
2840
2873
  webview.ptr,
2841
2874
  toCString("electrobun_custom_preload_script"),
2842
2875
  toCString(params.preload),
@@ -2851,7 +2884,7 @@ export const internalRpcHandlers = {
2851
2884
  );
2852
2885
  return;
2853
2886
  }
2854
- native.symbols.webviewGoBack(webview.ptr);
2887
+ native_.symbols.webviewGoBack(webview.ptr);
2855
2888
  },
2856
2889
  webviewTagGoForward: (params: { id: number }) => {
2857
2890
  const webview = BrowserView.getById(params.id);
@@ -2861,7 +2894,7 @@ export const internalRpcHandlers = {
2861
2894
  );
2862
2895
  return;
2863
2896
  }
2864
- native.symbols.webviewGoForward(webview.ptr);
2897
+ native_.symbols.webviewGoForward(webview.ptr);
2865
2898
  },
2866
2899
  webviewTagReload: (params: { id: number }) => {
2867
2900
  const webview = BrowserView.getById(params.id);
@@ -2871,7 +2904,7 @@ export const internalRpcHandlers = {
2871
2904
  );
2872
2905
  return;
2873
2906
  }
2874
- native.symbols.webviewReload(webview.ptr);
2907
+ native_.symbols.webviewReload(webview.ptr);
2875
2908
  },
2876
2909
  webviewTagRemove: (params: { id: number }) => {
2877
2910
  const webview = BrowserView.getById(params.id);
@@ -2881,15 +2914,15 @@ export const internalRpcHandlers = {
2881
2914
  );
2882
2915
  return;
2883
2916
  }
2884
- native.symbols.webviewRemove(webview.ptr);
2917
+ webview.remove();
2885
2918
  },
2886
2919
  startWindowMove: (params: { id: number }) => {
2887
2920
  const windowPtr = getWindowPtr(params.id);
2888
2921
  if (!windowPtr) return;
2889
- native.symbols.startWindowMove(windowPtr);
2922
+ native_.symbols.startWindowMove(windowPtr);
2890
2923
  },
2891
2924
  stopWindowMove: (_params: unknown) => {
2892
- native.symbols.stopWindowMove();
2925
+ native_.symbols.stopWindowMove();
2893
2926
  },
2894
2927
  webviewTagSetTransparent: (params: {
2895
2928
  id: number;
@@ -2902,7 +2935,7 @@ export const internalRpcHandlers = {
2902
2935
  );
2903
2936
  return;
2904
2937
  }
2905
- native.symbols.webviewSetTransparent(webview.ptr, params.transparent);
2938
+ native_.symbols.webviewSetTransparent(webview.ptr, params.transparent);
2906
2939
  },
2907
2940
  wgpuTagSetTransparent: (params: {
2908
2941
  id: number;
@@ -2915,7 +2948,7 @@ export const internalRpcHandlers = {
2915
2948
  );
2916
2949
  return;
2917
2950
  }
2918
- native.symbols.wgpuViewSetTransparent(view.ptr, params.transparent);
2951
+ native_.symbols.wgpuViewSetTransparent(view.ptr, params.transparent);
2919
2952
  },
2920
2953
  webviewTagSetPassthrough: (params: {
2921
2954
  id: number;
@@ -2928,7 +2961,7 @@ export const internalRpcHandlers = {
2928
2961
  );
2929
2962
  return;
2930
2963
  }
2931
- native.symbols.webviewSetPassthrough(
2964
+ native_.symbols.webviewSetPassthrough(
2932
2965
  webview.ptr,
2933
2966
  params.enablePassthrough,
2934
2967
  );
@@ -2941,7 +2974,7 @@ export const internalRpcHandlers = {
2941
2974
  );
2942
2975
  return;
2943
2976
  }
2944
- native.symbols.wgpuViewSetPassthrough(view.ptr, params.passthrough);
2977
+ native_.symbols.wgpuViewSetPassthrough(view.ptr, params.passthrough);
2945
2978
  },
2946
2979
  webviewTagSetHidden: (params: { id: number; hidden: boolean }) => {
2947
2980
  const webview = BrowserView.getById(params.id);
@@ -2951,7 +2984,7 @@ export const internalRpcHandlers = {
2951
2984
  );
2952
2985
  return;
2953
2986
  }
2954
- native.symbols.webviewSetHidden(webview.ptr, params.hidden);
2987
+ native_.symbols.webviewSetHidden(webview.ptr, params.hidden);
2955
2988
  },
2956
2989
  wgpuTagSetHidden: (params: { id: number; hidden: boolean }) => {
2957
2990
  const view = WGPUView.getById(params.id);
@@ -2961,7 +2994,7 @@ export const internalRpcHandlers = {
2961
2994
  );
2962
2995
  return;
2963
2996
  }
2964
- native.symbols.wgpuViewSetHidden(view.ptr, params.hidden);
2997
+ native_.symbols.wgpuViewSetHidden(view.ptr, params.hidden);
2965
2998
  },
2966
2999
  wgpuTagRemove: (params: { id: number }) => {
2967
3000
  const view = WGPUView.getById(params.id);
@@ -2985,7 +3018,7 @@ export const internalRpcHandlers = {
2985
3018
  console.error("wgpuTagRunTest: wgpuRunGPUTest not available");
2986
3019
  return;
2987
3020
  }
2988
- native.symbols.wgpuRunGPUTest(view.ptr);
3021
+ native_.symbols.wgpuRunGPUTest(view.ptr);
2989
3022
  },
2990
3023
  webviewTagSetNavigationRules: (params: { id: number; rules: string[] }) => {
2991
3024
  const webview = BrowserView.getById(params.id);
@@ -2996,7 +3029,7 @@ export const internalRpcHandlers = {
2996
3029
  return;
2997
3030
  }
2998
3031
  const rulesJson = JSON.stringify(params.rules);
2999
- native.symbols.setWebviewNavigationRules(
3032
+ native_.symbols.setWebviewNavigationRules(
3000
3033
  webview.ptr,
3001
3034
  toCString(rulesJson),
3002
3035
  );
@@ -3014,7 +3047,7 @@ export const internalRpcHandlers = {
3014
3047
  );
3015
3048
  return;
3016
3049
  }
3017
- native.symbols.webviewFindInPage(
3050
+ native_.symbols.webviewFindInPage(
3018
3051
  webview.ptr,
3019
3052
  toCString(params.searchText),
3020
3053
  params.forward,
@@ -3029,7 +3062,7 @@ export const internalRpcHandlers = {
3029
3062
  );
3030
3063
  return;
3031
3064
  }
3032
- native.symbols.webviewStopFind(webview.ptr);
3065
+ native_.symbols.webviewStopFind(webview.ptr);
3033
3066
  },
3034
3067
  webviewTagOpenDevTools: (params: { id: number }) => {
3035
3068
  const webview = BrowserView.getById(params.id);
@@ -3039,7 +3072,7 @@ export const internalRpcHandlers = {
3039
3072
  );
3040
3073
  return;
3041
3074
  }
3042
- native.symbols.webviewOpenDevTools(webview.ptr);
3075
+ native_.symbols.webviewOpenDevTools(webview.ptr);
3043
3076
  },
3044
3077
  webviewTagCloseDevTools: (params: { id: number }) => {
3045
3078
  const webview = BrowserView.getById(params.id);
@@ -3049,7 +3082,7 @@ export const internalRpcHandlers = {
3049
3082
  );
3050
3083
  return;
3051
3084
  }
3052
- native.symbols.webviewCloseDevTools(webview.ptr);
3085
+ native_.symbols.webviewCloseDevTools(webview.ptr);
3053
3086
  },
3054
3087
  webviewTagToggleDevTools: (params: { id: number }) => {
3055
3088
  const webview = BrowserView.getById(params.id);
@@ -3059,7 +3092,7 @@ export const internalRpcHandlers = {
3059
3092
  );
3060
3093
  return;
3061
3094
  }
3062
- native.symbols.webviewToggleDevTools(webview.ptr);
3095
+ native_.symbols.webviewToggleDevTools(webview.ptr);
3063
3096
  },
3064
3097
  webviewTagExecuteJavascript: (params: { id: number; js: string }) => {
3065
3098
  const webview = BrowserView.getById(params.id);
@@ -3069,7 +3102,7 @@ export const internalRpcHandlers = {
3069
3102
  );
3070
3103
  return;
3071
3104
  }
3072
- native.symbols.evaluateJavaScriptWithNoCompletion(
3105
+ native_.symbols.evaluateJavaScriptWithNoCompletion(
3073
3106
  webview.ptr,
3074
3107
  toCString(params.js),
3075
3108
  );