bunite-core 0.0.14 → 0.1.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 -1
- package/src/bun/core/App.ts +10 -4
- package/src/bun/core/BrowserView.ts +19 -19
- package/src/bun/core/BrowserWindow.ts +6 -0
- package/src/bun/index.ts +7 -0
- package/src/shared/rpcDemux.ts +65 -0
- package/src/shared/webRpcHandler.ts +23 -46
- package/src/shared/webSocketTransport.ts +26 -0
- package/src/view/index.ts +40 -43
package/package.json
CHANGED
package/src/bun/core/App.ts
CHANGED
|
@@ -31,6 +31,10 @@ type AppOptions = NativeBootstrapOptions & {
|
|
|
31
31
|
|
|
32
32
|
export type GlobalIPCHandler = (params: unknown, ctx: { viewId: number }) => unknown | Promise<unknown>;
|
|
33
33
|
|
|
34
|
+
function normalizeAppResPath(path: string): string {
|
|
35
|
+
return path.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
36
|
+
}
|
|
37
|
+
|
|
34
38
|
export class AppRuntime {
|
|
35
39
|
private stubKeepAliveTimer: ReturnType<typeof setInterval> | null = null;
|
|
36
40
|
private readonly globalIPCHandlers = new Map<string, GlobalIPCHandler>();
|
|
@@ -209,13 +213,15 @@ export class AppRuntime {
|
|
|
209
213
|
private readonly appresHandlers = new Map<string, () => string>();
|
|
210
214
|
|
|
211
215
|
getAppRes(path: string, handler: () => string) {
|
|
212
|
-
|
|
213
|
-
|
|
216
|
+
const normalized = normalizeAppResPath(path);
|
|
217
|
+
this.appresHandlers.set(normalized, handler);
|
|
218
|
+
getNativeLibrary()?.symbols.bunite_register_appres_route(toCString(normalized));
|
|
214
219
|
}
|
|
215
220
|
|
|
216
221
|
removeAppRes(path: string) {
|
|
217
|
-
|
|
218
|
-
|
|
222
|
+
const normalized = normalizeAppResPath(path);
|
|
223
|
+
this.appresHandlers.delete(normalized);
|
|
224
|
+
getNativeLibrary()?.symbols.bunite_unregister_appres_route(toCString(normalized));
|
|
219
225
|
}
|
|
220
226
|
|
|
221
227
|
/** @internal */
|
|
@@ -2,7 +2,7 @@ import { ptr } from "bun:ffi";
|
|
|
2
2
|
import { buildViewPreloadScript } from "../preload/inline";
|
|
3
3
|
import { log } from "../../shared/log";
|
|
4
4
|
import { buniteEventEmitter } from "../events/eventEmitter";
|
|
5
|
-
import { defineBuniteRPC, type BuniteRPCConfig, type BuniteRPCSchema, type RPCWithTransport } from "../../shared/rpc";
|
|
5
|
+
import { defineBuniteRPC, type BuniteRPCConfig, type BuniteRPCSchema, type RPCPacket, type RPCTransport, type RPCWithTransport } from "../../shared/rpc";
|
|
6
6
|
import { createWebRPCHandler } from "../../shared/webRpcHandler";
|
|
7
7
|
import { ensureNativeRuntime, getNativeLibrary, toCString, waitForViewReady, cancelWaitForViewReady } from "../proc/native";
|
|
8
8
|
import { attachBrowserViewRegistry, getRPCPort, sendMessageToView } from "./Socket";
|
|
@@ -14,6 +14,16 @@ import { cancelPendingMessageBoxesForView } from "./Utils";
|
|
|
14
14
|
const BrowserViewMap: Record<number, BrowserView<any>> = {};
|
|
15
15
|
let nextWebviewId = 1;
|
|
16
16
|
|
|
17
|
+
function createNativeViewPipe(viewId: number) {
|
|
18
|
+
let handler: ((packet: RPCPacket) => void) | undefined;
|
|
19
|
+
const transport: RPCTransport = {
|
|
20
|
+
send: (packet) => { sendMessageToView(viewId, packet); },
|
|
21
|
+
registerHandler: (h) => { handler = h; },
|
|
22
|
+
unregisterHandler: () => { handler = undefined; }
|
|
23
|
+
};
|
|
24
|
+
return { transport, receive: (packet: RPCPacket) => handler?.(packet) };
|
|
25
|
+
}
|
|
26
|
+
|
|
17
27
|
export type BrowserViewOptions<T = undefined> = {
|
|
18
28
|
url: string | null;
|
|
19
29
|
html: string | null;
|
|
@@ -66,7 +76,8 @@ export class BrowserView<T extends RPCWithTransport = RPCWithTransport> {
|
|
|
66
76
|
partition: string | null;
|
|
67
77
|
frame: BrowserViewOptions["frame"];
|
|
68
78
|
rpc?: T;
|
|
69
|
-
|
|
79
|
+
readonly transport: RPCTransport;
|
|
80
|
+
private pipe: ReturnType<typeof createNativeViewPipe>;
|
|
70
81
|
autoResize: boolean;
|
|
71
82
|
navigationRules: string[] | null;
|
|
72
83
|
sandbox: boolean;
|
|
@@ -75,6 +86,9 @@ export class BrowserView<T extends RPCWithTransport = RPCWithTransport> {
|
|
|
75
86
|
constructor(options: Partial<BrowserViewOptions<T>>) {
|
|
76
87
|
ensureNativeRuntime();
|
|
77
88
|
|
|
89
|
+
this.pipe = createNativeViewPipe(this.id);
|
|
90
|
+
this.transport = this.pipe.transport;
|
|
91
|
+
|
|
78
92
|
this.windowId = options.windowId ?? defaultOptions.windowId;
|
|
79
93
|
this.url = options.url ?? defaultOptions.url;
|
|
80
94
|
this.html = options.html ?? defaultOptions.html;
|
|
@@ -105,7 +119,7 @@ export class BrowserView<T extends RPCWithTransport = RPCWithTransport> {
|
|
|
105
119
|
});
|
|
106
120
|
|
|
107
121
|
BrowserViewMap[this.id] = this;
|
|
108
|
-
this.rpc?.setTransport(this.
|
|
122
|
+
this.rpc?.setTransport(this.transport);
|
|
109
123
|
// Register ready waiter BEFORE native create — OnAfterCreated can fire
|
|
110
124
|
// on the CEF UI thread before bunite_view_create returns to JS.
|
|
111
125
|
this._readyPromise = waitForViewReady(this.id);
|
|
@@ -173,22 +187,8 @@ export class BrowserView<T extends RPCWithTransport = RPCWithTransport> {
|
|
|
173
187
|
});
|
|
174
188
|
}
|
|
175
189
|
|
|
176
|
-
handleIncomingRPC(
|
|
177
|
-
this.
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
createTransport() {
|
|
181
|
-
return {
|
|
182
|
-
send: (message: any) => {
|
|
183
|
-
sendMessageToView(this.id, message);
|
|
184
|
-
},
|
|
185
|
-
registerHandler: (handler: (message: any) => void) => {
|
|
186
|
-
this.rpcHandler = handler;
|
|
187
|
-
},
|
|
188
|
-
unregisterHandler: () => {
|
|
189
|
-
this.rpcHandler = undefined;
|
|
190
|
-
}
|
|
191
|
-
};
|
|
190
|
+
handleIncomingRPC(packet: RPCPacket) {
|
|
191
|
+
this.pipe.receive(packet);
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
get rpcPort() {
|
|
@@ -202,6 +202,12 @@ export class BrowserWindow<T extends RPCWithTransport = RPCWithTransport> {
|
|
|
202
202
|
this.webviewId = webview.id;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
get view(): BrowserView<T> {
|
|
206
|
+
const view = BrowserView.getById(this.webviewId);
|
|
207
|
+
if (!view) throw new Error(`BrowserWindow ${this.id} has no attached view`);
|
|
208
|
+
return view as BrowserView<T>;
|
|
209
|
+
}
|
|
210
|
+
|
|
205
211
|
static getById(id: number) {
|
|
206
212
|
return BrowserWindowMap[id];
|
|
207
213
|
}
|
package/src/bun/index.ts
CHANGED
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
type RPCSchema,
|
|
14
14
|
type RPCWithTransport
|
|
15
15
|
} from "../shared/rpc";
|
|
16
|
+
import { createTransportDemuxer, type TransportDemuxer } from "../shared/rpcDemux";
|
|
17
|
+
import { createWebSocketTransport, type WebSocketLike, type WebSocketTransportPipe } from "../shared/webSocketTransport";
|
|
16
18
|
import type { MessageBoxOptions, MessageBoxResponse } from "./core/Utils";
|
|
17
19
|
import { log, type LogLevel } from "../shared/log";
|
|
18
20
|
|
|
@@ -24,6 +26,8 @@ export {
|
|
|
24
26
|
buniteEventEmitter,
|
|
25
27
|
completePermissionRequest,
|
|
26
28
|
createRPC,
|
|
29
|
+
createTransportDemuxer,
|
|
30
|
+
createWebSocketTransport,
|
|
27
31
|
defineBuniteRPC,
|
|
28
32
|
log
|
|
29
33
|
};
|
|
@@ -38,5 +42,8 @@ export type {
|
|
|
38
42
|
MessageBoxResponse,
|
|
39
43
|
RPCSchema,
|
|
40
44
|
RPCWithTransport,
|
|
45
|
+
TransportDemuxer,
|
|
46
|
+
WebSocketLike,
|
|
47
|
+
WebSocketTransportPipe,
|
|
41
48
|
WindowOptionsType
|
|
42
49
|
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { RPCPacket, RPCTransport } from "./rpc";
|
|
2
|
+
|
|
3
|
+
type DemuxEnvelope = { channel: string; packet: RPCPacket };
|
|
4
|
+
|
|
5
|
+
function isDemuxEnvelope(value: unknown): value is DemuxEnvelope {
|
|
6
|
+
if (typeof value !== "object" || value === null) return false;
|
|
7
|
+
const v = value as Partial<DemuxEnvelope>;
|
|
8
|
+
return typeof v.channel === "string" && typeof v.packet === "object" && v.packet !== null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type TransportDemuxer = {
|
|
12
|
+
channel(name: string): RPCTransport;
|
|
13
|
+
dispose(): void;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function createTransportDemuxer(base: RPCTransport): TransportDemuxer {
|
|
17
|
+
if (!base.send || !base.registerHandler) {
|
|
18
|
+
throw new Error("createTransportDemuxer requires a base transport with both send and registerHandler");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const handlers = new Map<string, (packet: RPCPacket) => void>();
|
|
22
|
+
let disposed = false;
|
|
23
|
+
|
|
24
|
+
base.registerHandler((data) => {
|
|
25
|
+
// Envelopes missing or malformed are dropped. A future fallthrough hook
|
|
26
|
+
// would land here if we ever multiplex legacy RPC on the same transport.
|
|
27
|
+
if (!isDemuxEnvelope(data)) return;
|
|
28
|
+
handlers.get(data.channel)?.(data.packet);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
channel(name) {
|
|
33
|
+
let ownHandler: ((packet: RPCPacket) => void) | undefined;
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
send(packet) {
|
|
37
|
+
if (disposed) throw new Error(`Demuxer disposed; cannot send on channel "${name}"`);
|
|
38
|
+
const envelope: DemuxEnvelope = { channel: name, packet };
|
|
39
|
+
// The wire layer (msgpackr) serializes the envelope opaquely, so
|
|
40
|
+
// routing the wider type through RPCTransport.send is safe in practice.
|
|
41
|
+
base.send!(envelope as unknown as RPCPacket);
|
|
42
|
+
},
|
|
43
|
+
registerHandler(handler) {
|
|
44
|
+
if (disposed) throw new Error(`Demuxer disposed; cannot register on channel "${name}"`);
|
|
45
|
+
if (handlers.has(name)) {
|
|
46
|
+
throw new Error(`Channel "${name}" already has a handler on this demuxer`);
|
|
47
|
+
}
|
|
48
|
+
ownHandler = handler;
|
|
49
|
+
handlers.set(name, handler);
|
|
50
|
+
},
|
|
51
|
+
unregisterHandler() {
|
|
52
|
+
if (ownHandler && handlers.get(name) === ownHandler) {
|
|
53
|
+
handlers.delete(name);
|
|
54
|
+
ownHandler = undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
dispose() {
|
|
60
|
+
disposed = true;
|
|
61
|
+
handlers.clear();
|
|
62
|
+
base.unregisterHandler?.();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
defineBuniteRPC,
|
|
3
3
|
type BuniteRPCConfig,
|
|
4
|
-
type BuniteRPCSchema
|
|
5
|
-
type RPCTransport,
|
|
6
|
-
type RPCPacket
|
|
4
|
+
type BuniteRPCSchema
|
|
7
5
|
} from "./rpc";
|
|
8
|
-
import {
|
|
6
|
+
import { createWebSocketTransport, type WebSocketLike } from "./webSocketTransport";
|
|
9
7
|
import { log } from "./log";
|
|
10
8
|
|
|
11
|
-
type WebRPCSocket = { send(data: Uint8Array | ArrayBuffer): void | number };
|
|
12
|
-
|
|
13
9
|
export type WebRPCClient<Schema extends BuniteRPCSchema = BuniteRPCSchema> = {
|
|
14
|
-
ws:
|
|
10
|
+
ws: WebSocketLike;
|
|
15
11
|
rpc: ReturnType<typeof defineBuniteRPC<Schema, "bun">>;
|
|
16
|
-
handlePacket: (packet: RPCPacket) => void | Promise<void>;
|
|
17
12
|
};
|
|
18
13
|
|
|
19
14
|
export function createWebRPCHandler<Schema extends BuniteRPCSchema>(
|
|
@@ -21,62 +16,44 @@ export function createWebRPCHandler<Schema extends BuniteRPCSchema>(
|
|
|
21
16
|
extraRequestHandlers?: Record<string, (...args: any[]) => unknown>;
|
|
22
17
|
}
|
|
23
18
|
) {
|
|
24
|
-
|
|
19
|
+
type Entry = { client: WebRPCClient<Schema>; receive: (raw: ArrayBuffer | Uint8Array) => void };
|
|
20
|
+
|
|
21
|
+
const connections = new WeakMap<WebSocketLike, Entry>();
|
|
25
22
|
const webClients = new Set<WebRPCClient<Schema>>();
|
|
26
23
|
|
|
27
24
|
const handler = {
|
|
28
|
-
open(ws:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const transport: RPCTransport = {
|
|
32
|
-
send(packet) {
|
|
33
|
-
ws.send(encodeRPCPacket(packet));
|
|
34
|
-
},
|
|
35
|
-
registerHandler(h) {
|
|
36
|
-
handlePacket = h;
|
|
37
|
-
},
|
|
38
|
-
unregisterHandler() {
|
|
39
|
-
handlePacket = undefined;
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
25
|
+
open(ws: WebSocketLike) {
|
|
26
|
+
const pipe = createWebSocketTransport(ws);
|
|
43
27
|
const rpc = defineBuniteRPC("bun", config);
|
|
44
|
-
rpc.setTransport(transport);
|
|
28
|
+
rpc.setTransport(pipe.transport);
|
|
45
29
|
|
|
46
|
-
const client: WebRPCClient<Schema> = {
|
|
47
|
-
ws,
|
|
48
|
-
rpc: rpc as WebRPCClient<Schema>["rpc"],
|
|
49
|
-
handlePacket: (packet) => handlePacket?.(packet)
|
|
50
|
-
};
|
|
30
|
+
const client: WebRPCClient<Schema> = { ws, rpc: rpc as WebRPCClient<Schema>["rpc"] };
|
|
51
31
|
|
|
52
|
-
connections.set(ws, client);
|
|
32
|
+
connections.set(ws, { client, receive: pipe.receive });
|
|
53
33
|
webClients.add(client);
|
|
54
34
|
handler.onWebClientConnected?.(client);
|
|
55
35
|
},
|
|
56
36
|
|
|
57
|
-
message(ws:
|
|
37
|
+
message(ws: WebSocketLike, raw: string | Buffer | ArrayBuffer | Uint8Array) {
|
|
58
38
|
if (typeof raw === "string") return;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (!client) return;
|
|
39
|
+
const entry = connections.get(ws);
|
|
40
|
+
if (!entry) return;
|
|
62
41
|
|
|
63
42
|
try {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
} catch {
|
|
68
|
-
// malformed packet — decode failure
|
|
43
|
+
entry.receive(raw);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
log.error("Web RPC packet handler error", error);
|
|
69
46
|
}
|
|
70
47
|
},
|
|
71
48
|
|
|
72
|
-
close(ws:
|
|
73
|
-
const
|
|
74
|
-
if (!
|
|
49
|
+
close(ws: WebSocketLike) {
|
|
50
|
+
const entry = connections.get(ws);
|
|
51
|
+
if (!entry) return;
|
|
75
52
|
|
|
76
|
-
client.rpc.dispose();
|
|
77
|
-
webClients.delete(client);
|
|
53
|
+
entry.client.rpc.dispose();
|
|
54
|
+
webClients.delete(entry.client);
|
|
78
55
|
connections.delete(ws);
|
|
79
|
-
handler.onWebClientDisconnected?.(client);
|
|
56
|
+
handler.onWebClientDisconnected?.(entry.client);
|
|
80
57
|
},
|
|
81
58
|
|
|
82
59
|
webClients: webClients as ReadonlySet<WebRPCClient<Schema>>,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { RPCPacket, RPCTransport } from "./rpc";
|
|
2
|
+
import { asUint8Array, decodeRPCPacket, encodeRPCPacket } from "./rpcWire";
|
|
3
|
+
|
|
4
|
+
export type WebSocketLike = {
|
|
5
|
+
send(data: Uint8Array | ArrayBuffer): void | number;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export type WebSocketTransportPipe = {
|
|
9
|
+
transport: RPCTransport;
|
|
10
|
+
receive(raw: ArrayBuffer | ArrayBufferView | Uint8Array): void;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function createWebSocketTransport(ws: WebSocketLike): WebSocketTransportPipe {
|
|
14
|
+
let handler: ((packet: RPCPacket) => void) | undefined;
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
transport: {
|
|
18
|
+
send(packet) { ws.send(encodeRPCPacket(packet)); },
|
|
19
|
+
registerHandler(h) { handler = h; },
|
|
20
|
+
unregisterHandler() { handler = undefined; }
|
|
21
|
+
},
|
|
22
|
+
receive(raw) {
|
|
23
|
+
handler?.(decodeRPCPacket(asUint8Array(raw)));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
package/src/view/index.ts
CHANGED
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
type RPCTransport,
|
|
9
9
|
type RPCWithTransport
|
|
10
10
|
} from "../shared/rpc";
|
|
11
|
+
import { createTransportDemuxer, type TransportDemuxer } from "../shared/rpcDemux";
|
|
12
|
+
import { createWebSocketTransport, type WebSocketLike, type WebSocketTransportPipe } from "../shared/webSocketTransport";
|
|
11
13
|
import { decodeRPCPacket, encodeRPCPacket } from "../shared/rpcWire";
|
|
12
14
|
import { log } from "../shared/log";
|
|
13
15
|
|
|
@@ -34,24 +36,37 @@ function toArrayBuffer(bytes: Uint8Array): ArrayBuffer {
|
|
|
34
36
|
return copy.buffer;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
export class BuniteView<T extends RPCWithTransport> {
|
|
39
|
+
export class BuniteView<T extends RPCWithTransport = RPCWithTransport> {
|
|
38
40
|
bunSocket?: WebSocket;
|
|
39
41
|
rpc?: T;
|
|
40
|
-
|
|
42
|
+
readonly transport: RPCTransport;
|
|
43
|
+
|
|
44
|
+
private handler?: (packet: RPCPacket) => void;
|
|
41
45
|
private pendingPackets: RPCPacket[] = [];
|
|
42
46
|
|
|
43
|
-
constructor(config
|
|
44
|
-
this.rpc = config
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
constructor(config?: { rpc?: T }) {
|
|
48
|
+
this.rpc = config?.rpc;
|
|
49
|
+
|
|
50
|
+
this.transport = {
|
|
51
|
+
send: (packet) => {
|
|
52
|
+
if (this.bunSocket?.readyState === WebSocket.OPEN) {
|
|
53
|
+
this.sendPacket(packet);
|
|
54
|
+
} else if (this.bunSocket?.readyState === WebSocket.CONNECTING) {
|
|
55
|
+
this.pendingPackets.push(packet);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
registerHandler: (h) => { this.handler = h; },
|
|
59
|
+
unregisterHandler: () => { this.handler = undefined; }
|
|
60
|
+
};
|
|
47
61
|
|
|
48
|
-
init() {
|
|
49
62
|
this.initSocketToBun();
|
|
50
63
|
if (isNative) {
|
|
51
64
|
buniteWindow.__bunite ??= {};
|
|
52
|
-
buniteWindow.__bunite.receiveMessageFromBun =
|
|
65
|
+
buniteWindow.__bunite.receiveMessageFromBun = (message) => {
|
|
66
|
+
this.handler?.(message as RPCPacket);
|
|
67
|
+
};
|
|
53
68
|
}
|
|
54
|
-
this.rpc?.setTransport(this.
|
|
69
|
+
this.rpc?.setTransport(this.transport);
|
|
55
70
|
}
|
|
56
71
|
|
|
57
72
|
private sendPacket(packet: RPCPacket) {
|
|
@@ -72,10 +87,10 @@ export class BuniteView<T extends RPCWithTransport> {
|
|
|
72
87
|
this.bunSocket = socket;
|
|
73
88
|
|
|
74
89
|
socket.addEventListener("message", async (event) => {
|
|
75
|
-
const bytes = await
|
|
90
|
+
const bytes = await messageToUint8Array(event.data);
|
|
76
91
|
if (!bytes) return;
|
|
77
92
|
try {
|
|
78
|
-
this.
|
|
93
|
+
this.handler?.(decodeRPCPacket(bytes));
|
|
79
94
|
} catch (error) {
|
|
80
95
|
log.error("Failed to parse WebSocket message", error);
|
|
81
96
|
}
|
|
@@ -97,7 +112,7 @@ export class BuniteView<T extends RPCWithTransport> {
|
|
|
97
112
|
}
|
|
98
113
|
|
|
99
114
|
this.bunSocket!.addEventListener("message", async (event) => {
|
|
100
|
-
const binaryMessage = await
|
|
115
|
+
const binaryMessage = await messageToUint8Array(event.data);
|
|
101
116
|
if (!binaryMessage) return;
|
|
102
117
|
|
|
103
118
|
try {
|
|
@@ -109,7 +124,7 @@ export class BuniteView<T extends RPCWithTransport> {
|
|
|
109
124
|
const decrypted = await decrypt(binaryMessage);
|
|
110
125
|
const packet = decodeRPCPacket(decrypted);
|
|
111
126
|
if ((packet as any).scope === "global") return;
|
|
112
|
-
this.
|
|
127
|
+
this.handler?.(packet);
|
|
113
128
|
} catch (error) {
|
|
114
129
|
log.error("Failed to parse message from Bun", error);
|
|
115
130
|
}
|
|
@@ -133,35 +148,6 @@ export class BuniteView<T extends RPCWithTransport> {
|
|
|
133
148
|
});
|
|
134
149
|
}
|
|
135
150
|
|
|
136
|
-
async messageToUint8Array(data: unknown) {
|
|
137
|
-
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
|
138
|
-
if (data instanceof Blob) return new Uint8Array(await data.arrayBuffer());
|
|
139
|
-
if (data instanceof Uint8Array) return data;
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
createTransport(): RPCTransport {
|
|
144
|
-
return {
|
|
145
|
-
send: (message) => {
|
|
146
|
-
if (this.bunSocket?.readyState === WebSocket.OPEN) {
|
|
147
|
-
this.sendPacket(message);
|
|
148
|
-
} else if (this.bunSocket?.readyState === WebSocket.CONNECTING) {
|
|
149
|
-
this.pendingPackets.push(message);
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
registerHandler: (handler: (packet: any) => void) => {
|
|
153
|
-
this.rpcHandler = handler;
|
|
154
|
-
},
|
|
155
|
-
unregisterHandler: () => {
|
|
156
|
-
this.rpcHandler = undefined;
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
receiveMessageFromBun(message: unknown) {
|
|
162
|
-
this.rpcHandler?.(message);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
151
|
async bunBridge(message: RPCPacket) {
|
|
166
152
|
if (this.bunSocket?.readyState !== WebSocket.OPEN) return;
|
|
167
153
|
|
|
@@ -184,10 +170,21 @@ export class BuniteView<T extends RPCWithTransport> {
|
|
|
184
170
|
}
|
|
185
171
|
}
|
|
186
172
|
|
|
173
|
+
async function messageToUint8Array(data: unknown) {
|
|
174
|
+
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
|
175
|
+
if (data instanceof Blob) return new Uint8Array(await data.arrayBuffer());
|
|
176
|
+
if (data instanceof Uint8Array) return data;
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
187
180
|
export { log, type LogLevel } from "../shared/log";
|
|
181
|
+
export { createTransportDemuxer, createWebSocketTransport, defineBuniteRPC };
|
|
188
182
|
|
|
189
183
|
export type {
|
|
190
184
|
BuniteRPCConfig,
|
|
191
185
|
BuniteRPCSchema,
|
|
192
|
-
RPCSchema
|
|
186
|
+
RPCSchema,
|
|
187
|
+
TransportDemuxer,
|
|
188
|
+
WebSocketLike,
|
|
189
|
+
WebSocketTransportPipe
|
|
193
190
|
};
|