bunite-core 0.4.0 → 0.6.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.
- package/package.json +1 -2
- package/src/shared/rpc.ts +4 -13
- package/src/shared/webRpcHandler.ts +1 -3
- package/src/shared/webviewPolyfill.ts +21 -5
- package/src/view/index.ts +26 -15
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bunite-core",
|
|
3
3
|
"description": "Uniting UI and Bun",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"setup:cef": "bun ../tools/bunite-dev/scripts/setup-cef.ts",
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
".": "./src/bun/index.ts",
|
|
13
13
|
"./bun": "./src/bun/index.ts",
|
|
14
14
|
"./view": "./src/view/index.ts",
|
|
15
|
-
"./webview-polyfill": "./src/shared/webviewPolyfill.ts",
|
|
16
15
|
"./shared/rpc": "./src/shared/rpc.ts",
|
|
17
16
|
"./package.json": "./package.json"
|
|
18
17
|
},
|
package/src/shared/rpc.ts
CHANGED
|
@@ -374,9 +374,7 @@ function defineSideRpc<
|
|
|
374
374
|
Schema extends BuniteRpcSchema,
|
|
375
375
|
Side extends "bun" | "webview"
|
|
376
376
|
>(
|
|
377
|
-
config: BuniteRpcConfig<Schema, Side>
|
|
378
|
-
extraRequestHandlers?: Record<string, (...args: any[]) => unknown>;
|
|
379
|
-
}
|
|
377
|
+
config: BuniteRpcConfig<Schema, Side>
|
|
380
378
|
) {
|
|
381
379
|
type RemoteSide = Side extends "bun" ? "webview" : "bun";
|
|
382
380
|
type LocalSchema = {
|
|
@@ -390,10 +388,7 @@ function defineSideRpc<
|
|
|
390
388
|
|
|
391
389
|
const rpc = createRpc<LocalSchema, RemoteSchema>({
|
|
392
390
|
maxRequestTime: config.maxRequestTime,
|
|
393
|
-
requestHandler:
|
|
394
|
-
...(config.handlers.requests ?? {}),
|
|
395
|
-
...(config.extraRequestHandlers ?? {})
|
|
396
|
-
} as RpcRequestHandler<LocalSchema["requests"]>,
|
|
391
|
+
requestHandler: config.handlers.requests,
|
|
397
392
|
transport: {
|
|
398
393
|
registerHandler: () => {}
|
|
399
394
|
}
|
|
@@ -417,17 +412,13 @@ function defineSideRpc<
|
|
|
417
412
|
}
|
|
418
413
|
|
|
419
414
|
export function defineBunRpc<Schema extends BuniteRpcSchema>(
|
|
420
|
-
config: BuniteRpcConfig<Schema, "bun">
|
|
421
|
-
extraRequestHandlers?: Record<string, (...args: any[]) => unknown>;
|
|
422
|
-
}
|
|
415
|
+
config: BuniteRpcConfig<Schema, "bun">
|
|
423
416
|
) {
|
|
424
417
|
return defineSideRpc<Schema, "bun">(config);
|
|
425
418
|
}
|
|
426
419
|
|
|
427
420
|
export function defineWebviewRpc<Schema extends BuniteRpcSchema>(
|
|
428
|
-
config: BuniteRpcConfig<Schema, "webview">
|
|
429
|
-
extraRequestHandlers?: Record<string, (...args: any[]) => unknown>;
|
|
430
|
-
}
|
|
421
|
+
config: BuniteRpcConfig<Schema, "webview">
|
|
431
422
|
) {
|
|
432
423
|
return defineSideRpc<Schema, "webview">(config);
|
|
433
424
|
}
|
|
@@ -12,9 +12,7 @@ export type WebRpcClient<Schema extends BuniteRpcSchema = BuniteRpcSchema> = {
|
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export function createWebRpcHandler<Schema extends BuniteRpcSchema>(
|
|
15
|
-
config: BuniteRpcConfig<Schema, "bun">
|
|
16
|
-
extraRequestHandlers?: Record<string, (...args: any[]) => unknown>;
|
|
17
|
-
}
|
|
15
|
+
config: BuniteRpcConfig<Schema, "bun">
|
|
18
16
|
) {
|
|
19
17
|
type Entry = { client: WebRpcClient<Schema>; receive: (raw: ArrayBuffer | Uint8Array) => void };
|
|
20
18
|
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
// Iframe-based fallback for web browsers. No-op when the native element is already registered by the CEF preload.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
// HTMLElement reference is lazy so this module is import-safe in Node/Bun.
|
|
3
|
+
|
|
4
|
+
let cachedClass: CustomElementConstructor | null = null;
|
|
5
|
+
|
|
6
|
+
function definePolyfillClass(): CustomElementConstructor {
|
|
7
|
+
if (cachedClass) return cachedClass;
|
|
8
|
+
|
|
6
9
|
class BuniteWebviewPolyfill extends HTMLElement {
|
|
7
10
|
static observedAttributes = ["src"];
|
|
8
11
|
|
|
@@ -69,5 +72,18 @@ if (
|
|
|
69
72
|
}
|
|
70
73
|
}
|
|
71
74
|
|
|
72
|
-
|
|
75
|
+
cachedClass = BuniteWebviewPolyfill;
|
|
76
|
+
return cachedClass;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Register the `<bunite-webview>` iframe polyfill. No-op in non-browser
|
|
81
|
+
* environments and when the native CEF preload has already registered the element.
|
|
82
|
+
* `BuniteView` calls this automatically on construction; call directly only when
|
|
83
|
+
* using `<bunite-webview>` markup without instantiating `BuniteView`.
|
|
84
|
+
*/
|
|
85
|
+
export function registerBuniteWebviewPolyfill() {
|
|
86
|
+
if (typeof customElements === "undefined") return;
|
|
87
|
+
if (customElements.get("bunite-webview")) return;
|
|
88
|
+
customElements.define("bunite-webview", definePolyfillClass());
|
|
73
89
|
}
|
package/src/view/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "../shared/webviewPolyfill";
|
|
1
|
+
import { registerBuniteWebviewPolyfill } from "../shared/webviewPolyfill";
|
|
2
2
|
import {
|
|
3
3
|
defineWebviewRpc,
|
|
4
4
|
type BuniteRpcConfig,
|
|
@@ -24,11 +24,19 @@ type BuniteWindowGlobals = Window &
|
|
|
24
24
|
__bunite_decrypt?: (data: Uint8Array) => Promise<Uint8Array>;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
type BuniteEnv = {
|
|
28
|
+
window: BuniteWindowGlobals | null;
|
|
29
|
+
webviewId: number | undefined;
|
|
30
|
+
rpcPort: number | undefined;
|
|
31
|
+
isNative: boolean;
|
|
32
|
+
};
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
function readBuniteEnv(): BuniteEnv {
|
|
35
|
+
const w = typeof window !== "undefined" ? (window as BuniteWindowGlobals) : null;
|
|
36
|
+
const webviewId = w?.__buniteWebviewId;
|
|
37
|
+
const rpcPort = w?.__buniteRpcSocketPort;
|
|
38
|
+
return { window: w, webviewId, rpcPort, isNative: webviewId != null && rpcPort != null };
|
|
39
|
+
}
|
|
32
40
|
|
|
33
41
|
function toArrayBuffer(bytes: Uint8Array): ArrayBuffer {
|
|
34
42
|
const copy = new Uint8Array(bytes.byteLength);
|
|
@@ -41,10 +49,13 @@ export class BuniteView<T extends RpcWithTransport = RpcWithTransport> {
|
|
|
41
49
|
rpc?: T;
|
|
42
50
|
readonly transport: RpcTransport;
|
|
43
51
|
|
|
52
|
+
private env: BuniteEnv;
|
|
44
53
|
private handler?: (packet: RpcPacket) => void;
|
|
45
54
|
private pendingPackets: RpcPacket[] = [];
|
|
46
55
|
|
|
47
56
|
constructor(config?: { rpc?: T }) {
|
|
57
|
+
registerBuniteWebviewPolyfill();
|
|
58
|
+
this.env = readBuniteEnv();
|
|
48
59
|
this.rpc = config?.rpc;
|
|
49
60
|
|
|
50
61
|
this.transport = {
|
|
@@ -60,9 +71,9 @@ export class BuniteView<T extends RpcWithTransport = RpcWithTransport> {
|
|
|
60
71
|
};
|
|
61
72
|
|
|
62
73
|
this.initSocketToBun();
|
|
63
|
-
if (isNative) {
|
|
64
|
-
|
|
65
|
-
|
|
74
|
+
if (this.env.isNative && this.env.window) {
|
|
75
|
+
this.env.window.__bunite ??= {};
|
|
76
|
+
this.env.window.__bunite.receiveMessageFromBun = (message) => {
|
|
66
77
|
this.handler?.(message as RpcPacket);
|
|
67
78
|
};
|
|
68
79
|
}
|
|
@@ -70,7 +81,7 @@ export class BuniteView<T extends RpcWithTransport = RpcWithTransport> {
|
|
|
70
81
|
}
|
|
71
82
|
|
|
72
83
|
private sendPacket(packet: RpcPacket) {
|
|
73
|
-
if (isNative) {
|
|
84
|
+
if (this.env.isNative) {
|
|
74
85
|
void this.bunBridge(packet).catch((error) => {
|
|
75
86
|
log.error("Failed to send RPC packet", error);
|
|
76
87
|
});
|
|
@@ -80,7 +91,7 @@ export class BuniteView<T extends RpcWithTransport = RpcWithTransport> {
|
|
|
80
91
|
}
|
|
81
92
|
|
|
82
93
|
initSocketToBun() {
|
|
83
|
-
if (!isNative) {
|
|
94
|
+
if (!this.env.isNative) {
|
|
84
95
|
const proto = location.protocol === "https:" ? "wss:" : "ws:";
|
|
85
96
|
const socket = new WebSocket(`${proto}//${location.host}/rpc`);
|
|
86
97
|
socket.binaryType = "arraybuffer";
|
|
@@ -97,14 +108,14 @@ export class BuniteView<T extends RpcWithTransport = RpcWithTransport> {
|
|
|
97
108
|
});
|
|
98
109
|
} else {
|
|
99
110
|
// Share a single WebSocket with the preload's bunite.invoke.
|
|
100
|
-
const globals =
|
|
111
|
+
const globals = this.env.window as any;
|
|
101
112
|
globals.__bunite ??= {};
|
|
102
113
|
const existing = globals.__bunite._socket;
|
|
103
114
|
if (existing && existing.readyState <= WebSocket.OPEN) {
|
|
104
115
|
this.bunSocket = existing;
|
|
105
116
|
} else {
|
|
106
117
|
const socket = new WebSocket(
|
|
107
|
-
`ws://localhost:${
|
|
118
|
+
`ws://localhost:${this.env.rpcPort}/socket?webviewId=${this.env.webviewId}`
|
|
108
119
|
);
|
|
109
120
|
socket.binaryType = "arraybuffer";
|
|
110
121
|
this.bunSocket = socket;
|
|
@@ -116,7 +127,7 @@ export class BuniteView<T extends RpcWithTransport = RpcWithTransport> {
|
|
|
116
127
|
if (!binaryMessage) return;
|
|
117
128
|
|
|
118
129
|
try {
|
|
119
|
-
const decrypt =
|
|
130
|
+
const decrypt = this.env.window?.__bunite_decrypt;
|
|
120
131
|
if (!decrypt) {
|
|
121
132
|
log.error("No decrypt function available in preload globals");
|
|
122
133
|
return;
|
|
@@ -151,7 +162,7 @@ export class BuniteView<T extends RpcWithTransport = RpcWithTransport> {
|
|
|
151
162
|
async bunBridge(message: RpcPacket) {
|
|
152
163
|
if (this.bunSocket?.readyState !== WebSocket.OPEN) return;
|
|
153
164
|
|
|
154
|
-
const encrypt =
|
|
165
|
+
const encrypt = this.env.window?.__bunite_encrypt;
|
|
155
166
|
if (!encrypt) {
|
|
156
167
|
log.error("No encrypt function available in preload globals");
|
|
157
168
|
return;
|
|
@@ -171,7 +182,7 @@ async function messageToUint8Array(data: unknown) {
|
|
|
171
182
|
}
|
|
172
183
|
|
|
173
184
|
export { log, type LogLevel } from "../shared/log";
|
|
174
|
-
export { createRpcTransportDemuxer, createWebSocketTransport, defineWebviewRpc };
|
|
185
|
+
export { createRpcTransportDemuxer, createWebSocketTransport, defineWebviewRpc, registerBuniteWebviewPolyfill };
|
|
175
186
|
|
|
176
187
|
export type {
|
|
177
188
|
BuniteRpcConfig,
|