bunite-core 0.0.1 → 0.0.4

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.
Files changed (40) hide show
  1. package/package.json +3 -2
  2. package/src/bun/core/App.ts +155 -15
  3. package/src/bun/core/BrowserView.ts +124 -44
  4. package/src/bun/core/BrowserWindow.ts +94 -47
  5. package/src/bun/core/Socket.ts +2 -1
  6. package/src/bun/core/SurfaceBrowserIPC.ts +65 -0
  7. package/src/bun/core/SurfaceManager.ts +201 -0
  8. package/src/bun/core/SurfaceRegistry.ts +60 -0
  9. package/src/bun/core/Utils.ts +275 -46
  10. package/src/bun/events/appEvents.ts +2 -1
  11. package/src/bun/events/webviewEvents.ts +1 -3
  12. package/src/bun/events/windowEvents.ts +2 -0
  13. package/src/bun/index.ts +4 -3
  14. package/src/bun/preload/inline.ts +19 -25
  15. package/src/bun/proc/native.ts +158 -122
  16. package/src/native/shared/callbacks.h +6 -6
  17. package/src/native/shared/ffi_exports.h +123 -119
  18. package/src/native/shared/log.h +24 -0
  19. package/src/native/shared/webview_storage.h +5 -5
  20. package/src/native/win/native_host_appres.cpp +258 -0
  21. package/src/native/win/native_host_cef.cpp +834 -0
  22. package/src/native/win/native_host_ffi.cpp +935 -0
  23. package/src/native/win/native_host_internal.h +285 -0
  24. package/src/native/win/native_host_runtime.cpp +286 -0
  25. package/src/native/win/native_host_utils.cpp +314 -0
  26. package/src/native/win/process_helper_win.cpp +126 -26
  27. package/src/preload/runtime.built.js +1 -1
  28. package/src/preload/runtime.ts +65 -42
  29. package/src/preload/tsconfig.json +2 -1
  30. package/src/preload/tsconfig.tsbuildinfo +1 -0
  31. package/src/preload/webviewElement.ts +307 -0
  32. package/src/shared/cefVersion.ts +2 -0
  33. package/src/shared/log.ts +40 -0
  34. package/src/shared/paths.ts +122 -52
  35. package/src/shared/rpc.ts +7 -1
  36. package/src/shared/webviewPolyfill.ts +80 -0
  37. package/src/view/index.ts +8 -5
  38. package/src/native/shared/cef_response_filter.h +0 -116
  39. package/src/native/win/native_host.cpp +0 -2453
  40. package/src/types/config.ts +0 -29
