@aigne/afs-explorer 1.11.0-beta.10 → 1.11.0-beta.12

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,7 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ //#region rolldown:runtime
4
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
5
+
6
+ //#endregion
7
+ export { __require };
package/dist/index.cjs CHANGED
@@ -1,20 +1,20 @@
1
- const require_server = require('./server.cjs');
1
+ const require_ws_server = require('./ws-server.cjs');
2
2
 
3
3
  //#region src/index.ts
4
4
  /**
5
- * Start the AFS Explorer web server
5
+ * Start the AFS Explorer web server (Bun.serve + WebSocket JSON-RPC)
6
6
  * @param afs - The AFS instance to explore
7
7
  * @param options - Server options
8
- * @returns The ExplorerServer instance
8
+ * @returns Object with port, url, and stop function
9
9
  */
10
10
  async function startExplorer(afs, options = {}) {
11
- const server = new require_server.ExplorerServer(afs, options);
12
- await server.start();
13
- return server;
11
+ const server = new require_ws_server.ExplorerWSServer(afs, options);
12
+ return {
13
+ ...await server.start(),
14
+ stop: () => server.stop()
15
+ };
14
16
  }
15
17
 
16
18
  //#endregion
17
- exports.ExplorerServer = require_server.ExplorerServer;
18
- exports.createExplorerMiddleware = require_server.createExplorerMiddleware;
19
- exports.createExplorerRouter = require_server.createExplorerRouter;
19
+ exports.ExplorerWSServer = require_ws_server.ExplorerWSServer;
20
20
  exports.startExplorer = startExplorer;
package/dist/index.d.cts CHANGED
@@ -1,14 +1,18 @@
1
- import { ExplorerMiddlewareOptions, ExplorerRouterOptions, ExplorerServer, ExplorerServerOptions, createExplorerMiddleware, createExplorerRouter } from "./server.cjs";
1
+ import { ConfigManager, ExplorerWSServer, WSServerOptions } from "./ws-server.cjs";
2
2
  import { AFS } from "@aigne/afs";
3
3
 
4
4
  //#region src/index.d.ts
5
5
  /**
6
- * Start the AFS Explorer web server
6
+ * Start the AFS Explorer web server (Bun.serve + WebSocket JSON-RPC)
7
7
  * @param afs - The AFS instance to explore
8
8
  * @param options - Server options
9
- * @returns The ExplorerServer instance
9
+ * @returns Object with port, url, and stop function
10
10
  */
11
- declare function startExplorer(afs: AFS, options?: ExplorerServerOptions): Promise<ExplorerServer>;
11
+ declare function startExplorer(afs: AFS, options?: WSServerOptions): Promise<{
12
+ port: number;
13
+ url: string;
14
+ stop: () => void;
15
+ }>;
12
16
  //#endregion
13
- export { type ExplorerMiddlewareOptions, type ExplorerRouterOptions, ExplorerServer, type ExplorerServerOptions, createExplorerMiddleware, createExplorerRouter, startExplorer };
17
+ export { type ConfigManager, ExplorerWSServer, type WSServerOptions, startExplorer };
14
18
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;AAyBA;;;;;iBAAsB,aAAA,CACpB,GAAA,EAAK,GAAA,EACL,OAAA,GAAS,qBAAA,GACR,OAAA,CAAQ,cAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;AAWA;;;;;iBAAsB,aAAA,CACpB,GAAA,EAAK,GAAA,EACL,OAAA,GAAS,eAAA,GACR,OAAA;EAAU,IAAA;EAAc,GAAA;EAAa,IAAA;AAAA"}
package/dist/index.d.mts CHANGED
@@ -1,14 +1,18 @@
1
- import { ExplorerMiddlewareOptions, ExplorerRouterOptions, ExplorerServer, ExplorerServerOptions, createExplorerMiddleware, createExplorerRouter } from "./server.mjs";
1
+ import { ConfigManager, ExplorerWSServer, WSServerOptions } from "./ws-server.mjs";
2
2
  import { AFS } from "@aigne/afs";
