bunite-core 0.0.12 → 0.0.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bunite-core",
3
3
  "description": "Uniting UI and Bun",
4
- "version": "0.0.12",
4
+ "version": "0.0.13",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "setup:cef": "bun ../tools/bunite-dev/scripts/setup-cef.ts",
@@ -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, type RPCRequestHandler } from "../../shared/rpc";
5
+ import { defineBuniteRPC, type BuniteRPCConfig, type BuniteRPCSchema, 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";
@@ -165,8 +165,11 @@ export class BrowserView<T extends RPCWithTransport = RPCWithTransport> {
165
165
  config: BuniteRPCConfig<Schema, "bun">
166
166
  ) {
167
167
  const rpc = defineBuniteRPC("bun", config);
168
+ const webRpc = createWebRPCHandler<Schema>(config);
168
169
  return Object.assign(rpc, {
169
- webHandler: createWebRPCHandler((config.handlers.requests ?? {}) as any)
170
+ webHandler: webRpc,
171
+ webClients: webRpc.webClients,
172
+ broadcast: webRpc.broadcast,
170
173
  });
171
174
  }
172
175
 
@@ -1,48 +1,92 @@
1
+ import {
2
+ defineBuniteRPC,
3
+ type BuniteRPCConfig,
4
+ type BuniteRPCSchema,
5
+ type RPCTransport,
6
+ type RPCPacket
7
+ } from "./rpc";
1
8
  import { decodeRPCPacket, encodeRPCPacket, asUint8Array } from "./rpcWire";
2
9
 
3
- type WebRPCHandlers = Record<string, (params?: unknown) => unknown>;
10
+ type WebRPCSocket = { send(data: Uint8Array | ArrayBuffer): void | number };
4
11
 
5
- /** Minimal ws interface compatible with Bun's ServerWebSocket. */
6
- type WebRPCSocket = { send(data: Uint8Array): void | number };
12
+ export type WebRPCClient<Schema extends BuniteRPCSchema = BuniteRPCSchema> = {
13
+ ws: WebRPCSocket;
14
+ rpc: ReturnType<typeof defineBuniteRPC<Schema, "bun">>;
15
+ handlePacket: (packet: RPCPacket) => void | Promise<void>;
16
+ };
7
17
 
8
- function errorMessage(error: unknown): string {
9
- return error instanceof Error ? error.message : String(error);
10
- }
18
+ export function createWebRPCHandler<Schema extends BuniteRPCSchema>(
19
+ config: BuniteRPCConfig<Schema, "bun"> & {
20
+ extraRequestHandlers?: Record<string, (...args: any[]) => unknown>;
21
+ }
22
+ ) {
23
+ const connections = new WeakMap<WebRPCSocket, WebRPCClient<Schema>>();
24
+ const webClients = new Set<WebRPCClient<Schema>>();
25
+
26
+ const handler = {
27
+ open(ws: WebRPCSocket) {
28
+ let handlePacket: ((packet: RPCPacket) => void | Promise<void>) | undefined;
29
+
30
+ const transport: RPCTransport = {
31
+ send(packet) {
32
+ ws.send(encodeRPCPacket(packet));
33
+ },
34
+ registerHandler(h) {
35
+ handlePacket = h;
36
+ },
37
+ unregisterHandler() {
38
+ handlePacket = undefined;
39
+ }
40
+ };
41
+
42
+ const rpc = defineBuniteRPC("bun", config);
43
+ rpc.setTransport(transport);
44
+
45
+ const client: WebRPCClient<Schema> = {
46
+ ws,
47
+ rpc: rpc as WebRPCClient<Schema>["rpc"],
48
+ handlePacket: (packet) => handlePacket?.(packet)
49
+ };
50
+
51
+ connections.set(ws, client);
52
+ webClients.add(client);
53
+ handler.onWebClientConnected?.(client);
54
+ },
11
55
 
12
- export function createWebRPCHandler(handlers: WebRPCHandlers) {
13
- return {
14
- message(ws: WebRPCSocket, raw: string | Buffer) {
56
+ message(ws: WebRPCSocket, raw: string | Buffer | ArrayBuffer | Uint8Array) {
15
57
  if (typeof raw === "string") return;
16
58
 
17
- let packet;
59
+ const client = connections.get(ws);
60
+ if (!client) return;
61
+
18
62
  try {
19
- packet = decodeRPCPacket(asUint8Array(raw));
63
+ client.handlePacket(decodeRPCPacket(asUint8Array(raw)));
20
64
  } catch {
21
- return;
65
+ // malformed packet
22
66
  }
67
+ },
23
68
 
24
- if (packet.type !== "request" || typeof packet.method !== "string") return;
69
+ close(ws: WebRPCSocket) {
70
+ const client = connections.get(ws);
71
+ if (!client) return;
25
72
 
26
- const handler = handlers[packet.method];
27
- if (!handler) {
28
- ws.send(
29
- encodeRPCPacket({ type: "response", id: packet.id, success: false, error: `Unknown method: ${packet.method}` })
30
- );
31
- return;
32
- }
73
+ webClients.delete(client);
74
+ handler.onWebClientDisconnected?.(client);
75
+ client.rpc.setTransport({});
76
+ connections.delete(ws);
77
+ },
33
78
 
34
- try {
35
- Promise.resolve(handler(packet.params)).then(
36
- (payload) =>
37
- ws.send(encodeRPCPacket({ type: "response", id: packet.id, success: true, payload })),
38
- (error) =>
39
- ws.send(encodeRPCPacket({ type: "response", id: packet.id, success: false, error: errorMessage(error) }))
40
- );
41
- } catch (error) {
42
- ws.send(
43
- encodeRPCPacket({ type: "response", id: packet.id, success: false, error: errorMessage(error) })
44
- );
79
+ webClients: webClients as ReadonlySet<WebRPCClient<Schema>>,
80
+
81
+ broadcast(messageName: string, payload?: unknown) {
82
+ for (const client of webClients) {
83
+ (client.rpc.send as any)(messageName, payload);
45
84
  }
46
- }
85
+ },
86
+
87
+ onWebClientConnected: undefined as ((client: WebRPCClient<Schema>) => void) | undefined,
88
+ onWebClientDisconnected: undefined as ((client: WebRPCClient<Schema>) => void) | undefined,
47
89
  };
90
+
91
+ return handler;
48
92
  }