@@ -0,0 +1 @@
1
+ {"fileNames":["../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es5.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2015.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2016.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2017.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2018.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2019.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2020.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2021.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2022.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.dom.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2015.core.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2017.date.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2017.object.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2017.string.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2019.array.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2019.object.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2019.string.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2020.date.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2020.string.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2020.number.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2021.string.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2022.array.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2022.error.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2022.object.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2022.string.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.decorators.d.ts","../../../node_modules/.bun/typescript@6.0.2/node_modules/typescript/lib/lib.decorators.legacy.d.ts","./webviewelement.ts","./runtime.ts"],"fileInfos":[{"version":"bcd24271a113971ba9eb71ff8cb01bc6b0f872a85c23fdbe5d93065b375933cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f88bedbeb09c6f5a6645cb24c7c55f1aa22d19ae96c8e6959cbd8b85a707bc6","impliedFormat":1},{"version":"7fe93b39b810eadd916be8db880dd7f0f7012a5cc6ffb62de8f62a2117fa6f1f","impliedFormat":1},{"version":"bb0074cc08b84a2374af33d8bf044b80851ccc9e719a5e202eacf40db2c31600","impliedFormat":1},{"version":"1a7daebe4f45fb03d9ec53d60008fbf9ac45a697fdc89e4ce218bc94b94f94d6","impliedFormat":1},{"version":"f94b133a3cb14a288803be545ac2683e0d0ff6661bcd37e31aaaec54fc382aed","impliedFormat":1},{"version":"f59d0650799f8782fd74cf73c19223730c6d1b9198671b1c5b3a38e1188b5953","impliedFormat":1},{"version":"8a15b4607d9a499e2dbeed9ec0d3c0d7372c850b2d5f1fb259e8f6d41d468a84","impliedFormat":1},{"version":"26e0fe14baee4e127f4365d1ae0b276f400562e45e19e35fd2d4c296684715e6","impliedFormat":1},{"version":"d6b1eba8496bdd0eed6fc8a685768fe01b2da4a0388b5fe7df558290bffcf32f","affectsGlobalScope":true,"impliedFormat":1},{"version":"eadcffda2aa84802c73938e589b9e58248d74c59cb7fcbca6474e3435ac15504","affectsGlobalScope":true,"impliedFormat":1},{"version":"105ba8ff7ba746404fe1a2e189d1d3d2e0eb29a08c18dded791af02f29fb4711","affectsGlobalScope":true,"impliedFormat":1},{"version":"00343ca5b2e3d48fa5df1db6e32ea2a59afab09590274a6cccb1dbae82e60c7c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebd9f816d4002697cb2864bea1f0b70a103124e18a8cd9645eeccc09bdf80ab4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2c1afac30a01772cd2a9a298a7ce7706b5892e447bb46bdbeef720f7b5da77ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b0225f483e4fa685625ebe43dd584bb7973bbd84e66a6ba7bbe175ee1048b4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0a4b8ac6ce74679c1da2b3795296f5896e31c38e888469a8e0f99dc3305de60","affectsGlobalScope":true,"impliedFormat":1},{"version":"3084a7b5f569088e0146533a00830e206565de65cae2239509168b11434cd84f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5079c53f0f141a0698faa903e76cb41cd664e3efb01cc17a5c46ec2eb0bef42","affectsGlobalScope":true,"impliedFormat":1},{"version":"32cafbc484dea6b0ab62cf8473182bbcb23020d70845b406f80b7526f38ae862","affectsGlobalScope":true,"impliedFormat":1},{"version":"fca4cdcb6d6c5ef18a869003d02c9f0fd95df8cfaf6eb431cd3376bc034cad36","affectsGlobalScope":true,"impliedFormat":1},{"version":"b93ec88115de9a9dc1b602291b85baf825c85666bf25985cc5f698073892b467","affectsGlobalScope":true,"impliedFormat":1},{"version":"f5c06dcc3fe849fcb297c247865a161f995cc29de7aa823afdd75aaaddc1419b","affectsGlobalScope":true,"impliedFormat":1},{"version":"b77e16112127a4b169ef0b8c3a4d730edf459c5f25fe52d5e436a6919206c4d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"fbffd9337146eff822c7c00acbb78b01ea7ea23987f6c961eba689349e744f8c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a995c0e49b721312f74fdfb89e4ba29bd9824c770bbb4021d74d2bf560e4c6bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"c7b3542146734342e440a84b213384bfa188835537ddbda50d30766f0593aff9","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce6180fa19b1cccd07ee7f7dbb9a367ac19c0ed160573e4686425060b6df7f57","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f02e2476bccb9dbe21280d6090f0df17d2f66b74711489415a8aa4df73c9675","affectsGlobalScope":true,"impliedFormat":1},{"version":"45e3ab34c1c013c8ab2dc1ba4c80c780744b13b5676800ae2e3be27ae862c40c","affectsGlobalScope":true,"impliedFormat":1},{"version":"805c86f6cca8d7702a62a844856dbaa2a3fd2abef0536e65d48732441dde5b5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e42e397f1a5a77994f0185fd1466520691456c772d06bf843e5084ceb879a0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"f4c2b41f90c95b1c532ecc874bd3c111865793b23aebcc1c3cbbabcd5d76ffb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab26191cfad5b66afa11b8bf935ef1cd88fabfcb28d30b2dfa6fad877d050332","affectsGlobalScope":true,"impliedFormat":1},{"version":"2088bc26531e38fb05eedac2951480db5309f6be3fa4a08d2221abb0f5b4200d","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb9d366c425fea79716a8fb3af0d78e6b22ebbab3bd64d25063b42dc9f531c1e","affectsGlobalScope":true,"impliedFormat":1},{"version":"500934a8089c26d57ebdb688fc9757389bb6207a3c8f0674d68efa900d2abb34","affectsGlobalScope":true,"impliedFormat":1},{"version":"689da16f46e647cef0d64b0def88910e818a5877ca5379ede156ca3afb780ac3","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc21cc8b6fee4f4c2440d08035b7ea3c06b3511314c8bab6bef7a92de58a2593","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ca53d13d2957003abb47922a71866ba7cb2068f8d154877c596d63c359fed25","affectsGlobalScope":true,"impliedFormat":1},{"version":"54725f8c4df3d900cb4dac84b64689ce29548da0b4e9b7c2de61d41c79293611","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5594bc3076ac29e6c1ebda77939bc4c8833de72f654b6e376862c0473199323","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f3eb332c2d73e729f3364fcc0c2b375e72a121e8157d25a82d67a138c83a95c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f4427f9642ce8d500970e4e69d1397f64072ab73b97e476b4002a646ac743b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"48915f327cd1dea4d7bd358d9dc7732f58f9e1626a29cc0c05c8c692419d9bb7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7bf9377723203b5a6a4b920164df22d56a43f593269ba6ae1fdc97774b68855","affectsGlobalScope":true,"impliedFormat":1},{"version":"db9709688f82c9e5f65a119c64d835f906efe5f559d08b11642d56eb85b79357","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b25b8c874acd1a4cf8444c3617e037d444d19080ac9f634b405583fd10ce1f7","affectsGlobalScope":true,"impliedFormat":1},{"version":"37be57d7c90cf1f8112ee2636a068d8fd181289f82b744160ec56a7dc158a9f5","affectsGlobalScope":true,"impliedFormat":1},{"version":"a917a49ac94cd26b754ab84e113369a75d1a47a710661d7cd25e961cc797065f","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d3261badeb7843d157ef3e6f5d1427d0eeb0af0cf9df84a62cfd29fd47ac86e","affectsGlobalScope":true,"impliedFormat":1},{"version":"195daca651dde22f2167ac0d0a05e215308119a3100f5e6268e8317d05a92526","affectsGlobalScope":true,"impliedFormat":1},{"version":"8b11e4285cd2bb164a4dc09248bdec69e9842517db4ca47c1ba913011e44ff2f","affectsGlobalScope":true,"impliedFormat":1},{"version":"0508571a52475e245b02bc50fa1394065a0a3d05277fbf5120c3784b85651799","affectsGlobalScope":true,"impliedFormat":1},{"version":"8f9af488f510c3015af3cc8c267a9e9d96c4dd38a1fdff0e11dc5a544711415b","affectsGlobalScope":true,"impliedFormat":1},{"version":"fc611fea8d30ea72c6bbfb599c9b4d393ce22e2f5bfef2172534781e7d138104","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ce14b81c5cc821994aa8ec1d42b220dd41b27fcc06373bce3958af7421b77d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3a048b3e9302ef9a34ef4ebb9aecfb28b66abb3bce577206a79fee559c230da","affectsGlobalScope":true,"impliedFormat":1},{"version":"f7924c67469cd6b44b50480cec49f3d34b3feae7bb292d6f44b7939f9d07a2dc","signature":"5c08c27ab7fdb9d3a443d5b81d066acf9a3b44413dbfe91153a2288779910ad5","affectsGlobalScope":true},{"version":"b61a26197044cf31caa83db322ecb653d081fc67e14b25c5a41cd7cc33b3fca1","signature":"6447fe52d8ee29270b95a53b62dece95739c334d51b6271bd7e1323e81b79a2c"}],"root":[59,60],"options":{"composite":true,"exactOptionalPropertyTypes":false,"module":7,"skipLibCheck":true,"strict":true,"target":9},"affectedFilesPendingEmit":[[60,17],[59,17]],"emitSignatures":[59,60],"version":"6.0.2"}
@@ -0,0 +1,307 @@
1
+ // <bunite-webview> custom element — registered in every appres:// page via preload.
2
+
3
+ declare const bunite: {
4
+ invoke: (method: string, params?: unknown) => Promise<any>;
5
+ on: (channel: string, handler: (data: any) => void) => (() => void);
6
+ off: (channel: string, handler: (data: any) => void) => void;
7
+ };
8
+
9
+ // --- OverlaySyncController ---
10
+ // Tracks element bounds and notifies when they change.
11
+ // Uses ResizeObserver for size changes and rAF polling for position changes.
12
+ // Dirty-flag coalescing ensures at most one IPC per animation frame.
13
+
14
+ type Rect = { x: number; y: number; width: number; height: number };
15
+
16
+ class OverlaySyncController {
17
+ private element: HTMLElement;
18
+ private onBoundsChange: (rect: Rect) => void;
19
+ private observer: ResizeObserver | null = null;
20
+ private rafId = 0;
21
+ private lastRect: Rect = { x: 0, y: 0, width: 0, height: 0 };
22
+ private dirty = false;
23
+ private stopped = false;
24
+
25
+ constructor(element: HTMLElement, onBoundsChange: (rect: Rect) => void) {
26
+ this.element = element;
27
+ this.onBoundsChange = onBoundsChange;
28
+ }
29
+
30
+ start() {
31
+ this.observer = new ResizeObserver(() => this.markDirty());
32
+ this.observer.observe(this.element);
33
+ this.scheduleFrame();
34
+ }
35
+
36
+ stop() {
37
+ this.stopped = true;
38
+ this.observer?.disconnect();
39
+ this.observer = null;
40
+ if (this.rafId) {
41
+ cancelAnimationFrame(this.rafId);
42
+ this.rafId = 0;
43
+ }
44
+ }
45
+
46
+ private markDirty() {
47
+ this.dirty = true;
48
+ }
49
+
50
+ private scheduleFrame() {
51
+ if (this.stopped) return;
52
+ this.rafId = requestAnimationFrame(() => {
53
+ this.flush();
54
+ this.scheduleFrame();
55
+ });
56
+ }
57
+
58
+ private flush() {
59
+ const dpr = window.devicePixelRatio || 1;
60
+ const r = this.element.getBoundingClientRect();
61
+ const rect: Rect = {
62
+ x: Math.round(r.x * dpr),
63
+ y: Math.round(r.y * dpr),
64
+ width: Math.round(r.width * dpr),
65
+ height: Math.round(r.height * dpr)
66
+ };
67
+
68
+ // Always check for position changes (not caught by ResizeObserver)
69
+ if (
70
+ !this.dirty &&
71
+ rect.x === this.lastRect.x &&
72
+ rect.y === this.lastRect.y &&
73
+ rect.width === this.lastRect.width &&
74
+ rect.height === this.lastRect.height
75
+ ) {
76
+ return;
77
+ }
78
+
79
+ this.dirty = false;
80
+ this.lastRect = rect;
81
+ this.onBoundsChange(rect);
82
+ }
83
+ }
84
+
85
+ // --- BuniteWebviewElement ---
86
+
87
+ type SurfaceInitResponse = { surfaceId: number };
88
+
89
+ class BuniteWebviewElement extends HTMLElement {
90
+ static observedAttributes = ["src"];
91
+
92
+ _surfaceId: number | null = null;
93
+ private _syncCtrl: OverlaySyncController | null = null;
94
+ private _initPromise: Promise<SurfaceInitResponse> | null = null;
95
+ private _aborted = false;
96
+ private _pendingSrc: string | null = null;
97
+ private _syncHidden = false;
98
+ private _userHidden = false;
99
+ private _layoutObserver: ResizeObserver | null = null;
100
+ private _unsubNavigate: (() => void) | null = null;
101
+
102
+ constructor() {
103
+ super();
104
+ // NOTE: Custom element spec forbids setting attributes in constructor.
105
+ }
106
+
107
+ connectedCallback() {
108
+ this._aborted = false;
109
+ this._syncHidden = false;
110
+ this._userHidden = false;
111
+ this._unsubNavigate = bunite.on("__bunite:webview.didNavigate", (data: any) => {
112
+ if (data?.surfaceId === this._surfaceId) {
113
+ this.dispatchEvent(new CustomEvent("did-navigate", { detail: { url: data.url } }));
114
+ }
115
+ });
116
+ this._waitForLayout();
117
+ }
118
+
119
+ private _waitForLayout() {
120
+ if (this._layoutObserver) return; // already waiting
121
+
122
+ const tryInit = () => {
123
+ if (!this.isConnected || this._aborted) return true; // stop waiting
124
+ const r = this.getBoundingClientRect();
125
+ if (r.width > 0 && r.height > 0) {
126
+ const src = this.getAttribute("src") || this._pendingSrc || "";
127
+ if (src) this.initSurface();
128
+ return true;
129
+ }
130
+ return false;
131
+ };
132
+
133
+ requestAnimationFrame(() => {
134
+ if (tryInit()) return;
135
+ // Element has no layout yet — wait via ResizeObserver
136
+ this._layoutObserver = new ResizeObserver(() => {
137
+ if (tryInit()) {
138
+ this._layoutObserver?.disconnect();
139
+ this._layoutObserver = null;
140
+ }
141
+ });
142
+ this._layoutObserver.observe(this);
143
+ });
144
+ }
145
+
146
+ disconnectedCallback() {
147
+ this._aborted = true;
148
+ this._unsubNavigate?.();
149
+ this._unsubNavigate = null;
150
+ this._layoutObserver?.disconnect();
151
+ this._layoutObserver = null;
152
+ this._syncCtrl?.stop();
153
+ this._syncCtrl = null;
154
+
155
+ if (this._surfaceId != null) {
156
+ const id = this._surfaceId;
157
+ this._surfaceId = null;
158
+ bunite.invoke("__bunite:surface.remove", { surfaceId: id }).catch(() => {});
159
+ } else if (this._initPromise) {
160
+ this._initPromise
161
+ .then((r) => {
162
+ bunite.invoke("__bunite:surface.remove", { surfaceId: r.surfaceId }).catch(() => {});
163
+ })
164
+ .catch(() => {});
165
+ }
166
+ this._initPromise = null;
167
+ }
168
+
169
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
170
+ if (name !== "src") return;
171
+ if (this._surfaceId != null) {
172
+ bunite.invoke("__bunite:webview.navigate", {
173
+ surfaceId: this._surfaceId,
174
+ url: newValue || ""
175
+ }).catch(() => {});
176
+ } else if (this._initPromise) {
177
+ // Init in progress — queue for after completion
178
+ this._pendingSrc = newValue || "";
179
+ } else if (this.isConnected && !this._aborted && newValue) {
180
+ // No init started yet (was waiting for src) — start now
181
+ this._waitForLayout();
182
+ }
183
+ }
184
+
185
+ setHidden(hidden: boolean) {
186
+ this._userHidden = hidden;
187
+ this._applySurfaceHidden();
188
+ }
189
+
190
+ goBack() {
191
+ if (this._surfaceId != null)
192
+ bunite.invoke("__bunite:webview.goBack", { surfaceId: this._surfaceId }).catch(() => {});
193
+ }
194
+
195
+ reload() {
196
+ if (this._surfaceId != null)
197
+ bunite.invoke("__bunite:webview.reload", { surfaceId: this._surfaceId }).catch(() => {});
198
+ }
199
+
200
+ navigate(url: string) {
201
+ this.setAttribute("src", url);
202
+ }
203
+
204
+ private _applySurfaceHidden() {
205
+ if (this._surfaceId == null) return;
206
+ bunite.invoke("__bunite:surface.setHidden", {
207
+ surfaceId: this._surfaceId,
208
+ hidden: this._userHidden || this._syncHidden
209
+ }).catch(() => {});
210
+ }
211
+
212
+ private initSurface() {
213
+ if (this._surfaceId != null || this._initPromise != null) return;
214
+
215
+ const dpr = window.devicePixelRatio || 1;
216
+ const r = this.getBoundingClientRect();
217
+ const src = this._pendingSrc || this.getAttribute("src") || "";
218
+ this._pendingSrc = null;
219
+
220
+ const initPromise = bunite.invoke("__bunite:surface.init", {
221
+ src,
222
+ x: Math.round(r.x * dpr),
223
+ y: Math.round(r.y * dpr),
224
+ width: Math.round(r.width * dpr),
225
+ height: Math.round(r.height * dpr),
226
+ hidden: this._userHidden
227
+ }) as Promise<SurfaceInitResponse>;
228
+ this._initPromise = initPromise;
229
+
230
+ initPromise
231
+ .then((response) => {
232
+ if (this._initPromise !== initPromise) return;
233
+ if (this._aborted) {
234
+ bunite.invoke("__bunite:surface.remove", { surfaceId: response.surfaceId }).catch(() => {});
235
+ return;
236
+ }
237
+
238
+ this._surfaceId = response.surfaceId;
239
+
240
+ // Apply hidden state that was set during init
241
+ if (this._userHidden) {
242
+ this._applySurfaceHidden();
243
+ }
244
+
245
+ // Apply src that was set before init completed
246
+ if (this._pendingSrc != null) {
247
+ const pending = this._pendingSrc;
248
+ this._pendingSrc = null;
249
+ bunite.invoke("__bunite:webview.navigate", {
250
+ surfaceId: this._surfaceId,
251
+ url: pending
252
+ }).catch(() => {});
253
+ }
254
+
255
+ this._syncCtrl = new OverlaySyncController(this, (rect) => {
256
+ if (this._surfaceId == null) return;
257
+
258
+ const isZero = rect.width === 0 && rect.height === 0;
259
+ if (isZero) {
260
+ if (!this._syncHidden) {
261
+ this._syncHidden = true;
262
+ this._applySurfaceHidden();
263
+ }
264
+ return;
265
+ }
266
+ if (this._syncHidden) {
267
+ this._syncHidden = false;
268
+ this._applySurfaceHidden();
269
+ }
270
+
271
+ bunite.invoke("__bunite:surface.resize", {
272
+ surfaceId: this._surfaceId,
273
+ x: rect.x,
274
+ y: rect.y,
275
+ w: rect.width,
276
+ h: rect.height
277
+ }).catch(() => {});
278
+ });
279
+ this._syncCtrl.start();
280
+ })
281
+ .catch(() => {})
282
+ .finally(() => {
283
+ if (this._initPromise === initPromise) {
284
+ this._initPromise = null;
285
+ }
286
+ });
287
+ }
288
+ }
289
+
290
+ if (typeof customElements !== "undefined") {
291
+ customElements.define("bunite-webview", BuniteWebviewElement);
292
+
293
+ // When the host page gains focus (click on non-surface area), the host BrowserView
294
+ // HWND comes to front and covers surface child HWNDs. Re-raise surfaces on focus.
295
+ const raiseAll = () => bunite.invoke("__bunite:surface.bringAllVisiblesToFront").catch(() => {});
296
+ document.addEventListener("pointerdown", raiseAll, true);
297
+
298
+ // During host-page drag (e.g. dockview tab drag), send surfaces behind host
299
+ // via Z-order swap so OLE DragDrop reaches the host's IDropTarget.
300
+ document.addEventListener("dragstart", () => {
301
+ bunite.invoke("__bunite:surface.setAllPassthrough", { passthrough: true }).catch(() => {});
302
+ }, true);
303
+ document.addEventListener("dragend", () => {
304
+ bunite.invoke("__bunite:surface.setAllPassthrough", { passthrough: false }).catch(() => {});
305
+ raiseAll();
306
+ }, true);
307
+ }
@@ -0,0 +1,2 @@
1
+ // Auto-generated by scripts/gen-cef-version.ts
2
+ export const CEF_VERSION = "146.0.10";
@@ -0,0 +1,40 @@
1
+ export type LogLevel = "debug" | "info" | "warn" | "error" | "silent";
2
+
3
+ const levels: Record<LogLevel, number> = {
4
+ debug: 0,
5
+ info: 1,
6
+ warn: 2,
7
+ error: 3,
8
+ silent: 4
9
+ };
10
+
11
+ let currentLevel: LogLevel = "warn";
12
+
13
+ function shouldLog(level: LogLevel): boolean {
14
+ return levels[level] >= levels[currentLevel];
15
+ }
16
+
17
+ export function logLevelToInt(level: LogLevel): number {
18
+ return levels[level];
19
+ }
20
+
21
+ export const log = {
22
+ setLevel(level: LogLevel) {
23
+ currentLevel = level;
24
+ },
25
+ getLevel(): LogLevel {
26
+ return currentLevel;
27
+ },
28
+ debug(...args: unknown[]) {
29
+ if (shouldLog("debug")) console.debug("[bunite]", ...args);
30
+ },
31
+ info(...args: unknown[]) {
32
+ if (shouldLog("info")) console.info("[bunite]", ...args);
33
+ },
34
+ warn(...args: unknown[]) {
35
+ if (shouldLog("warn")) console.warn("[bunite]", ...args);
36
+ },
37
+ error(...args: unknown[]) {
38
+ if (shouldLog("error")) console.error("[bunite]", ...args);
39
+ }
40
+ };
@@ -1,7 +1,8 @@
1
1
  import { dirname, join } from "node:path";
