bunite-core 0.0.1

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.
@@ -0,0 +1,399 @@
1
+ export type RPCRequestPacket = {
2
+ type: "request";
3
+ id: number;
4
+ method: string;
5
+ params: unknown;
6
+ scope?: "global";
7
+ };
8
+
9
+ export type RPCResponsePacket =
10
+ | { type: "response"; id: number; success: true; payload: unknown; scope?: "global" }
11
+ | { type: "response"; id: number; success: false; error?: string; scope?: "global" };
12
+
13
+ export type RPCMessagePacket = {
14
+ type: "message";
15
+ id: string;
16
+ payload: unknown;
17
+ };
18
+
19
+ export type RPCPacket = RPCRequestPacket | RPCResponsePacket | RPCMessagePacket;
20
+
21
+ type BaseRPCRequestsSchema = Record<string, { params: unknown; response: unknown }>;
22
+ type BaseRPCMessagesSchema = Record<string, unknown>;
23
+
24
+ export type RPCRequestsSchema<T extends BaseRPCRequestsSchema = BaseRPCRequestsSchema> = T;
25
+ export type RPCMessagesSchema<T extends BaseRPCMessagesSchema = BaseRPCMessagesSchema> = T;
26
+
27
+ type InputRPCSchema = {
28
+ requests?: RPCRequestsSchema;
29
+ messages?: RPCMessagesSchema;
30
+ };
31
+
32
+ type ResolvedRPCSchema<I extends InputRPCSchema> = {
33
+ requests: undefined extends I["requests"] ? BaseRPCRequestsSchema : NonNullable<I["requests"]>;
34
+ messages: undefined extends I["messages"] ? BaseRPCMessagesSchema : NonNullable<I["messages"]>;
35
+ };
36
+
37
+ export type RPCSchema<I extends InputRPCSchema | void = InputRPCSchema> = ResolvedRPCSchema<
38
+ I extends InputRPCSchema ? I : InputRPCSchema
39
+ >;
40
+
41
+ type RequestParams<RS extends RPCRequestsSchema, M extends keyof RS> = RS[M]["params"];
42
+ type RequestResponse<RS extends RPCRequestsSchema, M extends keyof RS> = RS[M]["response"];
43
+ type MessagePayload<MS extends RPCMessagesSchema, N extends keyof MS> = MS[N];
44
+
45
+ type RPCRequestHandlerFn<RS extends RPCRequestsSchema> = <M extends keyof RS>(
46
+ method: M,
47
+ params: RequestParams<RS, M>
48
+ ) => Promise<RequestResponse<RS, M>> | RequestResponse<RS, M>;
49
+
50
+ type RPCRequestHandlerObject<RS extends RPCRequestsSchema> = {
51
+ [M in keyof RS]?: (
52
+ ...args: undefined extends RS[M]["params"] ? [params?: RS[M]["params"]] : [params: RS[M]["params"]]
53
+ ) => Promise<Awaited<RequestResponse<RS, M>>> | Awaited<RequestResponse<RS, M>>;
54
+ } & {
55
+ _?: (method: keyof RS, params: RequestParams<RS, keyof RS>) => unknown;
56
+ };
57
+
58
+ export type RPCRequestHandler<RS extends RPCRequestsSchema = RPCRequestsSchema> =
59
+ | RPCRequestHandlerFn<RS>
60
+ | RPCRequestHandlerObject<RS>;
61
+
62
+ export type RPCTransport = {
63
+ send?: (data: RPCPacket) => void;
64
+ registerHandler?: (handler: (packet: RPCPacket) => void) => void;
65
+ unregisterHandler?: () => void;
66
+ };
67
+
68
+ export interface RPCWithTransport {
69
+ setTransport: (transport: RPCTransport) => void;
70
+ }
71
+
72
+ export type BuniteRPCSchema = {
73
+ bun: RPCSchema;
74
+ webview: RPCSchema;
75
+ };
76
+
77
+ export type BuniteRPCConfig<
78
+ Schema extends BuniteRPCSchema,
79
+ Side extends "bun" | "webview"
80
+ > = {
81
+ maxRequestTime?: number;
82
+ handlers: {
83
+ requests?: RPCRequestHandler<Schema[Side]["requests"]>;
84
+ messages?: {
85
+ [K in keyof Schema[Side]["messages"]]?: (
86
+ payload: MessagePayload<Schema[Side]["messages"], K>
87
+ ) => void;
88
+ } & {
89
+ "*"?: (
90
+ messageName: keyof Schema[Side]["messages"],
91
+ payload: MessagePayload<Schema[Side]["messages"], keyof Schema[Side]["messages"]>
92
+ ) => void;
93
+ };
94
+ };
95
+ };
96
+
97
+ const MAX_ID = 1e10;
98
+ const DEFAULT_MAX_REQUEST_TIME = 15_000;
99
+
100
+ function missingTransportMethodError(methods: string[], action: string): Error {
101
+ return new Error(
102
+ `This RPC instance cannot ${action} because the transport did not provide: ${methods.join(", ")}`
103
+ );
104
+ }
105
+
106
+ export function createRPC<
107
+ Schema extends RPCSchema = RPCSchema,
108
+ RemoteSchema extends RPCSchema = Schema
109
+ >(options: {
110
+ transport?: RPCTransport;
111
+ requestHandler?: RPCRequestHandler<Schema["requests"]>;
112
+ maxRequestTime?: number;
113
+ } = {}) {
114
+ let transport: RPCTransport = {};
115
+ let requestHandler:
116
+ | RPCRequestHandlerFn<Schema["requests"]>
117
+ | undefined;
118
+
119
+ function setTransport(nextTransport: RPCTransport) {
120
+ transport.unregisterHandler?.();
121
+ transport = nextTransport;
122
+ transport.registerHandler?.(handlePacket);
123
+ }
124
+
125
+ function setRequestHandler(handler: RPCRequestHandler<Schema["requests"]>) {
126
+ if (typeof handler === "function") {
127
+ requestHandler = handler as RPCRequestHandlerFn<Schema["requests"]>;
128
+ return;
129
+ }
130
+
131
+ requestHandler = (method, params) => {
132
+ const requestHandlerObject = handler as RPCRequestHandlerObject<Schema["requests"]>;
133
+ const specificHandler = requestHandlerObject[method];
134
+ if (specificHandler) {
135
+ return (specificHandler as (...args: [unknown]) => unknown)(params);
136
+ }
137
+ if (!requestHandlerObject._) {
138
+ throw new Error(`The requested method has no handler: ${String(method)}`);
139
+ }
140
+ return requestHandlerObject._(method, params as never);
141
+ };
142
+ }
143
+
144
+ if (options.transport) {
145
+ setTransport(options.transport);
146
+ }
147
+ if (options.requestHandler) {
148
+ setRequestHandler(options.requestHandler);
149
+ }
150
+
151
+ let lastRequestId = 0;
152
+ const maxRequestTime = options.maxRequestTime ?? DEFAULT_MAX_REQUEST_TIME;
153
+ const pendingRequests = new Map<
154
+ number,
155
+ {
156
+ resolve: (value: unknown) => void;
157
+ reject: (error: Error) => void;
158
+ timeout: ReturnType<typeof setTimeout>;
159
+ }
160
+ >();
161
+ const messageListeners = new Map<string, Set<(payload: unknown) => void>>();
162
+ const wildcardListeners = new Set<(messageName: string, payload: unknown) => void>();
163
+
164
+ function nextRequestId() {
165
+ if (lastRequestId < MAX_ID) {
166
+ lastRequestId += 1;
167
+ return lastRequestId;
168
+ }
169
+ lastRequestId = 1;
170
+ return lastRequestId;
171
+ }
172
+
173
+ function request<M extends keyof RemoteSchema["requests"]>(
174
+ method: M,
175
+ ...args: undefined extends RemoteSchema["requests"][M]["params"]
176
+ ? [params?: RemoteSchema["requests"][M]["params"]]
177
+ : [params: RemoteSchema["requests"][M]["params"]]
178
+ ): Promise<RemoteSchema["requests"][M]["response"]> {
179
+ if (!transport.send) {
180
+ throw missingTransportMethodError(["send"], "issue requests");
181
+ }
182
+
183
+ const id = nextRequestId();
184
+ const params = args[0];
185
+ const packet: RPCRequestPacket = {
186
+ type: "request",
187
+ id,
188
+ method: String(method),
189
+ params
190
+ };
191
+
192
+ return new Promise((resolve, reject) => {
193
+ const timeout = setTimeout(() => {
194
+ pendingRequests.delete(id);
195
+ reject(new Error(`Request timed out: ${String(method)}`));
196
+ }, maxRequestTime);
197
+
198
+ pendingRequests.set(id, { resolve, reject, timeout });
199
+ transport.send?.(packet);
200
+ }) as Promise<RemoteSchema["requests"][M]["response"]>;
201
+ }
202
+
203
+ function send<M extends keyof RemoteSchema["messages"]>(
204
+ messageName: M,
205
+ ...args: void extends RemoteSchema["messages"][M]
206
+ ? []
207
+ : undefined extends RemoteSchema["messages"][M]
208
+ ? [payload?: RemoteSchema["messages"][M]]
209
+ : [payload: RemoteSchema["messages"][M]]
210
+ ): void {
211
+ if (!transport.send) {
212
+ throw missingTransportMethodError(["send"], "send messages");
213
+ }
214
+
215
+ transport.send({
216
+ type: "message",
217
+ id: String(messageName),
218
+ payload: args[0]
219
+ });
220
+ }
221
+
222
+ function addMessageListener(
223
+ messageName: "*" | keyof Schema["messages"],
224
+ listener:
225
+ | ((name: string, payload: unknown) => void)
226
+ | ((payload: unknown) => void)
227
+ ) {
228
+ if (messageName === "*") {
229
+ wildcardListeners.add(listener as (name: string, payload: unknown) => void);
230
+ return;
231
+ }
232
+
233
+ const key = String(messageName);
234
+ if (!messageListeners.has(key)) {
235
+ messageListeners.set(key, new Set());
236
+ }
237
+ messageListeners.get(key)?.add(listener as (payload: unknown) => void);
238
+ }
239
+
240
+ function removeMessageListener(
241
+ messageName: "*" | keyof Schema["messages"],
242
+ listener: ((payload: unknown) => void) | ((name: string, payload: unknown) => void)
243
+ ) {
244
+ if (messageName === "*") {
245
+ wildcardListeners.delete(listener as (name: string, payload: unknown) => void);
246
+ return;
247
+ }
248
+
249
+ messageListeners.get(String(messageName))?.delete(listener as (payload: unknown) => void);
250
+ }
251
+
252
+ async function handlePacket(packet: RPCPacket) {
253
+ if (packet.type === "request") {
254
+ if (!transport.send || !requestHandler) {
255
+ throw missingTransportMethodError(["send", "requestHandler"], "handle requests");
256
+ }
257
+
258
+ try {
259
+ const payload = await requestHandler(packet.method as never, packet.params as never);
260
+ transport.send({
261
+ type: "response",
262
+ id: packet.id,
263
+ success: true,
264
+ payload
265
+ });
266
+ } catch (error) {
267
+ transport.send({
268
+ type: "response",
269
+ id: packet.id,
270
+ success: false,
271
+ error: error instanceof Error ? error.message : String(error)
272
+ });
273
+ }
274
+ return;
275
+ }
276
+
277
+ if (packet.type === "response") {
278
+ const pending = pendingRequests.get(packet.id);
279
+ if (!pending) {
280
+ return;
281
+ }
282
+
283
+ clearTimeout(pending.timeout);
284
+ pendingRequests.delete(packet.id);
285
+
286
+ if (!packet.success) {
287
+ pending.reject(new Error(packet.error ?? "Unknown RPC error"));
288
+ } else {
289
+ pending.resolve(packet.payload);
290
+ }
291
+ return;
292
+ }
293
+
294
+ if (packet.type === "message") {
295
+ for (const listener of wildcardListeners) {
296
+ listener(packet.id, packet.payload);
297
+ }
298
+ for (const listener of messageListeners.get(packet.id) ?? []) {
299
+ listener(packet.payload);
300
+ }
301
+ }
302
+ }
303
+
304
+ const requestProxy = new Proxy(
305
+ {},
306
+ {
307
+ get(_target, method) {
308
+ return (params: unknown) =>
309
+ request(method as keyof RemoteSchema["requests"], params as never);
310
+ }
311
+ }
312
+ ) as {
313
+ [M in keyof RemoteSchema["requests"]]: (
314
+ ...args: undefined extends RemoteSchema["requests"][M]["params"]
315
+ ? [params?: RemoteSchema["requests"][M]["params"]]
316
+ : [params: RemoteSchema["requests"][M]["params"]]
317
+ ) => Promise<RemoteSchema["requests"][M]["response"]>;
318
+ };
319
+
320
+ const sendProxy = new Proxy(
321
+ {},
322
+ {
323
+ get(_target, method) {
324
+ return (...args: unknown[]) =>
325
+ (send as any)(method as keyof RemoteSchema["messages"], ...args);
326
+ }
327
+ }
328
+ ) as {
329
+ [M in keyof RemoteSchema["messages"]]: (
330
+ ...args: void extends RemoteSchema["messages"][M]
331
+ ? []
332
+ : undefined extends RemoteSchema["messages"][M]
333
+ ? [payload?: RemoteSchema["messages"][M]]
334
+ : [payload: RemoteSchema["messages"][M]]
335
+ ) => void;
336
+ };
337
+
338
+ return {
339
+ setTransport,
340
+ setRequestHandler,
341
+ request,
342
+ send,
343
+ requestProxy,
344
+ sendProxy,
345
+ addMessageListener,
346
+ removeMessageListener,
347
+ proxy: {
348
+ request: requestProxy,
349
+ send: sendProxy
350
+ }
351
+ };
352
+ }
353
+
354
+ export function defineBuniteRPC<
355
+ Schema extends BuniteRPCSchema,
356
+ Side extends "bun" | "webview"
357
+ >(
358
+ side: Side,
359
+ config: BuniteRPCConfig<Schema, Side> & {
360
+ extraRequestHandlers?: Record<string, (...args: any[]) => unknown>;
361
+ }
362
+ ) {
363
+ type RemoteSide = Side extends "bun" ? "webview" : "bun";
364
+ type LocalSchema = {
365
+ requests: Schema[Side]["requests"];
366
+ messages: Schema[RemoteSide]["messages"];
367
+ };
368
+ type RemoteSchema = {
369
+ requests: Schema[RemoteSide]["requests"];
370
+ messages: Schema[Side]["messages"];
371
+ };
372
+
373
+ const rpc = createRPC<LocalSchema, RemoteSchema>({
374
+ maxRequestTime: config.maxRequestTime,
375
+ requestHandler: {
376
+ ...(config.handlers.requests ?? {}),
377
+ ...(config.extraRequestHandlers ?? {})
378
+ } as RPCRequestHandler<LocalSchema["requests"]>,
379
+ transport: {
380
+ registerHandler: () => {}
381
+ }
382
+ });
383
+
384
+ if (config.handlers.messages) {
385
+ rpc.addMessageListener("*", (messageName, payload) => {
386
+ const wildcardHandler = config.handlers.messages?.["*"];
387
+ wildcardHandler?.(messageName as never, payload as never);
388
+
389
+ const specificHandler = config.handlers.messages?.[
390
+ messageName as keyof Schema[Side]["messages"]
391
+ ];
392
+ if (specificHandler) {
393
+ (specificHandler as (payload: unknown) => void)(payload);
394
+ }
395
+ });
396
+ }
397
+
398
+ return rpc;
399
+ }
@@ -0,0 +1,54 @@
1
+ import { pack, unpack } from "msgpackr";
2
+ import type { RPCPacket } from "./rpc";
3
+ import {
4
+ RPC_AUTH_TAG_LENGTH,
5
+ RPC_FRAME_VERSION,
6
+ RPC_IV_LENGTH
7
+ } from "./rpcWireConstants";
8
+
9
+ export function encodeRPCPacket(packet: RPCPacket): Uint8Array {
10
+ return pack(packet) as Uint8Array;
11
+ }
12
+
13
+ export function decodeRPCPacket(data: Uint8Array): RPCPacket {
14
+ return unpack(data) as RPCPacket;
15
+ }
16
+
17
+ export function createEncryptedRPCFrame(
18
+ iv: Uint8Array,
19
+ encryptedPayload: Uint8Array
20
+ ): Uint8Array {
21
+ if (iv.byteLength !== RPC_IV_LENGTH) {
22
+ throw new Error(`Invalid RPC IV length: expected ${RPC_IV_LENGTH}, got ${iv.byteLength}`);
23
+ }
24
+
25
+ const frame = new Uint8Array(1 + RPC_IV_LENGTH + encryptedPayload.byteLength);
26
+ frame[0] = RPC_FRAME_VERSION;
27
+ frame.set(iv, 1);
28
+ frame.set(encryptedPayload, 1 + RPC_IV_LENGTH);
29
+ return frame;
30
+ }
31
+
32
+ export function parseEncryptedRPCFrame(frame: Uint8Array) {
33
+ if (frame.byteLength < 1 + RPC_IV_LENGTH + RPC_AUTH_TAG_LENGTH) {
34
+ throw new Error("Invalid RPC frame: payload is too short.");
35
+ }
36
+ if (frame[0] !== RPC_FRAME_VERSION) {
37
+ throw new Error(`Unsupported RPC frame version: ${frame[0]}`);
38
+ }
39
+
40
+ return {
41
+ iv: frame.subarray(1, 1 + RPC_IV_LENGTH),
42
+ encryptedPayload: frame.subarray(1 + RPC_IV_LENGTH)
43
+ };
44
+ }
45
+
46
+ export function asUint8Array(data: ArrayBuffer | ArrayBufferView | Uint8Array): Uint8Array {
47
+ if (data instanceof Uint8Array) {
48
+ return data;
49
+ }
50
+ if (ArrayBuffer.isView(data)) {
51
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
52
+ }
53
+ return new Uint8Array(data);
54
+ }
@@ -0,0 +1,3 @@
1
+ export const RPC_FRAME_VERSION = 1;
2
+ export const RPC_IV_LENGTH = 12;
3
+ export const RPC_AUTH_TAG_LENGTH = 16;
@@ -0,0 +1,29 @@
1
+ export interface BuniteConfig {
2
+ app: {
3
+ name: string;
4
+ identifier: string;
5
+ version: string;
6
+ description?: string;
7
+ };
8
+ build?: {
9
+ bun?: {
10
+ entrypoint?: string;
11
+ } & Omit<Parameters<typeof Bun.build>[0], "entrypoints" | "outdir" | "target">;
12
+ views?: Record<
13
+ string,
14
+ {
15
+ entrypoint: string;
16
+ } & Omit<Parameters<typeof Bun.build>[0], "entrypoints" | "outdir" | "target">
17
+ >;
18
+ copy?: Record<string, string>;
19
+ buildFolder?: string;
20
+ artifactFolder?: string;
21
+ targets?: string[];
22
+ cefVersion?: string;
23
+ watch?: string[];
24
+ };
25
+ runtime?: {
26
+ exitOnLastWindowClosed?: boolean;
27
+ hideConsole?: boolean;
28
+ };
29
+ }
@@ -0,0 +1,159 @@
1
+ import {
2
+ defineBuniteRPC,
3
+ type BuniteRPCConfig,
4
+ type RPCPacket,
5
+ type BuniteRPCSchema,
6
+ type RPCSchema,
7
+ type RPCTransport,
8
+ type RPCWithTransport
9
+ } from "../shared/rpc";
10
+ import { decodeRPCPacket, encodeRPCPacket } from "../shared/rpcWire";
11
+
12
+ type BuniteWindowGlobals = Window &
13
+ typeof globalThis & {
14
+ __buniteWebviewId?: number;
15
+ __buniteRpcSocketPort?: number;
16
+ __bunite?: {
17
+ receiveMessageFromBun?: (message: unknown) => void;
18
+ };
19
+ __bunite_encrypt?: (data: Uint8Array) => Promise<Uint8Array>;
20
+ __bunite_decrypt?: (data: Uint8Array) => Promise<Uint8Array>;
21
+ };
22
+
23
+ const buniteWindow = window as BuniteWindowGlobals;
24
+ const WEBVIEW_ID = buniteWindow.__buniteWebviewId;
25
+ const RPC_SOCKET_PORT = buniteWindow.__buniteRpcSocketPort;
26
+
27
+ function toArrayBuffer(bytes: Uint8Array): ArrayBuffer {
28
+ const copy = new Uint8Array(bytes.byteLength);
29
+ copy.set(bytes);
30
+ return copy.buffer;
31
+ }
32
+
33
+ export class BuniteView<T extends RPCWithTransport> {
34
+ bunSocket?: WebSocket;
35
+ rpc?: T;
36
+ rpcHandler?: (message: unknown) => void;
37
+
38
+ constructor(config: { rpc: T }) {
39
+ this.rpc = config.rpc;
40
+ this.init();
41
+ }
42
+
43
+ init() {
44
+ this.initSocketToBun();
45
+ buniteWindow.__bunite ??= {};
46
+ buniteWindow.__bunite.receiveMessageFromBun = this.receiveMessageFromBun.bind(this);
47
+ this.rpc?.setTransport(this.createTransport());
48
+ }
49
+
50
+ initSocketToBun() {
51
+ if (WEBVIEW_ID == null || RPC_SOCKET_PORT == null) {
52
+ console.warn("[bunite] Preload globals are missing. BuniteView will stay disconnected until native preload wiring is implemented.");
53
+ return;
54
+ }
55
+
56
+ // Share a single WebSocket with the preload's bunite.invoke.
57
+ // Whichever side (BuniteView or bunite.invoke) opens the socket first,
58
+ // the other reuses it via __bunite._socket.
59
+ const globals = buniteWindow as any;
60
+ globals.__bunite ??= {};
61
+ const existing = globals.__bunite._socket;
62
+ if (existing && existing.readyState <= WebSocket.OPEN) {
63
+ this.bunSocket = existing;
64
+ } else {
65
+ const socket = new WebSocket(
66
+ `ws://localhost:${RPC_SOCKET_PORT}/socket?webviewId=${WEBVIEW_ID}`
67
+ );
68
+ socket.binaryType = "arraybuffer";
69
+ this.bunSocket = socket;
70
+ globals.__bunite._socket = socket;
71
+ }
72
+
73
+ this.bunSocket!.addEventListener("message", async (event) => {
74
+ const binaryMessage = await this.messageToUint8Array(event.data);
75
+ if (!binaryMessage) {
76
+ return;
77
+ }
78
+
79
+ try {
80
+ const decrypt = buniteWindow.__bunite_decrypt;
81
+ if (!decrypt) {
82
+ console.error("[bunite] No decrypt function available in preload globals");
83
+ return;
84
+ }
85
+ const decrypted = await decrypt(binaryMessage);
86
+ const packet = decodeRPCPacket(decrypted);
87
+ // Skip global IPC responses — those are handled by bunite.invoke in the preload
88
+ if ((packet as any).scope === "global") {
89
+ return;
90
+ }
91
+ this.rpcHandler?.(packet);
92
+ } catch (error) {
93
+ console.error("[bunite] Failed to parse message from Bun", error);
94
+ }
95
+ });
96
+ }
97
+
98
+ async messageToUint8Array(data: unknown) {
99
+ if (data instanceof ArrayBuffer) {
100
+ return new Uint8Array(data);
101
+ }
102
+ if (data instanceof Blob) {
103
+ return new Uint8Array(await data.arrayBuffer());
104
+ }
105
+ if (data instanceof Uint8Array) {
106
+ return data;
107
+ }
108
+ return null;
109
+ }
110
+
111
+ createTransport(): RPCTransport {
112
+ return {
113
+ send: (message) => {
114
+ if (this.bunSocket?.readyState === WebSocket.OPEN) {
115
+ void this.bunBridge(message).catch((error) => {
116
+ console.error("[bunite] Failed to send RPC packet", error);
117
+ });
118
+ }
119
+ },
120
+ registerHandler: (handler: (packet: any) => void) => {
121
+ this.rpcHandler = handler;
122
+ },
123
+ unregisterHandler: () => {
124
+ this.rpcHandler = undefined;
125
+ }
126
+ };
127
+ }
128
+
129
+ receiveMessageFromBun(message: unknown) {
130
+ this.rpcHandler?.(message);
131
+ }
132
+
133
+ async bunBridge(message: RPCPacket) {
134
+ if (this.bunSocket?.readyState !== WebSocket.OPEN) {
135
+ return;
136
+ }
137
+
138
+ const encrypt = buniteWindow.__bunite_encrypt;
139
+ if (!encrypt) {
140
+ console.error("[bunite] No encrypt function available in preload globals");
141
+ return;
142
+ }
143
+
144
+ const encrypted = await encrypt(encodeRPCPacket(message));
145
+ this.bunSocket.send(toArrayBuffer(encrypted));
146
+ }
147
+
148
+ static defineRPC<Schema extends BuniteRPCSchema>(
149
+ config: BuniteRPCConfig<Schema, "webview">
150
+ ) {
151
+ return defineBuniteRPC("webview", config);
152
+ }
153
+ }
154
+
155
+ export type {
156
+ BuniteRPCConfig,
157
+ BuniteRPCSchema,
158
+ RPCSchema
159
+ };