3
3
 
4
4
  //#region src/index.d.ts
5
5
  /**
6
- * Start the AFS Explorer web server
6
+ * Start the AFS Explorer web server (Bun.serve + WebSocket JSON-RPC)
7
7
  * @param afs - The AFS instance to explore
8
8
  * @param options - Server options
9
- * @returns The ExplorerServer instance
9
+ * @returns Object with port, url, and stop function
10
10
  */
11
- declare function startExplorer(afs: AFS, options?: ExplorerServerOptions): Promise<ExplorerServer>;
11
+ declare function startExplorer(afs: AFS, options?: WSServerOptions): Promise<{
12
+ port: number;
13
+ url: string;
14
+ stop: () => void;
15
+ }>;
12
16
  //#endregion
13
- export { type ExplorerMiddlewareOptions, type ExplorerRouterOptions, ExplorerServer, type ExplorerServerOptions, createExplorerMiddleware, createExplorerRouter, startExplorer };
17
+ export { type ConfigManager, ExplorerWSServer, type WSServerOptions, startExplorer };
14
18
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;AAyBA;;;;;iBAAsB,aAAA,CACpB,GAAA,EAAK,GAAA,EACL,OAAA,GAAS,qBAAA,GACR,OAAA,CAAQ,cAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;AAWA;;;;;iBAAsB,aAAA,CACpB,GAAA,EAAK,GAAA,EACL,OAAA,GAAS,eAAA,GACR,OAAA;EAAU,IAAA;EAAc,GAAA;EAAa,IAAA;AAAA"}
package/dist/index.mjs CHANGED
@@ -1,18 +1,20 @@
1
- import { ExplorerServer, createExplorerMiddleware, createExplorerRouter } from "./server.mjs";
1
+ import { ExplorerWSServer } from "./ws-server.mjs";
2
2
 
3
3
  //#region src/index.ts
4
4
  /**
5
- * Start the AFS Explorer web server
5
+ * Start the AFS Explorer web server (Bun.serve + WebSocket JSON-RPC)
6
6
  * @param afs - The AFS instance to explore
7
7
  * @param options - Server options
8
- * @returns The ExplorerServer instance
8
+ * @returns Object with port, url, and stop function
9
9
  */
10
10
  async function startExplorer(afs, options = {}) {
11
- const server = new ExplorerServer(afs, options);
12
- await server.start();
13
- return server;
11
+ const server = new ExplorerWSServer(afs, options);
12
+ return {
13
+ ...await server.start(),
14
+ stop: () => server.stop()
15
+ };
14
16
  }
15
17
 
16
18
  //#endregion
