sparkbun 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/bin/sparkbun.cjs +18 -0
- package/dist-linux-arm64/bsdiff +0 -0
- package/dist-linux-arm64/bspatch +0 -0
- package/dist-linux-arm64/libElectrobunCore.so +0 -0
- package/dist-linux-arm64/libNativeWrapper.so +0 -0
- package/dist-linux-arm64/libasar.so +0 -0
- package/dist-linux-x64/bsdiff +0 -0
- package/dist-linux-x64/bspatch +0 -0
- package/dist-linux-x64/libElectrobunCore.so +0 -0
- package/dist-linux-x64/libNativeWrapper.so +0 -0
- package/dist-linux-x64/libasar.so +0 -0
- package/dist-macos-arm64/bsdiff +0 -0
- package/dist-macos-arm64/bspatch +0 -0
- package/dist-macos-arm64/libElectrobunCore.dylib +0 -0
- package/dist-macos-arm64/libNativeWrapper.dylib +0 -0
- package/dist-macos-arm64/libasar.dylib +0 -0
- package/dist-macos-arm64/libwebgpu_dawn.dylib +0 -0
- package/dist-macos-arm64/preload-full.js +885 -0
- package/dist-macos-arm64/preload-sandboxed.js +111 -0
- package/dist-macos-arm64/process_helper +0 -0
- package/dist-win-x64/ElectrobunCore.dll +0 -0
- package/dist-win-x64/WebView2Loader.dll +0 -0
- package/dist-win-x64/bsdiff.exe +0 -0
- package/dist-win-x64/bspatch.exe +0 -0
- package/dist-win-x64/libNativeWrapper.dll +0 -0
- package/dist-win-x64/zig-asar/arm64/libasar.dll +0 -0
- package/dist-win-x64/zig-asar/x64/libasar.dll +0 -0
- package/package.json +47 -0
- package/scripts/build-and-upload-artifacts.js +207 -0
- package/scripts/gen-webgpu-ffi.mjs +162 -0
- package/scripts/install-windows-deps.ps1 +80 -0
- package/scripts/package-release.js +237 -0
- package/scripts/push-version.js +84 -0
- package/scripts/update-bun-version.ts +122 -0
- package/scripts/update-cef-version.ts +145 -0
- package/src/browser/builtinrpcSchema.ts +19 -0
- package/src/browser/global.d.ts +36 -0
- package/src/browser/index.ts +234 -0
- package/src/browser/webviewtag.ts +88 -0
- package/src/browser/wgputag.ts +48 -0
- package/src/bun/SparkBunConfig.ts +497 -0
- package/src/bun/__tests__/ffi-contract.test.ts +105 -0
- package/src/bun/core/ApplicationMenu.ts +70 -0
- package/src/bun/core/BrowserView.ts +416 -0
- package/src/bun/core/BrowserWindow.ts +396 -0
- package/src/bun/core/BuildConfig.ts +71 -0
- package/src/bun/core/ContextMenu.ts +75 -0
- package/src/bun/core/GpuWindow.ts +289 -0
- package/src/bun/core/Paths.ts +5 -0
- package/src/bun/core/Socket.ts +22 -0
- package/src/bun/core/Tray.ts +197 -0
- package/src/bun/core/Updater.ts +1131 -0
- package/src/bun/core/Utils.ts +487 -0
- package/src/bun/core/WGPUView.ts +167 -0
- package/src/bun/core/menuRoles.ts +181 -0
- package/src/bun/events/ApplicationEvents.ts +22 -0
- package/src/bun/events/event.ts +27 -0
- package/src/bun/events/eventEmitter.ts +45 -0
- package/src/bun/events/trayEvents.ts +11 -0
- package/src/bun/events/webviewEvents.ts +39 -0
- package/src/bun/events/windowEvents.ts +23 -0
- package/src/bun/index.ts +120 -0
- package/src/bun/preload/.generated/compiled.ts +2 -0
- package/src/bun/preload/build.ts +65 -0
- package/src/bun/preload/dragRegions.ts +41 -0
- package/src/bun/preload/encryption.ts +86 -0
- package/src/bun/preload/events.ts +171 -0
- package/src/bun/preload/globals.d.ts +45 -0
- package/src/bun/preload/index-sandboxed.ts +28 -0
- package/src/bun/preload/index.ts +77 -0
- package/src/bun/preload/internalRpc.ts +80 -0
- package/src/bun/preload/overlaySync.ts +107 -0
- package/src/bun/preload/webviewTag.ts +451 -0
- package/src/bun/preload/wgpuTag.ts +246 -0
- package/src/bun/proc/linux.md +43 -0
- package/src/bun/proc/native.ts +3253 -0
- package/src/bun/webGPU.ts +346 -0
- package/src/bun/webgpuAdapter.ts +3011 -0
- package/src/cli/bun.lockb +0 -0
- package/src/cli/index.ts +4653 -0
- package/src/cli/package-lock.json +81 -0
- package/src/cli/package.json +11 -0
- package/src/cli/templates/embedded.ts +2 -0
- package/src/core/build.zig +16 -0
- package/src/core/main.zig +3378 -0
- package/src/extractor/build.zig +22 -0
- package/src/installer/installer-template.ts +216 -0
- package/src/launcher/main.ts +221 -0
- package/src/native/build/libNativeWrapper.so +0 -0
- package/src/native/linux/build/nativeWrapper.o +0 -0
- package/src/native/linux/cef_loader.cpp +110 -0
- package/src/native/linux/cef_loader.h +28 -0
- package/src/native/linux/cef_process_helper_linux.cpp +160 -0
- package/src/native/linux/nativeWrapper.cpp +11768 -0
- package/src/native/macos/cef_process_helper_mac.cc +160 -0
- package/src/native/macos/nativeWrapper.mm +9172 -0
- package/src/native/shared/accelerator_parser.h +72 -0
- package/src/native/shared/app_paths.h +110 -0
- package/src/native/shared/asar.h +35 -0
- package/src/native/shared/cache_migration.h +244 -0
- package/src/native/shared/callbacks.h +57 -0
- package/src/native/shared/cef_response_filter.h +189 -0
- package/src/native/shared/chromium_flags.h +181 -0
- package/src/native/shared/config.h +66 -0
- package/src/native/shared/download_event.h +197 -0
- package/src/native/shared/ffi_helpers.h +139 -0
- package/src/native/shared/glob_match.h +59 -0
- package/src/native/shared/json_menu_parser.h +223 -0
- package/src/native/shared/mime_types.h +101 -0
- package/src/native/shared/navigation_rules.h +98 -0
- package/src/native/shared/partition_context.h +137 -0
- package/src/native/shared/pending_resize_queue.h +45 -0
- package/src/native/shared/permissions.h +118 -0
- package/src/native/shared/permissions_cef.h +74 -0
- package/src/native/shared/preload_script.h +71 -0
- package/src/native/shared/shutdown_guard.h +134 -0
- package/src/native/shared/thread_safe_map.h +138 -0
- package/src/native/shared/webview_storage.h +91 -0
- package/src/native/win/cef_process_helper_win.cpp +143 -0
- package/src/native/win/dcomp_compositor.h +352 -0
- package/src/native/win/nativeWrapper.cpp +12434 -0
- package/src/npmbin/index.js +34 -0
- package/src/shared/bun-version.ts +3 -0
- package/src/shared/cef-version.ts +5 -0
- package/src/shared/naming.test.ts +327 -0
- package/src/shared/naming.ts +188 -0
- package/src/shared/platform.ts +48 -0
- package/src/shared/rpc.ts +541 -0
- package/src/shared/sparkbun-version.ts +2 -0
- package/src/types/three.d.ts +1 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
// ---- Wire protocol packets ----
|
|
2
|
+
|
|
3
|
+
type _RPCRequestPacket = {
|
|
4
|
+
type: "request";
|
|
5
|
+
id: number;
|
|
6
|
+
method: string;
|
|
7
|
+
params: any;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type _RPCResponsePacket =
|
|
11
|
+
| { type: "response"; id: number; success: true; payload: any }
|
|
12
|
+
| { type: "response"; id: number; success: false; error?: string };
|
|
13
|
+
|
|
14
|
+
type _RPCMessagePacket = {
|
|
15
|
+
type: "message";
|
|
16
|
+
id: string;
|
|
17
|
+
payload: any;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type _RPCPacket = _RPCRequestPacket | _RPCResponsePacket | _RPCMessagePacket;
|
|
21
|
+
|
|
22
|
+
// ---- Schema primitives ----
|
|
23
|
+
|
|
24
|
+
type BaseRPCRequestsSchema = {
|
|
25
|
+
[key: string]: { params: unknown; response: unknown };
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type RPCRequestsSchema<
|
|
29
|
+
T extends BaseRPCRequestsSchema = BaseRPCRequestsSchema,
|
|
30
|
+
> = T;
|
|
31
|
+
|
|
32
|
+
type RPCRequestParams<
|
|
33
|
+
RS extends RPCRequestsSchema,
|
|
34
|
+
M extends keyof RS = keyof RS,
|
|
35
|
+
> = "params" extends keyof RS[M] ? RS[M]["params"] : never;
|
|
36
|
+
|
|
37
|
+
type RPCRequestResponse<
|
|
38
|
+
RS extends RPCRequestsSchema,
|
|
39
|
+
M extends keyof RS = keyof RS,
|
|
40
|
+
> = "response" extends keyof RS[M] ? RS[M]["response"] : void;
|
|
41
|
+
|
|
42
|
+
type BaseRPCMessagesSchema = Record<never, unknown>;
|
|
43
|
+
|
|
44
|
+
export type RPCMessagesSchema<
|
|
45
|
+
T extends BaseRPCMessagesSchema = BaseRPCMessagesSchema,
|
|
46
|
+
> = T;
|
|
47
|
+
|
|
48
|
+
type RPCMessagePayload<
|
|
49
|
+
MS extends RPCMessagesSchema,
|
|
50
|
+
N extends keyof MS = keyof MS,
|
|
51
|
+
> = MS[N];
|
|
52
|
+
|
|
53
|
+
// ---- Composite schema ----
|
|
54
|
+
|
|
55
|
+
type InputRPCSchema = {
|
|
56
|
+
requests?: RPCRequestsSchema;
|
|
57
|
+
messages?: RPCMessagesSchema;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
type ResolvedRPCSchema<I extends InputRPCSchema> = {
|
|
61
|
+
requests: undefined extends I["requests"]
|
|
62
|
+
? BaseRPCRequestsSchema
|
|
63
|
+
: NonNullable<I["requests"]>;
|
|
64
|
+
messages: undefined extends I["messages"]
|
|
65
|
+
? BaseRPCMessagesSchema
|
|
66
|
+
: NonNullable<I["messages"]>;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export type RPCSchema<
|
|
70
|
+
I extends InputRPCSchema | void = InputRPCSchema,
|
|
71
|
+
> = ResolvedRPCSchema<I extends InputRPCSchema ? I : InputRPCSchema>;
|
|
72
|
+
|
|
73
|
+
// ---- Handler types ----
|
|
74
|
+
|
|
75
|
+
type RPCRequestHandlerFn<RS extends RPCRequestsSchema = RPCRequestsSchema> = <
|
|
76
|
+
M extends keyof RS,
|
|
77
|
+
>(
|
|
78
|
+
method: M,
|
|
79
|
+
params: RPCRequestParams<RS, M>,
|
|
80
|
+
) => any | Promise<any>;
|
|
81
|
+
|
|
82
|
+
type RPCRequestHandlerObject<
|
|
83
|
+
RS extends RPCRequestsSchema = RPCRequestsSchema,
|
|
84
|
+
> = {
|
|
85
|
+
[M in keyof RS]?: (
|
|
86
|
+
...args: "params" extends keyof RS[M]
|
|
87
|
+
? undefined extends RS[M]["params"]
|
|
88
|
+
? [params?: RS[M]["params"]]
|
|
89
|
+
: [params: RS[M]["params"]]
|
|
90
|
+
: []
|
|
91
|
+
) =>
|
|
92
|
+
| Awaited<RPCRequestResponse<RS, M>>
|
|
93
|
+
| Promise<Awaited<RPCRequestResponse<RS, M>>>;
|
|
94
|
+
} & {
|
|
95
|
+
_?: (method: keyof RS, params: RPCRequestParams<RS>) => any;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export type RPCRequestHandler<
|
|
99
|
+
RS extends RPCRequestsSchema = RPCRequestsSchema,
|
|
100
|
+
> = RPCRequestHandlerFn<RS> | RPCRequestHandlerObject<RS>;
|
|
101
|
+
|
|
102
|
+
export type RPCMessageHandlerFn<
|
|
103
|
+
MS extends RPCMessagesSchema,
|
|
104
|
+
N extends keyof MS,
|
|
105
|
+
> = (payload: RPCMessagePayload<MS, N>) => void;
|
|
106
|
+
|
|
107
|
+
export type WildcardRPCMessageHandlerFn<MS extends RPCMessagesSchema> = (
|
|
108
|
+
messageName: keyof MS,
|
|
109
|
+
payload: RPCMessagePayload<MS>,
|
|
110
|
+
) => void;
|
|
111
|
+
|
|
112
|
+
// ---- Proxy types ----
|
|
113
|
+
|
|
114
|
+
type RPCRequestsProxy<RS extends RPCRequestsSchema> = {
|
|
115
|
+
[K in keyof RS]: (
|
|
116
|
+
...args: "params" extends keyof RS[K]
|
|
117
|
+
? undefined extends RS[K]["params"]
|
|
118
|
+
? [params?: RS[K]["params"]]
|
|
119
|
+
: [params: RS[K]["params"]]
|
|
120
|
+
: []
|
|
121
|
+
) => Promise<RPCRequestResponse<RS, K>>;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
type RPCMessagesProxy<MS extends RPCMessagesSchema> = {
|
|
125
|
+
[K in keyof MS]-?: (
|
|
126
|
+
...args: void extends MS[K]
|
|
127
|
+
? []
|
|
128
|
+
: undefined extends MS[K]
|
|
129
|
+
? [payload?: MS[K]]
|
|
130
|
+
: [payload: MS[K]]
|
|
131
|
+
) => void;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// ---- Transport ----
|
|
135
|
+
|
|
136
|
+
type RPCTransportHandler = (data: any) => void;
|
|
137
|
+
|
|
138
|
+
export type RPCTransport = {
|
|
139
|
+
send?: (data: any) => void;
|
|
140
|
+
registerHandler?: (handler: RPCTransportHandler) => void;
|
|
141
|
+
unregisterHandler?: () => void;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// ---- Options ----
|
|
145
|
+
|
|
146
|
+
type DebugHooks = {
|
|
147
|
+
onSend?: (packet: _RPCPacket) => void;
|
|
148
|
+
onReceive?: (packet: _RPCPacket) => void;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
type _RPCAllOptions<S extends RPCSchema> = {
|
|
152
|
+
transport?: RPCTransport;
|
|
153
|
+
requestHandler?: RPCRequestHandler<S["requests"]>;
|
|
154
|
+
maxRequestTime?: number;
|
|
155
|
+
_debugHooks?: DebugHooks;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
type RPCBaseOption = "transport" | "_debugHooks";
|
|
159
|
+
type RPCRequestsInOption = "requestHandler";
|
|
160
|
+
type RPCRequestsOutOption = "maxRequestTime";
|
|
161
|
+
|
|
162
|
+
type OptionsByLocalSchema<S extends RPCSchema> =
|
|
163
|
+
NonNullable<unknown> extends S["requests"] ? never : RPCRequestsInOption;
|
|
164
|
+
type OptionsByRemoteSchema<RS extends RPCSchema> =
|
|
165
|
+
NonNullable<unknown> extends RS["requests"] ? never : RPCRequestsOutOption;
|
|
166
|
+
|
|
167
|
+
export type RPCOptions<
|
|
168
|
+
S extends RPCSchema,
|
|
169
|
+
RS extends RPCSchema,
|
|
170
|
+
> = Pick<
|
|
171
|
+
_RPCAllOptions<S>,
|
|
172
|
+
RPCBaseOption | OptionsByLocalSchema<S> | OptionsByRemoteSchema<RS>
|
|
173
|
+
>;
|
|
174
|
+
|
|
175
|
+
// ---- createRPC ----
|
|
176
|
+
|
|
177
|
+
const MAX_ID = 1e10;
|
|
178
|
+
const DEFAULT_MAX_REQUEST_TIME = 1000;
|
|
179
|
+
|
|
180
|
+
function missingTransportMethodError(
|
|
181
|
+
methods: string[],
|
|
182
|
+
action: string,
|
|
183
|
+
): Error {
|
|
184
|
+
const methodsString = methods.map((m) => `"${m}"`).join(", ");
|
|
185
|
+
return new Error(
|
|
186
|
+
`This RPC instance cannot ${action} because the transport did not provide one or more of these methods: ${methodsString}`,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function createRPC<
|
|
191
|
+
Schema extends RPCSchema = RPCSchema,
|
|
192
|
+
RemoteSchema extends RPCSchema = Schema,
|
|
193
|
+
>(options: _RPCAllOptions<Schema> = {}) {
|
|
194
|
+
// ---- transport ----
|
|
195
|
+
|
|
196
|
+
let debugHooks: DebugHooks = {};
|
|
197
|
+
let transport: RPCTransport = {};
|
|
198
|
+
let requestHandler:
|
|
199
|
+
| RPCRequestHandlerFn<Schema["requests"]>
|
|
200
|
+
| undefined = undefined;
|
|
201
|
+
|
|
202
|
+
function setTransport(newTransport: RPCTransport) {
|
|
203
|
+
if (transport.unregisterHandler) transport.unregisterHandler();
|
|
204
|
+
transport = newTransport;
|
|
205
|
+
transport.registerHandler?.(handler);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function setRequestHandler(
|
|
209
|
+
h: RPCRequestHandler<Schema["requests"]>,
|
|
210
|
+
) {
|
|
211
|
+
if (typeof h === "function") {
|
|
212
|
+
requestHandler = h as RPCRequestHandlerFn<Schema["requests"]>;
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
requestHandler = (method, params) => {
|
|
216
|
+
const handlerFn = (h as RPCRequestHandlerObject<Schema["requests"]>)[
|
|
217
|
+
method
|
|
218
|
+
];
|
|
219
|
+
if (handlerFn) return (handlerFn as any)(params);
|
|
220
|
+
const fallbackHandler = (
|
|
221
|
+
h as RPCRequestHandlerObject<Schema["requests"]>
|
|
222
|
+
)._;
|
|
223
|
+
if (!fallbackHandler)
|
|
224
|
+
throw new Error(`The requested method has no handler: ${String(method)}`);
|
|
225
|
+
return fallbackHandler(method, params as any);
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ---- apply options ----
|
|
230
|
+
|
|
231
|
+
const { maxRequestTime = DEFAULT_MAX_REQUEST_TIME } = options;
|
|
232
|
+
if (options.transport) setTransport(options.transport);
|
|
233
|
+
if (options.requestHandler) setRequestHandler(options.requestHandler);
|
|
234
|
+
if (options._debugHooks) debugHooks = options._debugHooks;
|
|
235
|
+
|
|
236
|
+
// ---- outgoing requests ----
|
|
237
|
+
|
|
238
|
+
let lastRequestId = 0;
|
|
239
|
+
function getRequestId() {
|
|
240
|
+
if (lastRequestId <= MAX_ID) return ++lastRequestId;
|
|
241
|
+
return (lastRequestId = 0);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const requestListeners = new Map<
|
|
245
|
+
number,
|
|
246
|
+
{ resolve: (v: any) => void; reject: (e: Error) => void }
|
|
247
|
+
>();
|
|
248
|
+
const requestTimeouts = new Map<number, ReturnType<typeof setTimeout>>();
|
|
249
|
+
|
|
250
|
+
function requestFn<M extends keyof RemoteSchema["requests"]>(
|
|
251
|
+
method: M,
|
|
252
|
+
...args: "params" extends keyof RemoteSchema["requests"][M]
|
|
253
|
+
? undefined extends RemoteSchema["requests"][M]["params"]
|
|
254
|
+
? [params?: RemoteSchema["requests"][M]["params"]]
|
|
255
|
+
: [params: RemoteSchema["requests"][M]["params"]]
|
|
256
|
+
: []
|
|
257
|
+
): Promise<RPCRequestResponse<RemoteSchema["requests"], M>> {
|
|
258
|
+
const params = args[0];
|
|
259
|
+
return new Promise((resolve, reject) => {
|
|
260
|
+
if (!transport.send)
|
|
261
|
+
throw missingTransportMethodError(["send"], "make requests");
|
|
262
|
+
const requestId = getRequestId();
|
|
263
|
+
const request: _RPCRequestPacket = {
|
|
264
|
+
type: "request",
|
|
265
|
+
id: requestId,
|
|
266
|
+
method: method as string,
|
|
267
|
+
params,
|
|
268
|
+
};
|
|
269
|
+
requestListeners.set(requestId, { resolve, reject });
|
|
270
|
+
if (maxRequestTime !== Infinity)
|
|
271
|
+
requestTimeouts.set(
|
|
272
|
+
requestId,
|
|
273
|
+
setTimeout(() => {
|
|
274
|
+
requestTimeouts.delete(requestId);
|
|
275
|
+
requestListeners.delete(requestId);
|
|
276
|
+
reject(new Error("RPC request timed out."));
|
|
277
|
+
}, maxRequestTime),
|
|
278
|
+
);
|
|
279
|
+
debugHooks.onSend?.(request);
|
|
280
|
+
transport.send(request);
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const request = new Proxy(requestFn, {
|
|
285
|
+
get: (target, prop, receiver) => {
|
|
286
|
+
if (prop in target) return Reflect.get(target, prop, receiver);
|
|
287
|
+
return (params: any) => (requestFn as any)(prop, params);
|
|
288
|
+
},
|
|
289
|
+
}) as typeof requestFn & RPCRequestsProxy<RemoteSchema["requests"]>;
|
|
290
|
+
|
|
291
|
+
const requestProxy =
|
|
292
|
+
request as unknown as RPCRequestsProxy<RemoteSchema["requests"]>;
|
|
293
|
+
|
|
294
|
+
// ---- outgoing messages ----
|
|
295
|
+
|
|
296
|
+
function sendFn<M extends keyof Schema["messages"]>(
|
|
297
|
+
message: M,
|
|
298
|
+
...args: void extends RPCMessagePayload<Schema["messages"], M>
|
|
299
|
+
? []
|
|
300
|
+
: undefined extends RPCMessagePayload<Schema["messages"], M>
|
|
301
|
+
? [payload?: RPCMessagePayload<Schema["messages"], M>]
|
|
302
|
+
: [payload: RPCMessagePayload<Schema["messages"], M>]
|
|
303
|
+
) {
|
|
304
|
+
const payload = args[0];
|
|
305
|
+
if (!transport.send)
|
|
306
|
+
throw missingTransportMethodError(["send"], "send messages");
|
|
307
|
+
const rpcMessage: _RPCMessagePacket = {
|
|
308
|
+
type: "message",
|
|
309
|
+
id: message as string,
|
|
310
|
+
payload,
|
|
311
|
+
};
|
|
312
|
+
debugHooks.onSend?.(rpcMessage);
|
|
313
|
+
transport.send(rpcMessage);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const send = new Proxy(sendFn, {
|
|
317
|
+
get: (target, prop, receiver) => {
|
|
318
|
+
if (prop in target) return Reflect.get(target, prop, receiver);
|
|
319
|
+
return (payload: any) => (sendFn as any)(prop, payload);
|
|
320
|
+
},
|
|
321
|
+
}) as typeof sendFn & RPCMessagesProxy<Schema["messages"]>;
|
|
322
|
+
|
|
323
|
+
const sendProxy =
|
|
324
|
+
send as unknown as RPCMessagesProxy<Schema["messages"]>;
|
|
325
|
+
|
|
326
|
+
// ---- incoming message listeners ----
|
|
327
|
+
|
|
328
|
+
const messageListeners = new Map<string | symbol, Set<Function>>();
|
|
329
|
+
const wildcardMessageListeners = new Set<Function>();
|
|
330
|
+
|
|
331
|
+
function addMessageListener(
|
|
332
|
+
message: "*",
|
|
333
|
+
listener: WildcardRPCMessageHandlerFn<RemoteSchema["messages"]>,
|
|
334
|
+
): void;
|
|
335
|
+
function addMessageListener<
|
|
336
|
+
M extends keyof RemoteSchema["messages"],
|
|
337
|
+
>(
|
|
338
|
+
message: M,
|
|
339
|
+
listener: RPCMessageHandlerFn<RemoteSchema["messages"], M>,
|
|
340
|
+
): void;
|
|
341
|
+
function addMessageListener(message: any, listener: any) {
|
|
342
|
+
if (!transport.registerHandler)
|
|
343
|
+
throw missingTransportMethodError(
|
|
344
|
+
["registerHandler"],
|
|
345
|
+
"register message listeners",
|
|
346
|
+
);
|
|
347
|
+
if (message === "*") {
|
|
348
|
+
wildcardMessageListeners.add(listener);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (!messageListeners.has(message))
|
|
352
|
+
messageListeners.set(message, new Set());
|
|
353
|
+
messageListeners.get(message)!.add(listener);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function removeMessageListener(
|
|
357
|
+
message: "*",
|
|
358
|
+
listener: WildcardRPCMessageHandlerFn<RemoteSchema["messages"]>,
|
|
359
|
+
): void;
|
|
360
|
+
function removeMessageListener<
|
|
361
|
+
M extends keyof RemoteSchema["messages"],
|
|
362
|
+
>(
|
|
363
|
+
message: M,
|
|
364
|
+
listener: RPCMessageHandlerFn<RemoteSchema["messages"], M>,
|
|
365
|
+
): void;
|
|
366
|
+
function removeMessageListener(message: any, listener: any) {
|
|
367
|
+
if (message === "*") {
|
|
368
|
+
wildcardMessageListeners.delete(listener);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
messageListeners.get(message)?.delete(listener);
|
|
372
|
+
if (messageListeners.get(message)?.size === 0)
|
|
373
|
+
messageListeners.delete(message);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// ---- incoming packet handler ----
|
|
377
|
+
|
|
378
|
+
async function handler(message: _RPCPacket) {
|
|
379
|
+
debugHooks.onReceive?.(message);
|
|
380
|
+
if (!("type" in message))
|
|
381
|
+
throw new Error("Message does not contain a type.");
|
|
382
|
+
|
|
383
|
+
if (message.type === "request") {
|
|
384
|
+
if (!transport.send || !requestHandler)
|
|
385
|
+
throw missingTransportMethodError(
|
|
386
|
+
["send", "requestHandler"],
|
|
387
|
+
"handle requests",
|
|
388
|
+
);
|
|
389
|
+
const { id, method, params } = message;
|
|
390
|
+
let response: _RPCResponsePacket;
|
|
391
|
+
try {
|
|
392
|
+
response = {
|
|
393
|
+
type: "response",
|
|
394
|
+
id,
|
|
395
|
+
success: true,
|
|
396
|
+
payload: await requestHandler(method as any, params),
|
|
397
|
+
};
|
|
398
|
+
} catch (error) {
|
|
399
|
+
if (!(error instanceof Error)) throw error;
|
|
400
|
+
response = {
|
|
401
|
+
type: "response",
|
|
402
|
+
id,
|
|
403
|
+
success: false,
|
|
404
|
+
error: error.message,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
debugHooks.onSend?.(response);
|
|
408
|
+
transport.send(response);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (message.type === "response") {
|
|
413
|
+
const timeout = requestTimeouts.get(message.id);
|
|
414
|
+
if (timeout != null) clearTimeout(timeout);
|
|
415
|
+
requestTimeouts.delete(message.id);
|
|
416
|
+
const { resolve, reject } =
|
|
417
|
+
requestListeners.get(message.id) ?? {};
|
|
418
|
+
requestListeners.delete(message.id);
|
|
419
|
+
if (!message.success) reject?.(new Error(message.error));
|
|
420
|
+
else resolve?.(message.payload);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (message.type === "message") {
|
|
425
|
+
for (const listener of wildcardMessageListeners)
|
|
426
|
+
(listener as any)(message.id, message.payload);
|
|
427
|
+
const listeners = messageListeners.get(message.id);
|
|
428
|
+
if (!listeners) return;
|
|
429
|
+
for (const listener of listeners) (listener as any)(message.payload);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
throw new Error(
|
|
434
|
+
`Unexpected RPC message type: ${(message as any).type}`,
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const proxy = { send: sendProxy, request: requestProxy };
|
|
439
|
+
|
|
440
|
+
return {
|
|
441
|
+
setTransport,
|
|
442
|
+
setRequestHandler,
|
|
443
|
+
request,
|
|
444
|
+
requestProxy,
|
|
445
|
+
send,
|
|
446
|
+
sendProxy,
|
|
447
|
+
addMessageListener,
|
|
448
|
+
removeMessageListener,
|
|
449
|
+
proxy,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// ---- SparkBun combined schema ----
|
|
454
|
+
|
|
455
|
+
export interface SparkBunRPCSchema {
|
|
456
|
+
bun: RPCSchema;
|
|
457
|
+
webview: RPCSchema;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
export interface RPCWithTransport {
|
|
461
|
+
setTransport: (transport: RPCTransport) => void;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
export type SparkBunRPCConfig<
|
|
465
|
+
Schema extends SparkBunRPCSchema,
|
|
466
|
+
Side extends "bun" | "webview",
|
|
467
|
+
> = {
|
|
468
|
+
maxRequestTime?: number;
|
|
469
|
+
handlers: {
|
|
470
|
+
requests?: RPCRequestHandler<Schema[Side]["requests"]>;
|
|
471
|
+
messages?: {
|
|
472
|
+
[K in keyof Schema[Side]["messages"]]?: RPCMessageHandlerFn<
|
|
473
|
+
Schema[Side]["messages"],
|
|
474
|
+
K
|
|
475
|
+
>;
|
|
476
|
+
} & {
|
|
477
|
+
"*"?: WildcardRPCMessageHandlerFn<Schema[Side]["messages"]>;
|
|
478
|
+
};
|
|
479
|
+
};
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
// ---- defineSparkBunRPC ----
|
|
483
|
+
|
|
484
|
+
export function defineSparkBunRPC<
|
|
485
|
+
Schema extends SparkBunRPCSchema,
|
|
486
|
+
Side extends "bun" | "webview" = "bun" | "webview",
|
|
487
|
+
>(
|
|
488
|
+
_side: Side,
|
|
489
|
+
config: SparkBunRPCConfig<Schema, Side> & {
|
|
490
|
+
extraRequestHandlers?: Record<string, Function>;
|
|
491
|
+
},
|
|
492
|
+
) {
|
|
493
|
+
// Determine the other side for outgoing calls
|
|
494
|
+
type OtherSide = Side extends "bun" ? "webview" : "bun";
|
|
495
|
+
|
|
496
|
+
// Local schema = what this side handles (incoming requests) + what the other side handles (outgoing messages)
|
|
497
|
+
type LocalSchema = {
|
|
498
|
+
requests: Schema[Side]["requests"];
|
|
499
|
+
messages: Schema[OtherSide]["messages"];
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
// Remote schema = what the other side handles (outgoing requests) + what this side handles (incoming messages)
|
|
503
|
+
type RemoteSchema = {
|
|
504
|
+
requests: Schema[OtherSide]["requests"];
|
|
505
|
+
messages: Schema[Side]["messages"];
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
const rpcOptions = {
|
|
509
|
+
maxRequestTime: config.maxRequestTime,
|
|
510
|
+
requestHandler: {
|
|
511
|
+
...config.handlers.requests,
|
|
512
|
+
...config.extraRequestHandlers,
|
|
513
|
+
},
|
|
514
|
+
transport: {
|
|
515
|
+
// Provide a stub so addMessageListener doesn't throw before real transport is set
|
|
516
|
+
registerHandler: () => {},
|
|
517
|
+
},
|
|
518
|
+
} as _RPCAllOptions<LocalSchema>;
|
|
519
|
+
|
|
520
|
+
const rpc = createRPC<LocalSchema, RemoteSchema>(rpcOptions);
|
|
521
|
+
|
|
522
|
+
const messageHandlers = config.handlers.messages;
|
|
523
|
+
if (messageHandlers) {
|
|
524
|
+
rpc.addMessageListener(
|
|
525
|
+
"*" as any,
|
|
526
|
+
((messageName: keyof Schema[Side]["messages"], payload: any) => {
|
|
527
|
+
const globalHandler = (messageHandlers as any)["*"];
|
|
528
|
+
if (globalHandler) {
|
|
529
|
+
globalHandler(messageName, payload);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const messageHandler = (messageHandlers as any)[messageName];
|
|
533
|
+
if (messageHandler) {
|
|
534
|
+
messageHandler(payload);
|
|
535
|
+
}
|
|
536
|
+
}) as any,
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return rpc;
|
|
541
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
declare module "three";
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Enable latest features
|
|
4
|
+
"lib": ["ESNext", "DOM"],
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
|
|
12
|
+
// Bundler mode
|
|
13
|
+
"moduleResolution": "bundler",
|
|
14
|
+
"allowImportingTsExtensions": true,
|
|
15
|
+
"verbatimModuleSyntax": true,
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
|
|
18
|
+
// Best practices
|
|
19
|
+
"strict": true,
|
|
20
|
+
"skipLibCheck": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true,
|
|
22
|
+
|
|
23
|
+
// Some stricter flags
|
|
24
|
+
"noUnusedLocals": true,
|
|
25
|
+
"noUnusedParameters": true,
|
|
26
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
27
|
+
"noUncheckedIndexedAccess": true
|
|
28
|
+
},
|
|
29
|
+
"include": ["src/**/*"],
|
|
30
|
+
"exclude": ["node_modules", "dist", "vendors", "build", "src/tests"]
|
|
31
|
+
}
|