@vitejs/devtools-rpc 0.0.0-alpha.8 → 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/README.md +214 -0
- package/dist/client.d.mts +9 -0
- package/dist/client.mjs +13 -0
- package/dist/index.d.mts +257 -0
- package/dist/index.mjs +314 -0
- package/dist/{index-SwSDJlvS.d.ts → presets/index.d.mts} +2 -2
- package/dist/{presets-CHvTKHNF.js → presets/index.mjs} +1 -2
- package/dist/presets/ws/client.d.mts +14 -0
- package/dist/presets/ws/{client.js → client.mjs} +5 -5
- package/dist/presets/ws/server.d.mts +24 -0
- package/dist/presets/ws/server.mjs +52 -0
- package/dist/server.d.mts +9 -0
- package/dist/server.mjs +12 -0
- package/package.json +19 -13
- package/dist/index.d.ts +0 -15
- package/dist/index.js +0 -22
- package/dist/presets/index.d.ts +0 -2
- package/dist/presets/index.js +0 -3
- package/dist/presets/ws/client.d.ts +0 -17
- package/dist/presets/ws/server.d.ts +0 -13
- package/dist/presets/ws/server.js +0 -3585
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { hash } from "ohash";
|
|
2
|
+
import pLimit from "p-limit";
|
|
3
|
+
//#region src/cache.ts
|
|
4
|
+
/**
|
|
5
|
+
* @experimental API is expected to change.
|
|
6
|
+
*/
|
|
7
|
+
var RpcCacheManager = class {
|
|
8
|
+
cacheMap = /* @__PURE__ */ new Map();
|
|
9
|
+
options;
|
|
10
|
+
keySerializer;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.options = options;
|
|
13
|
+
this.keySerializer = options.keySerializer || ((args) => hash(args));
|
|
14
|
+
}
|
|
15
|
+
updateOptions(options) {
|
|
16
|
+
this.options = {
|
|
17
|
+
...this.options,
|
|
18
|
+
...options
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
cached(m, a) {
|
|
22
|
+
const methodCache = this.cacheMap.get(m);
|
|
23
|
+
if (methodCache) return methodCache.get(this.keySerializer(a));
|
|
24
|
+
}
|
|
25
|
+
apply(req, res) {
|
|
26
|
+
const methodCache = this.cacheMap.get(req.m) || /* @__PURE__ */ new Map();
|
|
27
|
+
methodCache.set(this.keySerializer(req.a), res);
|
|
28
|
+
this.cacheMap.set(req.m, methodCache);
|
|
29
|
+
}
|
|
30
|
+
validate(m) {
|
|
31
|
+
return this.options.functions.includes(m);
|
|
32
|
+
}
|
|
33
|
+
clear(fn) {
|
|
34
|
+
if (fn) this.cacheMap.delete(fn);
|
|
35
|
+
else this.cacheMap.clear();
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/handler.ts
|
|
40
|
+
async function getRpcResolvedSetupResult(definition, context) {
|
|
41
|
+
if (definition.__resolved) return definition.__resolved;
|
|
42
|
+
if (!definition.setup) return {};
|
|
43
|
+
definition.__promise ??= Promise.resolve(definition.setup(context)).then((r) => {
|
|
44
|
+
definition.__resolved = r;
|
|
45
|
+
definition.__promise = void 0;
|
|
46
|
+
return r;
|
|
47
|
+
});
|
|
48
|
+
return definition.__resolved ??= await definition.__promise;
|
|
49
|
+
}
|
|
50
|
+
async function getRpcHandler(definition, context) {
|
|
51
|
+
if (definition.handler) return definition.handler;
|
|
52
|
+
const result = await getRpcResolvedSetupResult(definition, context);
|
|
53
|
+
if (!result.handler) throw new Error(`[devtools-rpc] Either handler or setup function must be provided for RPC function "${definition.name}"`);
|
|
54
|
+
return result.handler;
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/collector.ts
|
|
58
|
+
var RpcFunctionsCollectorBase = class {
|
|
59
|
+
definitions = /* @__PURE__ */ new Map();
|
|
60
|
+
functions;
|
|
61
|
+
_onChanged = [];
|
|
62
|
+
constructor(context) {
|
|
63
|
+
this.context = context;
|
|
64
|
+
const definitions = this.definitions;
|
|
65
|
+
const self = this;
|
|
66
|
+
this.functions = new Proxy({}, {
|
|
67
|
+
get(_, prop) {
|
|
68
|
+
const definition = definitions.get(prop);
|
|
69
|
+
if (!definition) return void 0;
|
|
70
|
+
return getRpcHandler(definition, self.context);
|
|
71
|
+
},
|
|
72
|
+
has(_, prop) {
|
|
73
|
+
return definitions.has(prop);
|
|
74
|
+
},
|
|
75
|
+
getOwnPropertyDescriptor(_, prop) {
|
|
76
|
+
return {
|
|
77
|
+
value: definitions.get(prop)?.handler,
|
|
78
|
+
configurable: true,
|
|
79
|
+
enumerable: true
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
ownKeys() {
|
|
83
|
+
return Array.from(definitions.keys());
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
register(fn, force = false) {
|
|
88
|
+
if (this.definitions.has(fn.name) && !force) throw new Error(`RPC function "${fn.name}" is already registered`);
|
|
89
|
+
this.definitions.set(fn.name, fn);
|
|
90
|
+
this._onChanged.forEach((cb) => cb(fn.name));
|
|
91
|
+
}
|
|
92
|
+
update(fn, force = false) {
|
|
93
|
+
if (!this.definitions.has(fn.name) && !force) throw new Error(`RPC function "${fn.name}" is not registered. Use register() to add new functions.`);
|
|
94
|
+
this.definitions.set(fn.name, fn);
|
|
95
|
+
this._onChanged.forEach((cb) => cb(fn.name));
|
|
96
|
+
}
|
|
97
|
+
onChanged(fn) {
|
|
98
|
+
this._onChanged.push(fn);
|
|
99
|
+
return () => {
|
|
100
|
+
const index = this._onChanged.indexOf(fn);
|
|
101
|
+
if (index !== -1) this._onChanged.splice(index, 1);
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
async getHandler(name) {
|
|
105
|
+
return await getRpcHandler(this.definitions.get(name), this.context);
|
|
106
|
+
}
|
|
107
|
+
getSchema(name) {
|
|
108
|
+
const definition = this.definitions.get(name);
|
|
109
|
+
if (!definition) throw new Error(`RPC function "${String(name)}" is not registered`);
|
|
110
|
+
return {
|
|
111
|
+
args: definition.args,
|
|
112
|
+
returns: definition.returns
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
has(name) {
|
|
116
|
+
return this.definitions.has(name);
|
|
117
|
+
}
|
|
118
|
+
get(name) {
|
|
119
|
+
return this.definitions.get(name);
|
|
120
|
+
}
|
|
121
|
+
list() {
|
|
122
|
+
return Array.from(this.definitions.keys());
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/define.ts
|
|
127
|
+
function defineRpcFunction(definition) {
|
|
128
|
+
return definition;
|
|
129
|
+
}
|
|
130
|
+
function createDefineWrapperWithContext() {
|
|
131
|
+
return function defineRpcFunctionWithContext(definition) {
|
|
132
|
+
return definition;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
//#region src/validation.ts
|
|
137
|
+
/**
|
|
138
|
+
* Validates RPC function definitions.
|
|
139
|
+
* Action and event functions cannot have dumps (side effects should not be cached).
|
|
140
|
+
*
|
|
141
|
+
* @throws {Error} If an action or event function has a dump configuration
|
|
142
|
+
*/
|
|
143
|
+
function validateDefinitions(definitions) {
|
|
144
|
+
for (const definition of definitions) {
|
|
145
|
+
const type = definition.type || "query";
|
|
146
|
+
if ((type === "action" || type === "event") && definition.dump) throw new Error(`[devtools-rpc] Function "${definition.name}" with type "${type}" cannot have dump configuration. Only "static" and "query" types support dumps.`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Validates a single RPC function definition.
|
|
151
|
+
*
|
|
152
|
+
* @throws {Error} If an action or event function has a dump configuration
|
|
153
|
+
*/
|
|
154
|
+
function validateDefinition(definition) {
|
|
155
|
+
validateDefinitions([definition]);
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/dumps.ts
|
|
159
|
+
function getDumpRecordKey(functionName, args) {
|
|
160
|
+
return `${functionName}---${hash(args)}`;
|
|
161
|
+
}
|
|
162
|
+
function getDumpFallbackKey(functionName) {
|
|
163
|
+
return `${functionName}---fallback`;
|
|
164
|
+
}
|
|
165
|
+
async function resolveGetter(valueOrGetter) {
|
|
166
|
+
return typeof valueOrGetter === "function" ? await valueOrGetter() : valueOrGetter;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Collects pre-computed dumps by executing functions with their defined input combinations.
|
|
170
|
+
* Static functions without dump config automatically get `{ inputs: [[]] }`.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```ts
|
|
174
|
+
* const store = await dumpFunctions([greet], context, { concurrency: 10 })
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
async function dumpFunctions(definitions, context, options = {}) {
|
|
178
|
+
validateDefinitions(definitions);
|
|
179
|
+
const concurrency = options.concurrency === true ? 5 : options.concurrency === false || options.concurrency == null ? 1 : options.concurrency;
|
|
180
|
+
const store = {
|
|
181
|
+
definitions: {},
|
|
182
|
+
records: {}
|
|
183
|
+
};
|
|
184
|
+
const tasksResolutions = definitions.map((definition) => async () => {
|
|
185
|
+
if (definition.type === "event" || definition.type === "action") return;
|
|
186
|
+
const setupResult = definition.setup ? await Promise.resolve(definition.setup(context)) : {};
|
|
187
|
+
const handler = setupResult.handler || definition.handler;
|
|
188
|
+
if (!handler) throw new Error(`[devtools-rpc] Either handler or setup function must be provided for RPC function "${definition.name}"`);
|
|
189
|
+
let dump = setupResult.dump ?? definition.dump;
|
|
190
|
+
if (!dump && definition.type === "static") dump = { inputs: [[]] };
|
|
191
|
+
if (!dump) return;
|
|
192
|
+
if (typeof dump === "function") dump = await Promise.resolve(dump(context, handler));
|
|
193
|
+
store.definitions[definition.name] = {
|
|
194
|
+
name: definition.name,
|
|
195
|
+
type: definition.type
|
|
196
|
+
};
|
|
197
|
+
return {
|
|
198
|
+
handler,
|
|
199
|
+
dump,
|
|
200
|
+
definition
|
|
201
|
+
};
|
|
202
|
+
});
|
|
203
|
+
let functionsToDump = [];
|
|
204
|
+
if (concurrency <= 1) for (const task of tasksResolutions) {
|
|
205
|
+
const resolution = await task();
|
|
206
|
+
if (resolution) functionsToDump.push(resolution);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
const limit = pLimit(concurrency);
|
|
210
|
+
functionsToDump = (await Promise.all(tasksResolutions.map((task) => limit(task)))).filter((x) => !!x);
|
|
211
|
+
}
|
|
212
|
+
const dumpTasks = [];
|
|
213
|
+
for (const { definition, handler, dump } of functionsToDump) {
|
|
214
|
+
const { inputs, records, fallback } = dump;
|
|
215
|
+
if (records) for (const record of records) {
|
|
216
|
+
const recordKey = getDumpRecordKey(definition.name, record.inputs);
|
|
217
|
+
store.records[recordKey] = record;
|
|
218
|
+
}
|
|
219
|
+
if ("fallback" in dump) {
|
|
220
|
+
const fallbackKey = getDumpFallbackKey(definition.name);
|
|
221
|
+
store.records[fallbackKey] = {
|
|
222
|
+
inputs: [],
|
|
223
|
+
output: fallback
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
if (inputs) for (const input of inputs) dumpTasks.push(async () => {
|
|
227
|
+
const recordKey = getDumpRecordKey(definition.name, input);
|
|
228
|
+
try {
|
|
229
|
+
const output = await Promise.resolve(handler(...input));
|
|
230
|
+
store.records[recordKey] = {
|
|
231
|
+
inputs: input,
|
|
232
|
+
output
|
|
233
|
+
};
|
|
234
|
+
} catch (error) {
|
|
235
|
+
store.records[recordKey] = {
|
|
236
|
+
inputs: input,
|
|
237
|
+
error: {
|
|
238
|
+
message: error.message,
|
|
239
|
+
name: error.name
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
if (concurrency <= 1) for (const task of dumpTasks) await task();
|
|
246
|
+
else {
|
|
247
|
+
const limit = pLimit(concurrency);
|
|
248
|
+
await Promise.all(dumpTasks.map((task) => limit(task)));
|
|
249
|
+
}
|
|
250
|
+
return store;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Creates a client that serves pre-computed results from a dump store.
|
|
254
|
+
* Uses argument hashing to match calls to stored records.
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* ```ts
|
|
258
|
+
* const client = createClientFromDump(store)
|
|
259
|
+
* await client.greet('Alice')
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
262
|
+
function createClientFromDump(store, options = {}) {
|
|
263
|
+
const { onMiss } = options;
|
|
264
|
+
return new Proxy({}, {
|
|
265
|
+
get(_, functionName) {
|
|
266
|
+
if (!(functionName in store.definitions)) throw new Error(`[devtools-rpc] Function "${functionName}" not found in dump store`);
|
|
267
|
+
return async (...args) => {
|
|
268
|
+
const recordKey = getDumpRecordKey(functionName, args);
|
|
269
|
+
const recordOrGetter = store.records[recordKey];
|
|
270
|
+
if (recordOrGetter) {
|
|
271
|
+
const record = await resolveGetter(recordOrGetter);
|
|
272
|
+
if (record.error) {
|
|
273
|
+
const error = new Error(record.error.message);
|
|
274
|
+
error.name = record.error.name;
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
277
|
+
if (typeof record.output === "function") return await record.output();
|
|
278
|
+
return record.output;
|
|
279
|
+
}
|
|
280
|
+
onMiss?.(functionName, args);
|
|
281
|
+
const fallbackKey = getDumpFallbackKey(functionName);
|
|
282
|
+
if (fallbackKey in store.records) {
|
|
283
|
+
const fallbackOrGetter = store.records[fallbackKey];
|
|
284
|
+
const fallbackRecord = await resolveGetter(fallbackOrGetter);
|
|
285
|
+
if (fallbackRecord && typeof fallbackRecord.output === "function") return await fallbackRecord.output();
|
|
286
|
+
if (fallbackRecord) return fallbackRecord.output;
|
|
287
|
+
}
|
|
288
|
+
throw new Error(`[devtools-rpc] No dump match for "${functionName}" with args: ${JSON.stringify(args)}`);
|
|
289
|
+
};
|
|
290
|
+
},
|
|
291
|
+
has(_, functionName) {
|
|
292
|
+
return functionName in store.definitions;
|
|
293
|
+
},
|
|
294
|
+
ownKeys() {
|
|
295
|
+
return Object.keys(store.definitions);
|
|
296
|
+
},
|
|
297
|
+
getOwnPropertyDescriptor(_, functionName) {
|
|
298
|
+
return functionName in store.definitions ? {
|
|
299
|
+
configurable: true,
|
|
300
|
+
enumerable: true,
|
|
301
|
+
value: void 0
|
|
302
|
+
} : void 0;
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Filters function definitions to only those with dump definitions.
|
|
308
|
+
* Note: Only checks the definition itself, not setup results.
|
|
309
|
+
*/
|
|
310
|
+
function getDefinitionsWithDumps(definitions) {
|
|
311
|
+
return definitions.filter((def) => def.dump !== void 0);
|
|
312
|
+
}
|
|
313
|
+
//#endregion
|
|
314
|
+
export { RpcCacheManager, RpcFunctionsCollectorBase, createClientFromDump, createDefineWrapperWithContext, defineRpcFunction, dumpFunctions, getDefinitionsWithDumps, getRpcHandler, getRpcResolvedSetupResult, validateDefinition, validateDefinitions };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BirpcGroup, BirpcOptions, ChannelOptions } from "birpc";
|
|
2
2
|
|
|
3
3
|
//#region src/presets/index.d.ts
|
|
4
|
-
type RpcServerPresetReturnType = <ClientFunctions, ServerFunctions>(rpc: BirpcGroup<ClientFunctions, ServerFunctions>, options?: Pick<BirpcOptions<ClientFunctions>, 'serialize' | 'deserialize'>) => void;
|
|
4
|
+
type RpcServerPresetReturnType = <ClientFunctions extends object, ServerFunctions extends object>(rpc: BirpcGroup<ClientFunctions, ServerFunctions, false>, options?: Pick<BirpcOptions<ClientFunctions, ServerFunctions, false>, 'serialize' | 'deserialize'>) => void;
|
|
5
5
|
type RpcServerPresetBasicType = (...args: any[]) => RpcServerPresetReturnType;
|
|
6
6
|
type RpcServerPreset<T extends RpcServerPresetBasicType> = (...args: Parameters<T>) => RpcServerPresetReturnType;
|
|
7
7
|
declare function defineRpcServerPreset<T extends RpcServerPresetBasicType>(preset: T): RpcServerPreset<T>;
|
|
@@ -10,4 +10,4 @@ type RpcClientPresetBasicType = (...args: any[]) => RpcClientPresetReturnType;
|
|
|
10
10
|
type RpcClientPreset<T extends RpcClientPresetBasicType> = (...args: Parameters<T>) => RpcClientPresetReturnType;
|
|
11
11
|
declare function defineRpcClientPreset<T extends RpcClientPresetBasicType>(preset: T): RpcClientPreset<T>;
|
|
12
12
|
//#endregion
|
|
13
|
-
export {
|
|
13
|
+
export { RpcClientPreset, RpcClientPresetBasicType, RpcClientPresetReturnType, RpcServerPreset, RpcServerPresetBasicType, RpcServerPresetReturnType, defineRpcClientPreset, defineRpcServerPreset };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RpcClientPreset } from "../index.mjs";
|
|
2
|
+
import { ChannelOptions } from "birpc";
|
|
3
|
+
|
|
4
|
+
//#region src/presets/ws/client.d.ts
|
|
5
|
+
interface WebSocketRpcClientOptions {
|
|
6
|
+
url: string;
|
|
7
|
+
onConnected?: (e: Event) => void;
|
|
8
|
+
onError?: (e: Error) => void;
|
|
9
|
+
onDisconnected?: (e: CloseEvent) => void;
|
|
10
|
+
authId?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const createWsRpcPreset: RpcClientPreset<(options: WebSocketRpcClientOptions) => ChannelOptions>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { WebSocketRpcClientOptions, createWsRpcPreset };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineRpcClientPreset } from "../index.mjs";
|
|
2
2
|
import { parse, stringify } from "structured-clone-es";
|
|
3
|
-
|
|
4
3
|
//#region src/presets/ws/client.ts
|
|
5
4
|
function NOOP() {}
|
|
6
5
|
const createWsRpcPreset = defineRpcClientPreset((options) => {
|
|
7
|
-
|
|
6
|
+
let url = options.url;
|
|
7
|
+
if (options.authId) url = `${url}?vite_devtools_auth_id=${encodeURIComponent(options.authId)}`;
|
|
8
|
+
const ws = new WebSocket(url);
|
|
8
9
|
const { onConnected = NOOP, onError = NOOP, onDisconnected = NOOP } = options;
|
|
9
10
|
ws.addEventListener("open", (e) => {
|
|
10
11
|
onConnected(e);
|
|
@@ -35,6 +36,5 @@ const createWsRpcPreset = defineRpcClientPreset((options) => {
|
|
|
35
36
|
deserialize: parse
|
|
36
37
|
};
|
|
37
38
|
});
|
|
38
|
-
|
|
39
39
|
//#endregion
|
|
40
|
-
export { createWsRpcPreset };
|
|
40
|
+
export { createWsRpcPreset };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { RpcServerPreset } from "../index.mjs";
|
|
2
|
+
import { BirpcGroup, BirpcOptions } from "birpc";
|
|
3
|
+
import { ServerOptions } from "node:https";
|
|
4
|
+
import { WebSocket } from "ws";
|
|
5
|
+
import { IncomingMessage } from "node:http";
|
|
6
|
+
|
|
7
|
+
//#region src/presets/ws/server.d.ts
|
|
8
|
+
interface DevToolsNodeRpcSessionMeta {
|
|
9
|
+
id: number;
|
|
10
|
+
ws?: WebSocket;
|
|
11
|
+
clientAuthId?: string;
|
|
12
|
+
isTrusted?: boolean;
|
|
13
|
+
subscribedStates: Set<string>;
|
|
14
|
+
}
|
|
15
|
+
interface WebSocketRpcServerOptions {
|
|
16
|
+
port: number;
|
|
17
|
+
host?: string;
|
|
18
|
+
https?: ServerOptions | undefined;
|
|
19
|
+
onConnected?: (ws: WebSocket, req: IncomingMessage, meta: DevToolsNodeRpcSessionMeta) => void;
|
|
20
|
+
onDisconnected?: (ws: WebSocket, meta: DevToolsNodeRpcSessionMeta) => void;
|
|
21
|
+
}
|
|
22
|
+
declare const createWsRpcPreset: RpcServerPreset<(options: WebSocketRpcServerOptions) => <ClientFunctions extends object, ServerFunctions extends object>(rpc: BirpcGroup<ClientFunctions, ServerFunctions, false>, options?: Pick<BirpcOptions<ClientFunctions, ServerFunctions, false>, 'serialize' | 'deserialize'>) => void>;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { DevToolsNodeRpcSessionMeta, WebSocketRpcServerOptions, createWsRpcPreset };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { defineRpcServerPreset } from "../index.mjs";
|
|
2
|
+
import { parse, stringify } from "structured-clone-es";
|
|
3
|
+
import { createServer } from "node:https";
|
|
4
|
+
import { WebSocketServer } from "ws";
|
|
5
|
+
//#region src/presets/ws/server.ts
|
|
6
|
+
let id = 0;
|
|
7
|
+
function NOOP() {}
|
|
8
|
+
const createWsRpcPreset = defineRpcServerPreset((options) => {
|
|
9
|
+
const { port, https, host = "localhost", onConnected = NOOP, onDisconnected = NOOP } = options;
|
|
10
|
+
const httpsServer = https ? createServer(https) : void 0;
|
|
11
|
+
const wss = https ? new WebSocketServer({ server: httpsServer }) : new WebSocketServer({
|
|
12
|
+
port,
|
|
13
|
+
host
|
|
14
|
+
});
|
|
15
|
+
return (rpcGroup, options) => {
|
|
16
|
+
const { serialize = stringify, deserialize = parse } = options ?? {};
|
|
17
|
+
wss.on("connection", (ws, req) => {
|
|
18
|
+
const meta = {
|
|
19
|
+
id: id++,
|
|
20
|
+
ws,
|
|
21
|
+
subscribedStates: /* @__PURE__ */ new Set()
|
|
22
|
+
};
|
|
23
|
+
const channel = {
|
|
24
|
+
post: (data) => {
|
|
25
|
+
ws.send(data);
|
|
26
|
+
},
|
|
27
|
+
on: (fn) => {
|
|
28
|
+
ws.on("message", (data) => {
|
|
29
|
+
fn(data.toString());
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
serialize,
|
|
33
|
+
deserialize,
|
|
34
|
+
meta
|
|
35
|
+
};
|
|
36
|
+
rpcGroup.updateChannels((channels) => {
|
|
37
|
+
channels.push(channel);
|
|
38
|
+
});
|
|
39
|
+
ws.on("close", () => {
|
|
40
|
+
rpcGroup.updateChannels((channels) => {
|
|
41
|
+
const index = channels.indexOf(channel);
|
|
42
|
+
if (index >= 0) channels.splice(index, 1);
|
|
43
|
+
});
|
|
44
|
+
onDisconnected(ws, meta);
|
|
45
|
+
});
|
|
46
|
+
onConnected(ws, req, meta);
|
|
47
|
+
});
|
|
48
|
+
httpsServer?.listen(port, host);
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
//#endregion
|
|
52
|
+
export { createWsRpcPreset };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BirpcGroup, EventOptions } from "birpc";
|
|
2
|
+
|
|
3
|
+
//#region src/server.d.ts
|
|
4
|
+
declare function createRpcServer<ClientFunctions extends object = Record<string, never>, ServerFunctions extends object = Record<string, never>>(functions: ServerFunctions, options: {
|
|
5
|
+
preset: (rpc: BirpcGroup<ClientFunctions, ServerFunctions, false>) => void;
|
|
6
|
+
rpcOptions?: EventOptions<ClientFunctions, ServerFunctions, false>;
|
|
7
|
+
}): BirpcGroup<ClientFunctions, ServerFunctions, false>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { createRpcServer };
|
package/dist/server.mjs
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createBirpcGroup } from "birpc";
|
|
2
|
+
//#region src/server.ts
|
|
3
|
+
function createRpcServer(functions, options) {
|
|
4
|
+
const rpc = createBirpcGroup(functions, [], {
|
|
5
|
+
...options?.rpcOptions,
|
|
6
|
+
proxify: false
|
|
7
|
+
});
|
|
8
|
+
options?.preset(rpc);
|
|
9
|
+
return rpc;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { createRpcServer };
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitejs/devtools-rpc",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"description": "
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Vite DevTools RPC Layer",
|
|
6
6
|
"author": "VoidZero Inc.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"homepage": "https://github.com/vitejs/devtools#readme",
|
|
@@ -19,30 +19,36 @@
|
|
|
19
19
|
],
|
|
20
20
|
"sideEffects": false,
|
|
21
21
|
"exports": {
|
|
22
|
-
".": "./dist/index.
|
|
23
|
-
"./
|
|
24
|
-
"./presets
|
|
25
|
-
"./presets/ws/
|
|
22
|
+
".": "./dist/index.mjs",
|
|
23
|
+
"./client": "./dist/client.mjs",
|
|
24
|
+
"./presets": "./dist/presets/index.mjs",
|
|
25
|
+
"./presets/ws/client": "./dist/presets/ws/client.mjs",
|
|
26
|
+
"./presets/ws/server": "./dist/presets/ws/server.mjs",
|
|
27
|
+
"./server": "./dist/server.mjs",
|
|
26
28
|
"./package.json": "./package.json"
|
|
27
29
|
},
|
|
28
|
-
"
|
|
29
|
-
"module": "./dist/index.js",
|
|
30
|
-
"types": "./dist/index.d.ts",
|
|
30
|
+
"types": "./dist/index.d.mts",
|
|
31
31
|
"files": [
|
|
32
32
|
"dist"
|
|
33
33
|
],
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"ws": "*"
|
|
36
|
+
},
|
|
34
37
|
"peerDependenciesMeta": {
|
|
35
38
|
"ws": {
|
|
36
39
|
"optional": true
|
|
37
40
|
}
|
|
38
41
|
},
|
|
39
42
|
"dependencies": {
|
|
40
|
-
"birpc": "^
|
|
41
|
-
"
|
|
43
|
+
"birpc": "^4.0.0",
|
|
44
|
+
"ohash": "^2.0.11",
|
|
45
|
+
"p-limit": "^7.3.0",
|
|
46
|
+
"structured-clone-es": "^1.0.0",
|
|
47
|
+
"valibot": "^1.2.0"
|
|
42
48
|
},
|
|
43
49
|
"devDependencies": {
|
|
44
|
-
"tsdown": "^0.
|
|
45
|
-
"ws": "^8.
|
|
50
|
+
"tsdown": "^0.21.2",
|
|
51
|
+
"ws": "^8.19.0"
|
|
46
52
|
},
|
|
47
53
|
"scripts": {
|
|
48
54
|
"build": "tsdown",
|
package/dist/index.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { BirpcGroup, BirpcOptions, BirpcReturn, EventOptions } from "birpc";
|
|
2
|
-
|
|
3
|
-
//#region src/client.d.ts
|
|
4
|
-
declare function createRpcClient<ServerFunctions = Record<string, never>, ClientFunctions extends object = Record<string, never>>(functions: ClientFunctions, options: {
|
|
5
|
-
preset: BirpcOptions<ServerFunctions>;
|
|
6
|
-
rpcOptions?: Partial<BirpcOptions<ServerFunctions>>;
|
|
7
|
-
}): BirpcReturn<ServerFunctions, ClientFunctions>;
|
|
8
|
-
//#endregion
|
|
9
|
-
//#region src/server.d.ts
|
|
10
|
-
declare function createRpcServer<ClientFunctions extends object = Record<string, never>, ServerFunctions extends object = Record<string, never>>(functions: ServerFunctions, options: {
|
|
11
|
-
preset: (rpc: BirpcGroup<ClientFunctions, ServerFunctions>) => void;
|
|
12
|
-
rpcOptions?: EventOptions<ClientFunctions>;
|
|
13
|
-
}): BirpcGroup<ClientFunctions, ServerFunctions>;
|
|
14
|
-
//#endregion
|
|
15
|
-
export { createRpcClient, createRpcServer };
|
package/dist/index.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { createBirpc, createBirpcGroup } from "birpc";
|
|
2
|
-
|
|
3
|
-
//#region src/client.ts
|
|
4
|
-
function createRpcClient(functions, options) {
|
|
5
|
-
const { preset, rpcOptions = {} } = options;
|
|
6
|
-
return createBirpc(functions, {
|
|
7
|
-
...preset,
|
|
8
|
-
timeout: -1,
|
|
9
|
-
...rpcOptions
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
//#endregion
|
|
14
|
-
//#region src/server.ts
|
|
15
|
-
function createRpcServer(functions, options) {
|
|
16
|
-
const rpc = createBirpcGroup(functions, [], options?.rpcOptions ?? {});
|
|
17
|
-
options?.preset(rpc);
|
|
18
|
-
return rpc;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
//#endregion
|
|
22
|
-
export { createRpcClient, createRpcServer };
|
package/dist/presets/index.d.ts
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import { a as RpcServerPresetBasicType, c as defineRpcServerPreset, i as RpcServerPreset, n as RpcClientPresetBasicType, o as RpcServerPresetReturnType, r as RpcClientPresetReturnType, s as defineRpcClientPreset, t as RpcClientPreset } from "../index-SwSDJlvS.js";
|
|
2
|
-
export { RpcClientPreset, RpcClientPresetBasicType, RpcClientPresetReturnType, RpcServerPreset, RpcServerPresetBasicType, RpcServerPresetReturnType, defineRpcClientPreset, defineRpcServerPreset };
|
package/dist/presets/index.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { t as RpcClientPreset } from "../../index-SwSDJlvS.js";
|
|
2
|
-
|
|
3
|
-
//#region src/presets/ws/client.d.ts
|
|
4
|
-
interface WebSocketRpcClientOptions {
|
|
5
|
-
url: string;
|
|
6
|
-
onConnected?: (e: Event) => void;
|
|
7
|
-
onError?: (e: Error) => void;
|
|
8
|
-
onDisconnected?: (e: CloseEvent) => void;
|
|
9
|
-
}
|
|
10
|
-
declare const createWsRpcPreset: RpcClientPreset<(options: WebSocketRpcClientOptions) => {
|
|
11
|
-
on: (handler: (data: string) => void) => void;
|
|
12
|
-
post: (data: string) => void;
|
|
13
|
-
serialize: (obj: any) => string;
|
|
14
|
-
deserialize: (str: string) => unknown;
|
|
15
|
-
}>;
|
|
16
|
-
//#endregion
|
|
17
|
-
export { WebSocketRpcClientOptions, createWsRpcPreset };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { i as RpcServerPreset } from "../../index-SwSDJlvS.js";
|
|
2
|
-
import { BirpcGroup, BirpcOptions } from "birpc";
|
|
3
|
-
import { WebSocket } from "ws";
|
|
4
|
-
|
|
5
|
-
//#region src/presets/ws/server.d.ts
|
|
6
|
-
interface WebSocketRpcServerOptions {
|
|
7
|
-
port: number;
|
|
8
|
-
onConnected?: (ws: WebSocket) => void;
|
|
9
|
-
onDisconnected?: (ws: WebSocket) => void;
|
|
10
|
-
}
|
|
11
|
-
declare const createWsRpcPreset: RpcServerPreset<(options: WebSocketRpcServerOptions) => <ClientFunctions, ServerFunctions>(rpc: BirpcGroup<ClientFunctions, ServerFunctions>, options?: Pick<BirpcOptions<ClientFunctions>, 'serialize' | 'deserialize'>) => void>;
|
|
12
|
-
//#endregion
|
|
13
|
-
export { WebSocketRpcServerOptions, createWsRpcPreset };
|