17
- export { ExplorerServer, createExplorerMiddleware, createExplorerRouter, startExplorer };
19
+ export { ExplorerWSServer, startExplorer };
18
20
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { AFS } from \"@aigne/afs\";\nimport {\n createExplorerMiddleware,\n createExplorerRouter,\n type ExplorerMiddlewareOptions,\n type ExplorerRouterOptions,\n ExplorerServer,\n type ExplorerServerOptions,\n} from \"./server.js\";\n\nexport {\n ExplorerServer,\n type ExplorerServerOptions,\n createExplorerRouter,\n createExplorerMiddleware,\n type ExplorerRouterOptions,\n type ExplorerMiddlewareOptions,\n};\n\n/**\n * Start the AFS Explorer web server\n * @param afs - The AFS instance to explore\n * @param options - Server options\n * @returns The ExplorerServer instance\n */\nexport async function startExplorer(\n afs: AFS,\n options: ExplorerServerOptions = {},\n): Promise<ExplorerServer> {\n const server = new ExplorerServer(afs, options);\n await server.start();\n return server;\n}\n"],"mappings":";;;;;;;;;AAyBA,eAAsB,cACpB,KACA,UAAiC,EAAE,EACV;CACzB,MAAM,SAAS,IAAI,eAAe,KAAK,QAAQ;AAC/C,OAAM,OAAO,OAAO;AACpB,QAAO"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { AFS } from \"@aigne/afs\";\nimport { type ConfigManager, ExplorerWSServer, type WSServerOptions } from \"./ws-server.js\";\n\nexport { ExplorerWSServer, type ConfigManager, type WSServerOptions };\n\n/**\n * Start the AFS Explorer web server (Bun.serve + WebSocket JSON-RPC)\n * @param afs - The AFS instance to explore\n * @param options - Server options\n * @returns Object with port, url, and stop function\n */\nexport async function startExplorer(\n afs: AFS,\n options: WSServerOptions = {},\n): Promise<{ port: number; url: string; stop: () => void }> {\n const server = new ExplorerWSServer(afs, options);\n const info = await server.start();\n return { ...info, stop: () => server.stop() };\n}\n"],"mappings":";;;;;;;;;AAWA,eAAsB,cACpB,KACA,UAA2B,EAAE,EAC6B;CAC1D,MAAM,SAAS,IAAI,iBAAiB,KAAK,QAAQ;AAEjD,QAAO;EAAE,GADI,MAAM,OAAO,OAAO;EACf,YAAY,OAAO,MAAM;EAAE"}
@@ -0,0 +1,493 @@
1
+ let node_fs = require("node:fs");
2
+ let node_http = require("node:http");
3
+ let node_path = require("node:path");
4
+
5
+ //#region src/ws-server.ts
6
+ const MIME_TYPES = {
7
+ ".html": "text/html; charset=utf-8",
8
+ ".js": "application/javascript; charset=utf-8",
9
+ ".css": "text/css; charset=utf-8",
10
+ ".json": "application/json; charset=utf-8",
11
+ ".svg": "image/svg+xml",
12
+ ".png": "image/png",
13
+ ".jpg": "image/jpeg",
14
+ ".jpeg": "image/jpeg",
15
+ ".gif": "image/gif",
16
+ ".webp": "image/webp",
17
+ ".bmp": "image/bmp",
18
+ ".ico": "image/x-icon",
19
+ ".pdf": "application/pdf",
20
+ ".md": "text/markdown; charset=utf-8",
21
+ ".txt": "text/plain; charset=utf-8"
22
+ };
23
+ function getMimeType(fileName) {
24
+ return MIME_TYPES[fileName.slice(fileName.lastIndexOf("."))] || "application/octet-stream";
25
+ }
26
+ var ExplorerWSServer = class {
27
+ httpServer;
28
+ wss;
29
+ afs;
30
+ options;
31
+ constructor(afs, options = {}) {
32
+ this.afs = afs;
33
+ this.options = options;
34
+ }
35
+ /**
36
+ * Broadcast a JSON-RPC notification to all connected WebSocket clients.
37
+ */
38
+ broadcast(method, params) {
39
+ if (!this.wss) return;
40
+ const message = JSON.stringify({
41
+ method,
42
+ params
43
+ });
44
+ for (const client of this.wss.clients) if (client.readyState === 1) client.send(message);
45
+ }
46
+ async start() {
47
+ const port = this.options.port || 0;
48
+ const host = this.options.host || "localhost";
49
+ const afs = this.afs;
50
+ const opts = this.options;
51
+ const configManager = this.options.configManager;
52
+ const httpMiddleware = this.options.httpMiddleware;
53
+ const { WebSocketServer } = await import("ws");
54
+ const httpServer = (0, node_http.createServer)(async (req, res) => {
55
+ const url = new URL(req.url || "/", `http://${req.headers.host}`);
56
+ if (httpMiddleware) {
57
+ if (await httpMiddleware(req, res)) return;
58
+ }
59
+ if (url.pathname === "/api/read") {
60
+ const afsPath = url.searchParams.get("path");
61
+ if (!afsPath) {
62
+ res.writeHead(400);
63
+ res.end("Missing path parameter");
64
+ return;
65
+ }
66
+ try {
67
+ const content = (await afs.read(afsPath)).data?.content;
68
+ const mime = MIME_TYPES[afsPath.slice(afsPath.lastIndexOf("."))] || "application/octet-stream";
69
+ if (content instanceof Buffer || content instanceof Uint8Array) {
70
+ res.writeHead(200, {
71
+ "Content-Type": mime,
72
+ "Cache-Control": "no-cache"
73
+ });
74
+ res.end(Buffer.from(content));
75
+ } else if (content instanceof ArrayBuffer) {
76
+ res.writeHead(200, {
77
+ "Content-Type": mime,
78
+ "Cache-Control": "no-cache"
79
+ });
80
+ res.end(Buffer.from(new Uint8Array(content)));
81
+ } else {
82
+ const text = typeof content === "string" ? content : content !== void 0 && content !== null ? JSON.stringify(content, null, 2) : "";
83
+ res.writeHead(200, {
84
+ "Content-Type": mime.includes("charset") ? mime : `${mime}; charset=utf-8`,
85
+ "Cache-Control": "no-cache"
86
+ });
87
+ res.end(text);
88
+ }
89
+ } catch (err) {
90
+ res.writeHead(500);
91
+ res.end(err instanceof Error ? err.message : String(err));
92
+ }
93
+ return;
94
+ }
95
+ let fileName = url.pathname === "/" ? "index.html" : url.pathname.slice(1);
96
+ fileName = fileName.replace(/\.\./g, "");
97
+ serveStatic(fileName, opts, res);
98
+ });
99
+ const wss = new WebSocketServer({
100
+ server: httpServer,
101
+ path: "/ws"
102
+ });
103
+ this.wss = wss;
104
+ wss.on("connection", (ws) => {
105
+ ws.on("message", async (raw) => {
106
+ let req;
107
+ try {
108
+ const text = typeof raw === "string" ? raw : raw.toString("utf-8");
109
+ req = JSON.parse(text);
110
+ } catch {
111
+ ws.send(JSON.stringify({
112
+ id: null,
113
+ error: {
114
+ code: -32700,
115
+ message: "Parse error"
116
+ }
117
+ }));
118
+ return;
119
+ }
120
+ if (!req.method || req.id === void 0) {
121
+ ws.send(JSON.stringify({
122
+ id: req.id ?? null,
123
+ error: {
124
+ code: -32600,
125
+ message: "Invalid request"
126
+ }
127
+ }));
128
+ return;
129
+ }
130
+ const response = await handleRPC(afs, req, configManager);
131
+ ws.send(JSON.stringify(response));
132
+ });
133
+ });
134
+ this.httpServer = httpServer;
135
+ return new Promise((resolve) => {
136
+ httpServer.listen(port, host, () => {
137
+ const addr = httpServer.address();
138
+ const actualPort = typeof addr === "object" && addr ? addr.port : port;
139
+ const serverUrl = `http://${host}:${actualPort}`;
140
+ if (opts.open) {
141
+ const { exec } = require("node:child_process");
142
+ exec(`${process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open"} ${serverUrl}`);
143
+ }
144
+ resolve({
145
+ port: actualPort,
146
+ url: serverUrl
147
+ });
148
+ });
149
+ });
150
+ }
151
+ stop() {
152
+ if (this.wss) {
153
+ this.wss.close();
154
+ this.wss = void 0;
155
+ }
156
+ if (this.httpServer) {
157
+ this.httpServer.close();
158
+ this.httpServer = void 0;
159
+ }
160
+ }
161
+ };
162
+ function serveStatic(fileName, opts, res) {
163
+ if (opts.embeddedAssets && fileName in opts.embeddedAssets) {
164
+ res.writeHead(200, { "Content-Type": getMimeType(fileName) });
165
+ res.end(opts.embeddedAssets[fileName]);
166
+ return;
167
+ }
168
+ if (opts.webRoot) {
169
+ const filePath = (0, node_path.join)(opts.webRoot, fileName);
170
+ if ((0, node_fs.existsSync)(filePath)) {
171
+ const content = (0, node_fs.readFileSync)(filePath);
172
+ res.writeHead(200, {
173
+ "Content-Type": getMimeType(fileName),
174
+ "Cache-Control": "no-cache"
175
+ });
176
+ res.end(content);
177
+ return;
178
+ }
179
+ }
180
+ res.writeHead(404);
181
+ res.end("Not Found");
182
+ }
183
+ async function handleRPC(afs, req, configManager) {
184
+ const params = req.params || {};
185
+ try {
186
+ switch (req.method) {
187
+ case "list": {
188
+ const path = params.path || "/";
189
+ const maxDepth = params.maxDepth ?? 1;
190
+ const result = await afs.list(path, { maxDepth });
191
+ return {
192
+ id: req.id,
193
+ result: { list: result.data }
194
+ };
195
+ }
196
+ case "read": {
197
+ const path = params.path;
198
+ if (!path) return {
199
+ id: req.id,
200
+ error: {
201
+ code: -32602,
202
+ message: "path is required"
203
+ }
204
+ };
205
+ const entry = (await afs.read(path)).data;
206
+ let content = entry?.content;
207
+ if (content instanceof Buffer || content instanceof Uint8Array) content = new TextDecoder().decode(content);
208
+ else if (content instanceof ArrayBuffer) content = new TextDecoder().decode(new Uint8Array(content));
209
+ else if (typeof content === "object" && content !== null) content = JSON.stringify(content, null, 2);
210
+ else if (content !== void 0 && typeof content !== "string") content = String(content);
211
+ return {
212
+ id: req.id,
213
+ result: {
214
+ content,
215
+ entry
216
+ }
217
+ };
218
+ }
219
+ case "stat": {
220
+ const path = params.path;
221
+ if (!path) return {
222
+ id: req.id,
223
+ error: {
224
+ code: -32602,
225
+ message: "path is required"
226
+ }
227
+ };
228
+ const result = await afs.stat(path);
229
+ return {
230
+ id: req.id,
231
+ result: result.data || null
232
+ };
233
+ }
234
+ case "search": {
235
+ const path = params.path || "/";
236
+ const pattern = params.pattern;
237
+ if (!pattern) return {
238
+ id: req.id,
239
+ error: {
240
+ code: -32602,
241
+ message: "pattern is required"
242
+ }
243
+ };
244
+ const result = await afs.search(path, pattern);
245
+ return {
246
+ id: req.id,
247
+ result
248
+ };
249
+ }
250
+ case "exec": {
251
+ const path = params.path;
252
+ if (!path) return {
253
+ id: req.id,
254
+ error: {
255
+ code: -32602,
256
+ message: "path is required"
257
+ }
258
+ };
259
+ const args = params.args || {};
260
+ const result = await afs.exec(path, args, {});
261
+ return {
262
+ id: req.id,
263
+ result
264
+ };
265
+ }
266
+ case "explain": {
267
+ const path = params.path;
268
+ if (!path) return {
269
+ id: req.id,
270
+ error: {
271
+ code: -32602,
272
+ message: "path is required"
273
+ }
274
+ };
275
+ const result = await afs.stat(path);
276
+ return {
277
+ id: req.id,
278
+ result: result.data || null
279
+ };
280
+ }
281
+ case "write": {
282
+ const path = params.path;
283
+ if (!path) return {
284
+ id: req.id,
285
+ error: {
286
+ code: -32602,
287
+ message: "path is required"
288
+ }
289
+ };
290
+ const content = params.content;
291
+ await afs.write(path, { content });
292
+ return {
293
+ id: req.id,
294
+ result: { success: true }
295
+ };
296
+ }
297
+ case "delete": {
298
+ const path = params.path;
299
+ if (!path) return {
300
+ id: req.id,
301
+ error: {
302
+ code: -32602,
303
+ message: "path is required"
304
+ }
305
+ };
306
+ const result = await afs.delete(path);
307
+ return {
308
+ id: req.id,
309
+ result
310
+ };
311
+ }
312
+ case "getMounts": {
313
+ const mounts = afs.getMounts();
314
+ const mountInfos = await Promise.all(mounts.map(async (m) => {
315
+ const ctor = m.module.constructor;
316
+ const manifest = typeof ctor.manifest === "function" ? ctor.manifest() : null;
317
+ let url;
318
+ try {
319
+ if (typeof m.module.stat === "function") url = (await m.module.stat("/", {}))?.data?.meta?.url || void 0;
320
+ } catch {}
321
+ return {
322
+ namespace: m.namespace,
323
+ path: m.path,
324
+ name: m.module.name,
325
+ description: m.module.description,
326
+ accessMode: m.module.accessMode,
327
+ category: manifest?.category || void 0,
328
+ tags: manifest?.tags || void 0,
329
+ url
330
+ };
331
+ }));
332
+ return {
333
+ id: req.id,
334
+ result: { mounts: mountInfos }
335
+ };
336
+ }
337
+ case "mount.list": {
338
+ if (!configManager) return {
339
+ id: req.id,
340
+ error: {
341
+ code: -32601,
342
+ message: "Mount management not available"
343
+ }
344
+ };
345
+ const result = await configManager.getMountList();
346
+ return {
347
+ id: req.id,
348
+ result
349
+ };
350
+ }
351
+ case "mount.add":
352
+ if (!configManager) return {
353
+ id: req.id,
354
+ error: {
355
+ code: -32601,
356
+ message: "Mount management not available"
357
+ }
358
+ };
359
+ await configManager.addMount(params);
360
+ return {
361
+ id: req.id,
362
+ result: { success: true }
363
+ };
364
+ case "mount.remove": {
365
+ if (!configManager) return {
366
+ id: req.id,
367
+ error: {
368
+ code: -32601,
369
+ message: "Mount management not available"
370
+ }
371
+ };
372
+ const path = params.path;
373
+ if (!path) return {
374
+ id: req.id,
375
+ error: {
376
+ code: -32602,
377
+ message: "path is required"
378
+ }
379
+ };
380
+ await configManager.removeMount(path);
381
+ return {
382
+ id: req.id,
383
+ result: { success: true }
384
+ };
385
+ }
386
+ case "mount.update": {
387
+ if (!configManager) return {
388
+ id: req.id,
389
+ error: {
390
+ code: -32601,
391
+ message: "Mount management not available"
392
+ }
393
+ };
394
+ const path = params.path;
395
+ if (!path) return {
396
+ id: req.id,
397
+ error: {
398
+ code: -32602,
399
+ message: "path is required"
400
+ }
401
+ };
402
+ const { path: _path, ...updates } = params;
403
+ await configManager.updateMount(path, updates);
404
+ return {
405
+ id: req.id,
406
+ result: { success: true }
407
+ };
408
+ }
409
+ case "mount.test": {
410
+ if (!configManager) return {
411
+ id: req.id,
412
+ error: {
413
+ code: -32601,
414
+ message: "Mount management not available"
415
+ }
416
+ };
417
+ const uri = params.uri;
418
+ if (!uri) return {
419
+ id: req.id,
420
+ error: {
421
+ code: -32602,
422
+ message: "uri is required"
423
+ }
424
+ };
425
+ const result = await configManager.testMount(uri, params.auth);
426
+ return {
427
+ id: req.id,
428
+ result
429
+ };
430
+ }
431
+ case "config.get": {
432
+ if (!configManager) return {
433
+ id: req.id,
434
+ error: {
435
+ code: -32601,
436
+ message: "Mount management not available"
437
+ }
438
+ };
439
+ const config = await configManager.getConfig();
440
+ return {
441
+ id: req.id,
442
+ result: { config }
443
+ };
444
+ }
445
+ case "config.reload":
446
+ if (!configManager) return {
447
+ id: req.id,
448
+ error: {
449
+ code: -32601,
450
+ message: "Mount management not available"
451
+ }
452
+ };
453
+ await configManager.reloadConfig();
454
+ return {
455
+ id: req.id,
456
+ result: { success: true }
457
+ };
458
+ case "registry.list": {
459
+ if (!configManager?.getRegistry) return {
460
+ id: req.id,
461
+ error: {
462
+ code: -32601,
463
+ message: "Registry not available"
464
+ }
465
+ };
466
+ const providers = await configManager.getRegistry();
467
+ return {
468
+ id: req.id,
469
+ result: { providers }
470
+ };
471
+ }
472
+ default: return {
473
+ id: req.id,
474
+ error: {
475
+ code: -32601,
476
+ message: `Method not found: ${req.method}`
477
+ }
478
+ };
479
+ }
480
+ } catch (err) {
481
+ const message = err instanceof Error ? err.message : String(err);
482
+ return {
483
+ id: req.id,
484
+ error: {
485
+ code: -32e3,
486
+ message
487
+ }
488
+ };
489
+ }
490
+ }
491
+
492
+ //#endregion
493
+ exports.ExplorerWSServer = ExplorerWSServer;
@@ -0,0 +1,69 @@
1
+ import { AFS } from "@aigne/afs";
2
+ import { IncomingMessage, ServerResponse } from "node:http";
3
+
4
+ //#region src/ws-server.d.ts
5
+ /**
6
+ * ConfigManager interface for mount management operations.
7
+ * Implemented in CLI layer (knows config.toml path), injected into ws-server.
8
+ */
9
+ interface ConfigManager {
10
+ getConfig(): Promise<unknown>;
11
+ getMountList(): Promise<{
12
+ mounts: unknown[];
13
+ failures: unknown[];
14
+ }>;
15
+ addMount(mount: Record<string, unknown>): Promise<void>;
16
+ removeMount(path: string): Promise<void>;
17
+ updateMount(path: string, updates: Record<string, unknown>): Promise<void>;
18
+ testMount(uri: string, auth?: string): Promise<{
19
+ success: boolean;
20
+ error?: string;
21
+ providerName?: string;
22
+ }>;
23
+ reloadConfig(): Promise<void>;
24
+ /** Get available providers from runtime discovery (scan installed @aigne/afs-* packages). */
25
+ getRegistry?(): Promise<Array<{
26
+ name: string;
27
+ description: string;
28
+ category: string;
29
+ uriTemplate: string;
30
+ tags?: string[];
31
+ packageName?: string;
32
+ }>>;
33
+ }
34
+ interface WSServerOptions {
35
+ port?: number;
36
+ host?: string;
37
+ /** Path to web/ directory for dev mode serving. */
38
+ webRoot?: string;
39
+ /** Embedded assets (for compiled binary mode). */
40
+ embeddedAssets?: Record<string, string>;
41
+ /** Open browser on start. */
42
+ open?: boolean;
43
+ /** Optional ConfigManager for mount management RPCs. */
44
+ configManager?: ConfigManager;
45
+ /**
46
+ * Optional HTTP middleware. Called before static file serving.
47
+ * Return true if the middleware handled the request.
48
+ */
49
+ httpMiddleware?: (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
50
+ }
51
+ declare class ExplorerWSServer {
52
+ private httpServer?;
53
+ private wss?;
54
+ private afs;
55
+ private options;
56
+ constructor(afs: AFS, options?: WSServerOptions);
57
+ /**
58
+ * Broadcast a JSON-RPC notification to all connected WebSocket clients.
59
+ */
60
+ broadcast(method: string, params?: Record<string, unknown>): void;
61
+ start(): Promise<{
62
+ port: number;
63
+ url: string;
64
+ }>;
65
+ stop(): void;
66
+ }
67
+ //#endregion
68
+ export { ConfigManager, ExplorerWSServer, WSServerOptions };
69
+ //# sourceMappingURL=ws-server.d.cts.map