2
- import { existsSync } from "node:fs";
2
+ import { existsSync, readdirSync } from "node:fs";
3
3
  import { createRequire } from "node:module";
4
4
  import { ARCH, BIN_EXT, NATIVE_LIB_EXT, PLATFORM_TAG } from "./platform";
5
+ import { CEF_VERSION } from "./cefVersion";
5
6
 
6
7
  const require = createRequire(import.meta.url);
7
8
 
@@ -24,38 +25,108 @@ export function resolvePackageRoot(packageName: string): string | null {
24
25
  }
25
26
  }
26
27
 
27
- export function resolveBunitePackageRoot(): string {
28
- const packageJsonPath = require.resolve("bunite/package.json");
29
- return dirname(packageJsonPath);
28
+ export function resolveBunitePackageRoot(): string | null {
29
+ try {
30
+ const packageJsonPath = require.resolve("bunite-core/package.json");
31
+ return dirname(packageJsonPath);
32
+ } catch {
33
+ return null;
34
+ }
30
35
  }
31
36
 
32
- export function resolveFallbackCefDir(): string | null {
33
- const envOverride = process.env.BUNITE_CEF_DIR ?? process.env.BUNITE_CEF_ROOT;
34
- if (envOverride && existsSync(envOverride)) {
35
- return envOverride;
37
+ function hasCefRuntime(dir: string): boolean {
38
+ return existsSync(join(dir, "libcef.dll")) || existsSync(join(dir, "libcef.so"));
39
+ }
40
+
41
+ function parseCefVersion(name: string): number[] | null {
42
+ const m = name.match(/^cef-(\d+)\.(\d+)\.(\d+)$/);
43
+ return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
44
+ }
45
+
46
+ function resolveCefDir(searchDirs: string[]): string | null {
47
+ // 0. Explicit override (testing / development)
48
+ const forceDir = process.env.BUNITE_CEF_DIR;
49
+ if (forceDir && hasCefRuntime(forceDir)) {
50
+ return forceDir;
36
51
  }
37
52
 
38
- const bunitePackageRoot = resolveBunitePackageRoot();
39
- const localVendorPath = join(bunitePackageRoot, "vendors", "cef");
40
- if (existsSync(localVendorPath)) {
41
- return localVendorPath;
53
+ // 1. Local cef/ adjacent to native artifacts (standalone dist)
54
+ for (const dir of searchDirs) {
55
+ const candidate = join(dir, "cef");
56
+ if (hasCefRuntime(candidate)) {
57
+ return candidate;
58
+ }
42
59
  }
43
60
 
44
- const upstreamVendorPath = "C:\\project\\electrobun\\package\\vendors\\cef";
45
- if (existsSync(upstreamVendorPath)) {
46
- return upstreamVendorPath;
61
+ // 2. Shared CEF root: BUNITE_CEF_ROOTDIR/cef-<version>/
62
+ const rootDir = process.env.BUNITE_CEF_ROOTDIR;
63
+ if (rootDir && existsSync(rootDir)) {
64
+ const exact = join(rootDir, `cef-${CEF_VERSION}`);
65
+ if (hasCefRuntime(exact)) {
66
+ return exact;
67
+ }
68
+ // Same major fallback — numeric version comparison
69
+ const [targetMajor] = CEF_VERSION.split(".").map(Number);
70
+ try {
71
+ let best: { dir: string; ver: number[] } | null = null;
72
+ for (const name of readdirSync(rootDir)) {
73
+ const ver = parseCefVersion(name);
74
+ if (!ver || ver[0] !== targetMajor) continue;
75
+ const full = join(rootDir, name);
76
+ if (!hasCefRuntime(full)) continue;
77
+ if (!best || ver[1] > best.ver[1] || (ver[1] === best.ver[1] && ver[2] > best.ver[2])) {
78
+ best = { dir: full, ver };
79
+ }
80
+ }
81
+ if (best) return best.dir;
82
+ } catch {}
83
+ }
84
+
85
+ // 3. vendors/cef inside bunite-core package
86
+ const packageRoot = resolveBunitePackageRoot();
87
+ if (packageRoot) {
88
+ const vendorPath = join(packageRoot, "vendors", "cef");
89
+ if (hasCefRuntime(vendorPath)) {
90
+ return vendorPath;
91
+ }
47
92
  }
48
93
 
49
94
  return null;
50
95
  }
51
96
 
52
- export function resolveDefaultViewsRoot(): string | null {
53
- const candidate = join(process.cwd(), "views");
97
+ /** Entry script dir (dev) or exe dir (compiled binary). */
98
+ export function getBaseDir(): string {
99
+ const main = Bun.main;
100
+ if (main && existsSync(main)) return dirname(main);
101
+ return dirname(process.execPath);
102
+ }
103
+
104
+ export function resolveDefaultAppResRoot(): string | null {
105
+ const candidate = join(process.cwd(), "appres");
54
106
  return existsSync(candidate) ? candidate : null;
55
107
  }
56
108
 
57
109
  export function resolveNativeArtifacts(): ResolvedNativeArtifacts {
110
+ const exeDir = dirname(process.execPath);
111
+
112
+ // 1. Executable-relative (compiled standalone binary)
113
+ const exeNativeLib = join(exeDir, `libBuniteNative${NATIVE_LIB_EXT}`);
114
+ const exeProcessHelper = join(exeDir, `process_helper${BIN_EXT}`);
115
+ if (existsSync(exeNativeLib) && existsSync(exeProcessHelper)) {
116
+ return {
117
+ packageRoot: exeDir,
118
+ source: "local-build",
119
+ nativePackageName: null,
120
+ cefPackageName: null,
121
+ nativeLibPath: exeNativeLib,
122
+ processHelperPath: exeProcessHelper,
123
+ cefDir: resolveCefDir([exeDir])
124
+ };
125
+ }
126
+
58
127
  const packageRoot = resolveBunitePackageRoot();
128
+
129
+ // 2. Optional npm packages (@bunite/native-*, @bunite/cef-*)
59
130
  const nativePackageName = `@bunite/native-${PLATFORM_TAG}-${ARCH}`;
60
131
  const cefPackageName = `@bunite/cef-${PLATFORM_TAG}-${ARCH}`;
61
132
  const nativePackageRoot = resolvePackageRoot(nativePackageName);
@@ -76,7 +147,7 @@ export function resolveNativeArtifacts(): ResolvedNativeArtifacts {
76
147
  existsSync(packagedProcessHelperPath)
77
148
  ) {
78
149
  return {
79
- packageRoot,
150
+ packageRoot: packageRoot ?? exeDir,
80
151
  source: "optional-package",
81
152
  nativePackageName,
82
153
  cefPackageName: packagedCefDir && existsSync(packagedCefDir) ? cefPackageName : null,
@@ -86,43 +157,42 @@ export function resolveNativeArtifacts(): ResolvedNativeArtifacts {
86
157
  };
87
158
  }
88
159
 
89
- const localBuildRoot = join(packageRoot, "native-build", `${PLATFORM_TAG}-${ARCH}`);
90
- const localCefDir = join(localBuildRoot, "cef");
91
- const directLocalNativeLibPath = join(localBuildRoot, `libBuniteNative${NATIVE_LIB_EXT}`);
92
- const directLocalProcessHelperPath = join(localBuildRoot, `process_helper${BIN_EXT}`);
93
-
94
- if (existsSync(directLocalNativeLibPath) && existsSync(directLocalProcessHelperPath)) {
95
- const resolvedLocalCefDir = existsSync(localCefDir) ? localCefDir : resolveFallbackCefDir();
96
- return {
97
- packageRoot,
98
- source: "local-build",
99
- nativePackageName: null,
100
- cefPackageName: null,
101
- nativeLibPath: directLocalNativeLibPath,
102
- processHelperPath: directLocalProcessHelperPath,
103
- cefDir: resolvedLocalCefDir
104
- };
105
- }
106
-
107
- const localBuildBinRoot = join(localBuildRoot, "Release");
108
- const localNativeLibPath = join(localBuildBinRoot, `libBuniteNative${NATIVE_LIB_EXT}`);
109
- const localProcessHelperPath = join(localBuildBinRoot, `process_helper${BIN_EXT}`);
110
-
111
- if (existsSync(localNativeLibPath) && existsSync(localProcessHelperPath)) {
112
- const resolvedLocalCefDir = existsSync(localCefDir) ? localCefDir : resolveFallbackCefDir();
113
- return {
114
- packageRoot,
115
- source: "local-build",
116
- nativePackageName: null,
117
- cefPackageName: null,
118
- nativeLibPath: localNativeLibPath,
119
- processHelperPath: localProcessHelperPath,
120
- cefDir: resolvedLocalCefDir
121
- };
160
+ // 3. Local build (development)
161
+ if (packageRoot) {
162
+ const localBuildRoot = join(packageRoot, "native-build", `${PLATFORM_TAG}-${ARCH}`);
163
+ const directLib = join(localBuildRoot, `libBuniteNative${NATIVE_LIB_EXT}`);
164
+ const directHelper = join(localBuildRoot, `process_helper${BIN_EXT}`);
165
+
166
+ if (existsSync(directLib) && existsSync(directHelper)) {
167
+ return {
168
+ packageRoot,
169
+ source: "local-build",
170
+ nativePackageName: null,
171
+ cefPackageName: null,
172
+ nativeLibPath: directLib,
173
+ processHelperPath: directHelper,
174
+ cefDir: resolveCefDir([localBuildRoot])
175
+ };
176
+ }
177
+
178
+ const releaseLib = join(localBuildRoot, "Release", `libBuniteNative${NATIVE_LIB_EXT}`);
179
+ const releaseHelper = join(localBuildRoot, "Release", `process_helper${BIN_EXT}`);
180
+
181
+ if (existsSync(releaseLib) && existsSync(releaseHelper)) {
182
+ return {
183
+ packageRoot,
184
+ source: "local-build",
185
+ nativePackageName: null,
186
+ cefPackageName: null,
187
+ nativeLibPath: releaseLib,
188
+ processHelperPath: releaseHelper,
189
+ cefDir: resolveCefDir([localBuildRoot])
190
+ };
191
+ }
122
192
  }
123
193
 
124
194
  return {
125
- packageRoot,
195
+ packageRoot: packageRoot ?? exeDir,
126
196
  source: "missing",
127
197
  nativePackageName: nativePackageRoot ? nativePackageName : null,
128
198
  cefPackageName: cefPackageRoot ? cefPackageName : null,
package/src/shared/rpc.ts CHANGED
@@ -16,7 +16,13 @@ export type RPCMessagePacket = {
16
16
  payload: unknown;
17
17
  };
18
18
 
19
- export type RPCPacket = RPCRequestPacket | RPCResponsePacket | RPCMessagePacket;
19
+ export type RPCEventPacket = {
20
+ type: "event";
21
+ channel: string;
22
+ data: unknown;
23
+ };
24
+
25
+ export type RPCPacket = RPCRequestPacket | RPCResponsePacket | RPCMessagePacket | RPCEventPacket;
20
26
 
21
27
  type BaseRPCRequestsSchema = Record<string, { params: unknown; response: unknown }>;
22
28
  type BaseRPCMessagesSchema = Record<string, unknown>;