@antseed/dashboard 0.1.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.
- package/README.md +45 -0
- package/dist/api/routes.d.ts +84 -0
- package/dist/api/routes.d.ts.map +1 -0
- package/dist/api/routes.js +454 -0
- package/dist/api/routes.js.map +1 -0
- package/dist/api/routes.test.d.ts +2 -0
- package/dist/api/routes.test.d.ts.map +1 -0
- package/dist/api/routes.test.js +77 -0
- package/dist/api/routes.test.js.map +1 -0
- package/dist/api/websocket.d.ts +25 -0
- package/dist/api/websocket.d.ts.map +1 -0
- package/dist/api/websocket.js +51 -0
- package/dist/api/websocket.js.map +1 -0
- package/dist/config-io.d.ts +7 -0
- package/dist/config-io.d.ts.map +1 -0
- package/dist/config-io.js +22 -0
- package/dist/config-io.js.map +1 -0
- package/dist/dht-query-service.d.ts +52 -0
- package/dist/dht-query-service.d.ts.map +1 -0
- package/dist/dht-query-service.js +276 -0
- package/dist/dht-query-service.js.map +1 -0
- package/dist/dht-query-service.test.d.ts +2 -0
- package/dist/dht-query-service.test.d.ts.map +1 -0
- package/dist/dht-query-service.test.js +77 -0
- package/dist/dht-query-service.test.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +20 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +65 -0
- package/dist/server.js.map +1 -0
- package/dist/status.d.ts +9 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +97 -0
- package/dist/status.js.map +1 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist-web/assets/index-CsvLvJ8Z.css +1 -0
- package/dist-web/assets/index-Da6V1FWz.js +142 -0
- package/dist-web/index.html +13 -0
- package/package.json +43 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
import Fastify from 'fastify';
|
|
4
|
+
import { mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
import { registerApiRoutes } from './routes.js';
|
|
8
|
+
function makeConfig() {
|
|
9
|
+
return {
|
|
10
|
+
identity: {
|
|
11
|
+
displayName: 'Dashboard Test Node',
|
|
12
|
+
},
|
|
13
|
+
seller: {
|
|
14
|
+
enabledProviders: ['anthropic'],
|
|
15
|
+
reserveFloor: 10,
|
|
16
|
+
maxConcurrentBuyers: 5,
|
|
17
|
+
pricing: {
|
|
18
|
+
defaults: {
|
|
19
|
+
inputUsdPerMillion: 10,
|
|
20
|
+
outputUsdPerMillion: 20,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
buyer: {
|
|
25
|
+
preferredProviders: ['anthropic'],
|
|
26
|
+
maxPricing: {
|
|
27
|
+
defaults: {
|
|
28
|
+
inputUsdPerMillion: 30,
|
|
29
|
+
outputUsdPerMillion: 60,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
minPeerReputation: 50,
|
|
33
|
+
proxyPort: 8377,
|
|
34
|
+
},
|
|
35
|
+
network: {
|
|
36
|
+
bootstrapNodes: [],
|
|
37
|
+
},
|
|
38
|
+
payments: {
|
|
39
|
+
preferredMethod: 'crypto',
|
|
40
|
+
platformFeeRate: 0.05,
|
|
41
|
+
},
|
|
42
|
+
providers: [],
|
|
43
|
+
plugins: [],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
test('PUT /api/config writes to injected config path and persists payments updates', async (t) => {
|
|
47
|
+
const tempDir = await mkdtemp(join(tmpdir(), 'dashboard-routes-test-'));
|
|
48
|
+
const configPath = join(tempDir, 'custom-config.json');
|
|
49
|
+
const app = Fastify();
|
|
50
|
+
t.after(async () => {
|
|
51
|
+
await app.close();
|
|
52
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
53
|
+
});
|
|
54
|
+
await registerApiRoutes(app, makeConfig(), undefined, configPath);
|
|
55
|
+
const response = await app.inject({
|
|
56
|
+
method: 'PUT',
|
|
57
|
+
url: '/api/config',
|
|
58
|
+
payload: {
|
|
59
|
+
payments: {
|
|
60
|
+
preferredMethod: 'crypto',
|
|
61
|
+
platformFeeRate: 0.12,
|
|
62
|
+
crypto: {
|
|
63
|
+
chainId: 'base-sepolia',
|
|
64
|
+
rpcUrl: 'http://127.0.0.1:8545',
|
|
65
|
+
escrowContractAddress: '0xabc',
|
|
66
|
+
usdcContractAddress: '0xdef',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
assert.equal(response.statusCode, 200);
|
|
72
|
+
const savedRaw = await readFile(configPath, 'utf-8');
|
|
73
|
+
const saved = JSON.parse(savedRaw);
|
|
74
|
+
assert.equal(saved.payments.platformFeeRate, 0.12);
|
|
75
|
+
assert.equal(saved.payments.crypto?.rpcUrl, 'http://127.0.0.1:8545');
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=routes.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.test.js","sourceRoot":"","sources":["../../src/api/routes.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FastifyInstance } from 'fastify';
|
|
2
|
+
/** Event types pushed to the dashboard via WebSocket */
|
|
3
|
+
export type WsEventType = 'peer_connected' | 'peer_disconnected' | 'session_started' | 'session_ended' | 'earnings_update' | 'status_change' | 'network_peers_updated';
|
|
4
|
+
export interface WsEvent {
|
|
5
|
+
type: WsEventType;
|
|
6
|
+
data: unknown;
|
|
7
|
+
timestamp: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Register the WebSocket endpoint on the Fastify server.
|
|
11
|
+
* Dashboard connects to ws://localhost:{port}/ws
|
|
12
|
+
*/
|
|
13
|
+
export declare function registerWebSocket(app: FastifyInstance): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Broadcast an event to all connected dashboard WebSocket clients.
|
|
16
|
+
* Called by the daemon when state changes occur.
|
|
17
|
+
*
|
|
18
|
+
* @param event - The event to broadcast
|
|
19
|
+
*/
|
|
20
|
+
export declare function broadcastEvent(event: WsEvent): void;
|
|
21
|
+
/**
|
|
22
|
+
* Get the number of connected dashboard clients.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getConnectedClientCount(): number;
|
|
25
|
+
//# sourceMappingURL=websocket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../src/api/websocket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI1C,wDAAwD;AACxD,MAAM,MAAM,WAAW,GACnB,gBAAgB,GAChB,mBAAmB,GACnB,iBAAiB,GACjB,eAAe,GACf,iBAAiB,GACjB,eAAe,GACf,uBAAuB,CAAC;AAE5B,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB3E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAWnD;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fastifyWebsocket from '@fastify/websocket';
|
|
2
|
+
/** Set of connected WebSocket clients */
|
|
3
|
+
const clients = new Set();
|
|
4
|
+
/**
|
|
5
|
+
* Register the WebSocket endpoint on the Fastify server.
|
|
6
|
+
* Dashboard connects to ws://localhost:{port}/ws
|
|
7
|
+
*/
|
|
8
|
+
export async function registerWebSocket(app) {
|
|
9
|
+
await app.register(fastifyWebsocket);
|
|
10
|
+
app.get('/ws', { websocket: true }, (socket, _req) => {
|
|
11
|
+
clients.add(socket);
|
|
12
|
+
socket.on('close', () => {
|
|
13
|
+
clients.delete(socket);
|
|
14
|
+
});
|
|
15
|
+
socket.on('error', () => {
|
|
16
|
+
clients.delete(socket);
|
|
17
|
+
});
|
|
18
|
+
// Send initial connection confirmation
|
|
19
|
+
socket.send(JSON.stringify({
|
|
20
|
+
type: 'status_change',
|
|
21
|
+
data: { connected: true },
|
|
22
|
+
timestamp: Date.now(),
|
|
23
|
+
}));
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Broadcast an event to all connected dashboard WebSocket clients.
|
|
28
|
+
* Called by the daemon when state changes occur.
|
|
29
|
+
*
|
|
30
|
+
* @param event - The event to broadcast
|
|
31
|
+
*/
|
|
32
|
+
export function broadcastEvent(event) {
|
|
33
|
+
const message = JSON.stringify(event);
|
|
34
|
+
for (const client of clients) {
|
|
35
|
+
if (client.readyState === client.OPEN) {
|
|
36
|
+
try {
|
|
37
|
+
client.send(message);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
clients.delete(client);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get the number of connected dashboard clients.
|
|
47
|
+
*/
|
|
48
|
+
export function getConnectedClientCount() {
|
|
49
|
+
return clients.size;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=websocket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../src/api/websocket.ts"],"names":[],"mappings":"AACA,OAAO,gBAAgB,MAAM,oBAAoB,CAAC;AAmBlD,yCAAyC;AACzC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAa,CAAC;AAErC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAoB;IAC1D,MAAM,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAErC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;QACnD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAEpB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACtB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACtB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;QAEH,uCAAuC;QACvC,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,SAAS,CAAC;YACb,IAAI,EAAE,eAAe;YACrB,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;YACzB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACJ,CAAC,CACrB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACtC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC;YACtC,IAAI,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,OAAO,CAAC,IAAI,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DashboardConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Persist the dashboard config to disk.
|
|
4
|
+
* Creates the directory if it doesn't exist.
|
|
5
|
+
*/
|
|
6
|
+
export declare function saveConfig(configPath: string, config: DashboardConfig): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=config-io.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-io.d.ts","sourceRoot":"","sources":["../src/config-io.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAYlD;;;GAGG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAI3F"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
/**
|
|
5
|
+
* Resolve a config path, expanding ~ to the user's home directory.
|
|
6
|
+
*/
|
|
7
|
+
function resolveConfigPath(configPath) {
|
|
8
|
+
if (configPath.startsWith('~')) {
|
|
9
|
+
return resolve(homedir(), configPath.slice(2));
|
|
10
|
+
}
|
|
11
|
+
return resolve(configPath);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Persist the dashboard config to disk.
|
|
15
|
+
* Creates the directory if it doesn't exist.
|
|
16
|
+
*/
|
|
17
|
+
export async function saveConfig(configPath, config) {
|
|
18
|
+
const resolved = resolveConfigPath(configPath);
|
|
19
|
+
await mkdir(dirname(resolved), { recursive: true });
|
|
20
|
+
await writeFile(resolved, JSON.stringify(config, null, 2), 'utf-8');
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=config-io.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-io.js","sourceRoot":"","sources":["../src/config-io.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC;;GAEG;AACH,SAAS,iBAAiB,CAAC,UAAkB;IAC3C,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,OAAO,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAkB,EAAE,MAAuB;IAC1E,MAAM,QAAQ,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { DashboardConfig } from './types.js';
|
|
2
|
+
import type { PeerMetadata } from '@antseed/node';
|
|
3
|
+
export interface NetworkPeer {
|
|
4
|
+
peerId: string;
|
|
5
|
+
host: string;
|
|
6
|
+
port: number;
|
|
7
|
+
providers: string[];
|
|
8
|
+
inputUsdPerMillion: number;
|
|
9
|
+
outputUsdPerMillion: number;
|
|
10
|
+
capacityMsgPerHour: number;
|
|
11
|
+
reputation: number;
|
|
12
|
+
lastSeen: number;
|
|
13
|
+
source: 'dht' | 'daemon';
|
|
14
|
+
}
|
|
15
|
+
export interface NetworkStats {
|
|
16
|
+
totalPeers: number;
|
|
17
|
+
dhtNodeCount: number;
|
|
18
|
+
dhtHealthy: boolean;
|
|
19
|
+
lastScanAt: number | null;
|
|
20
|
+
totalLookups: number;
|
|
21
|
+
successfulLookups: number;
|
|
22
|
+
lookupSuccessRate: number;
|
|
23
|
+
averageLookupLatencyMs: number;
|
|
24
|
+
healthReason: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function resolveDiscoveryProviders(config: Pick<DashboardConfig, 'seller' | 'buyer'>): string[];
|
|
27
|
+
export declare function resolveNetworkPeerProviders(metadata: Pick<PeerMetadata, 'providers'> | null | undefined, existingProviders: string[] | undefined, discoveredTopic: string): string[];
|
|
28
|
+
export declare function resolveMetadataSummaryPricing(metadata: Pick<PeerMetadata, 'providers'> | null | undefined, preferredProviders?: string[]): {
|
|
29
|
+
inputUsdPerMillion: number;
|
|
30
|
+
outputUsdPerMillion: number;
|
|
31
|
+
};
|
|
32
|
+
export declare class DHTQueryService {
|
|
33
|
+
private readonly config;
|
|
34
|
+
private dhtNode;
|
|
35
|
+
private healthMonitor;
|
|
36
|
+
private readonly metadataResolver;
|
|
37
|
+
private readonly peers;
|
|
38
|
+
private readonly events;
|
|
39
|
+
private scanTimer;
|
|
40
|
+
private lastScanAt;
|
|
41
|
+
private running;
|
|
42
|
+
constructor(config: DashboardConfig);
|
|
43
|
+
private resolveSummaryPricing;
|
|
44
|
+
start(): Promise<void>;
|
|
45
|
+
stop(): Promise<void>;
|
|
46
|
+
scanNow(): Promise<void>;
|
|
47
|
+
getNetworkPeers(): NetworkPeer[];
|
|
48
|
+
getNetworkStats(): NetworkStats;
|
|
49
|
+
onPeersUpdated(callback: (peers: NetworkPeer[]) => void): void;
|
|
50
|
+
offPeersUpdated(callback: (peers: NetworkPeer[]) => void): void;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=dht-query-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dht-query-service.d.ts","sourceRoot":"","sources":["../src/dht-query-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAOlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,KAAK,GAAG,QAAQ,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;CACtB;AAkDD,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,OAAO,CAAC,GAChD,MAAM,EAAE,CAsBV;AAmBD,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,GAAG,IAAI,GAAG,SAAS,EAC5D,iBAAiB,EAAE,MAAM,EAAE,GAAG,SAAS,EACvC,eAAe,EAAE,MAAM,GACtB,MAAM,EAAE,CAoBV;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,GAAG,IAAI,GAAG,SAAS,EAC5D,kBAAkB,GAAE,MAAM,EAAO,GAChC;IAAE,kBAAkB,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAA;CAAE,CAiB7D;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,aAAa,CAAiC;IACtD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAiD;IAClF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IACxD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,eAAe;IAInC,OAAO,CAAC,qBAAqB;IAOvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyCtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAoE9B,eAAe,IAAI,WAAW,EAAE;IAIhC,eAAe,IAAI,YAAY;IA2B/B,cAAc,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,IAAI,GAAG,IAAI;IAI9D,eAAe,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,IAAI,GAAG,IAAI;CAGhE"}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { randomBytes } from 'node:crypto';
|
|
3
|
+
import { DHTNode, DEFAULT_DHT_CONFIG, topicToInfoHash, providerTopic } from '@antseed/node/discovery';
|
|
4
|
+
import { DHTHealthMonitor } from '@antseed/node/discovery';
|
|
5
|
+
import { DEFAULT_HEALTH_THRESHOLDS } from '@antseed/node/discovery';
|
|
6
|
+
import { HttpMetadataResolver } from '@antseed/node/discovery';
|
|
7
|
+
import { mergeBootstrapNodes, OFFICIAL_BOOTSTRAP_NODES, toBootstrapConfig, parseBootstrapList } from '@antseed/node/discovery';
|
|
8
|
+
import { toPeerId } from '@antseed/node';
|
|
9
|
+
const SCAN_INTERVAL_MS = 30_000;
|
|
10
|
+
const DEFAULT_DISCOVERY_PROVIDERS = [
|
|
11
|
+
'anthropic',
|
|
12
|
+
'openai',
|
|
13
|
+
'google',
|
|
14
|
+
'claude-code',
|
|
15
|
+
'claude-oauth',
|
|
16
|
+
'openrouter',
|
|
17
|
+
'local-llm',
|
|
18
|
+
];
|
|
19
|
+
const PROVIDER_ALIAS_MAP = {
|
|
20
|
+
'@antseed/provider-anthropic': 'anthropic',
|
|
21
|
+
'antseed-provider-anthropic': 'anthropic',
|
|
22
|
+
'@antseed/provider-claude-code': 'claude-code',
|
|
23
|
+
'antseed-provider-claude-code': 'claude-code',
|
|
24
|
+
'@antseed/provider-claude-oauth': 'claude-oauth',
|
|
25
|
+
'antseed-provider-claude-oauth': 'claude-oauth',
|
|
26
|
+
'@antseed/provider-openrouter': 'openrouter',
|
|
27
|
+
'antseed-provider-openrouter': 'openrouter',
|
|
28
|
+
'@antseed/provider-local-llm': 'local-llm',
|
|
29
|
+
'antseed-provider-local-llm': 'local-llm',
|
|
30
|
+
};
|
|
31
|
+
function normalizeProviderTopicName(value) {
|
|
32
|
+
if (typeof value !== 'string') {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const raw = value.trim().toLowerCase();
|
|
36
|
+
if (!raw) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const alias = PROVIDER_ALIAS_MAP[raw];
|
|
40
|
+
if (alias) {
|
|
41
|
+
return alias;
|
|
42
|
+
}
|
|
43
|
+
if (raw.startsWith('@antseed/provider-')) {
|
|
44
|
+
return raw.slice('@antseed/provider-'.length);
|
|
45
|
+
}
|
|
46
|
+
if (raw.startsWith('antseed-provider-')) {
|
|
47
|
+
return raw.slice('antseed-provider-'.length);
|
|
48
|
+
}
|
|
49
|
+
return raw;
|
|
50
|
+
}
|
|
51
|
+
export function resolveDiscoveryProviders(config) {
|
|
52
|
+
const topics = new Set();
|
|
53
|
+
for (const candidate of config.seller.enabledProviders) {
|
|
54
|
+
const normalized = normalizeProviderTopicName(candidate);
|
|
55
|
+
if (normalized) {
|
|
56
|
+
topics.add(normalized);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
for (const candidate of config.buyer.preferredProviders) {
|
|
60
|
+
const normalized = normalizeProviderTopicName(candidate);
|
|
61
|
+
if (normalized) {
|
|
62
|
+
topics.add(normalized);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const candidate of DEFAULT_DISCOVERY_PROVIDERS) {
|
|
66
|
+
topics.add(candidate);
|
|
67
|
+
}
|
|
68
|
+
return Array.from(topics);
|
|
69
|
+
}
|
|
70
|
+
function providerNamesFromMetadata(metadata) {
|
|
71
|
+
if (!metadata?.providers || metadata.providers.length === 0) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
const providers = new Set();
|
|
75
|
+
for (const entry of metadata.providers) {
|
|
76
|
+
const normalized = normalizeProviderTopicName(entry.provider);
|
|
77
|
+
if (normalized) {
|
|
78
|
+
providers.add(normalized);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return Array.from(providers);
|
|
82
|
+
}
|
|
83
|
+
export function resolveNetworkPeerProviders(metadata, existingProviders, discoveredTopic) {
|
|
84
|
+
// Prefer explicit provider list from peer metadata when available.
|
|
85
|
+
const fromMetadata = providerNamesFromMetadata(metadata);
|
|
86
|
+
if (fromMetadata.length > 0) {
|
|
87
|
+
return fromMetadata;
|
|
88
|
+
}
|
|
89
|
+
// Otherwise accumulate prior inferred topics and current lookup topic.
|
|
90
|
+
const providers = new Set();
|
|
91
|
+
for (const provider of existingProviders ?? []) {
|
|
92
|
+
const normalized = normalizeProviderTopicName(provider);
|
|
93
|
+
if (normalized) {
|
|
94
|
+
providers.add(normalized);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const normalizedTopic = normalizeProviderTopicName(discoveredTopic);
|
|
98
|
+
if (normalizedTopic) {
|
|
99
|
+
providers.add(normalizedTopic);
|
|
100
|
+
}
|
|
101
|
+
return Array.from(providers);
|
|
102
|
+
}
|
|
103
|
+
export function resolveMetadataSummaryPricing(metadata, preferredProviders = []) {
|
|
104
|
+
if (!metadata?.providers || metadata.providers.length === 0) {
|
|
105
|
+
return { inputUsdPerMillion: 0, outputUsdPerMillion: 0 };
|
|
106
|
+
}
|
|
107
|
+
const selectedProvider = preferredProviders.length > 0
|
|
108
|
+
? metadata.providers.find((provider) => preferredProviders.includes(provider.provider)) ?? metadata.providers[0]
|
|
109
|
+
: metadata.providers[0];
|
|
110
|
+
if (!selectedProvider) {
|
|
111
|
+
return { inputUsdPerMillion: 0, outputUsdPerMillion: 0 };
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
inputUsdPerMillion: selectedProvider.defaultPricing.inputUsdPerMillion,
|
|
115
|
+
outputUsdPerMillion: selectedProvider.defaultPricing.outputUsdPerMillion,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export class DHTQueryService {
|
|
119
|
+
config;
|
|
120
|
+
dhtNode = null;
|
|
121
|
+
healthMonitor = null;
|
|
122
|
+
metadataResolver = new HttpMetadataResolver({ timeoutMs: 5000 });
|
|
123
|
+
peers = new Map();
|
|
124
|
+
events = new EventEmitter();
|
|
125
|
+
scanTimer;
|
|
126
|
+
lastScanAt = null;
|
|
127
|
+
running = false;
|
|
128
|
+
constructor(config) {
|
|
129
|
+
this.config = config;
|
|
130
|
+
}
|
|
131
|
+
resolveSummaryPricing(metadata) {
|
|
132
|
+
return resolveMetadataSummaryPricing(metadata, this.config.buyer?.preferredProviders ?? []);
|
|
133
|
+
}
|
|
134
|
+
async start() {
|
|
135
|
+
if (this.running)
|
|
136
|
+
return;
|
|
137
|
+
// Generate a random peerId for the read-only DHT node
|
|
138
|
+
const randomId = randomBytes(32).toString('hex');
|
|
139
|
+
const peerId = toPeerId(randomId);
|
|
140
|
+
const userBootstrap = this.config.network?.bootstrapNodes?.length
|
|
141
|
+
? parseBootstrapList(this.config.network.bootstrapNodes)
|
|
142
|
+
: [];
|
|
143
|
+
const allBootstrap = toBootstrapConfig(mergeBootstrapNodes(OFFICIAL_BOOTSTRAP_NODES, userBootstrap));
|
|
144
|
+
this.dhtNode = new DHTNode({
|
|
145
|
+
peerId,
|
|
146
|
+
...DEFAULT_DHT_CONFIG,
|
|
147
|
+
port: 0, // OS-assigned port — read-only, no announce
|
|
148
|
+
bootstrapNodes: allBootstrap,
|
|
149
|
+
allowPrivateIPs: true, // Allow local/private peers for development
|
|
150
|
+
});
|
|
151
|
+
await this.dhtNode.start();
|
|
152
|
+
// Dashboard DHT visibility is read-only and often runs in small local networks.
|
|
153
|
+
// Use a less strict health threshold than the full node runtime monitor.
|
|
154
|
+
this.healthMonitor = new DHTHealthMonitor(() => this.dhtNode?.getNodeCount() ?? 0, {
|
|
155
|
+
...DEFAULT_HEALTH_THRESHOLDS,
|
|
156
|
+
minNodeCount: 1,
|
|
157
|
+
minLookupSuccessRate: 0.2,
|
|
158
|
+
maxAvgLookupLatencyMs: 30_000,
|
|
159
|
+
});
|
|
160
|
+
this.running = true;
|
|
161
|
+
// Initial scan
|
|
162
|
+
this.scanNow().catch(() => { });
|
|
163
|
+
// Periodic scans
|
|
164
|
+
this.scanTimer = setInterval(() => {
|
|
165
|
+
this.scanNow().catch(() => { });
|
|
166
|
+
}, SCAN_INTERVAL_MS);
|
|
167
|
+
}
|
|
168
|
+
async stop() {
|
|
169
|
+
if (!this.running)
|
|
170
|
+
return;
|
|
171
|
+
this.running = false;
|
|
172
|
+
if (this.scanTimer) {
|
|
173
|
+
clearInterval(this.scanTimer);
|
|
174
|
+
this.scanTimer = undefined;
|
|
175
|
+
}
|
|
176
|
+
if (this.dhtNode) {
|
|
177
|
+
await this.dhtNode.stop();
|
|
178
|
+
this.dhtNode = null;
|
|
179
|
+
}
|
|
180
|
+
this.healthMonitor = null;
|
|
181
|
+
this.peers.clear();
|
|
182
|
+
}
|
|
183
|
+
async scanNow() {
|
|
184
|
+
if (!this.dhtNode || !this.healthMonitor)
|
|
185
|
+
return;
|
|
186
|
+
const topics = resolveDiscoveryProviders(this.config);
|
|
187
|
+
const discoveredPeers = new Map();
|
|
188
|
+
for (const name of topics) {
|
|
189
|
+
const topic = providerTopic(name);
|
|
190
|
+
const infoHash = topicToInfoHash(topic);
|
|
191
|
+
const startTime = Date.now();
|
|
192
|
+
try {
|
|
193
|
+
const endpoints = await this.dhtNode.lookup(infoHash);
|
|
194
|
+
const latency = Date.now() - startTime;
|
|
195
|
+
this.healthMonitor.recordLookup(endpoints.length > 0, latency);
|
|
196
|
+
for (const ep of endpoints) {
|
|
197
|
+
// Try to resolve metadata for richer peer info
|
|
198
|
+
let metadata = null;
|
|
199
|
+
try {
|
|
200
|
+
metadata = await this.metadataResolver.resolve(ep);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
// Metadata resolution failed — use basic info
|
|
204
|
+
}
|
|
205
|
+
const peerId = metadata?.peerId ?? `${ep.host}:${ep.port}`;
|
|
206
|
+
const existing = discoveredPeers.get(peerId);
|
|
207
|
+
const providers = resolveNetworkPeerProviders(metadata, existing?.providers, name);
|
|
208
|
+
// Extract summary pricing and capacity from metadata
|
|
209
|
+
const summaryPricing = this.resolveSummaryPricing(metadata);
|
|
210
|
+
let capacityMsgPerHour = 0;
|
|
211
|
+
if (metadata?.providers) {
|
|
212
|
+
for (const pa of metadata.providers) {
|
|
213
|
+
capacityMsgPerHour += pa.maxConcurrency * 60;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
discoveredPeers.set(peerId, {
|
|
217
|
+
peerId,
|
|
218
|
+
host: ep.host,
|
|
219
|
+
port: ep.port,
|
|
220
|
+
providers,
|
|
221
|
+
inputUsdPerMillion: existing?.inputUsdPerMillion || summaryPricing.inputUsdPerMillion,
|
|
222
|
+
outputUsdPerMillion: existing?.outputUsdPerMillion || summaryPricing.outputUsdPerMillion,
|
|
223
|
+
capacityMsgPerHour: existing?.capacityMsgPerHour || capacityMsgPerHour,
|
|
224
|
+
reputation: metadata ? 100 : 50, // Reputation scale is 0-100
|
|
225
|
+
lastSeen: Date.now(),
|
|
226
|
+
source: 'dht',
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
this.healthMonitor.recordLookup(false, Date.now() - startTime);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// Update cache
|
|
235
|
+
this.peers.clear();
|
|
236
|
+
for (const [id, peer] of discoveredPeers) {
|
|
237
|
+
this.peers.set(id, peer);
|
|
238
|
+
}
|
|
239
|
+
this.lastScanAt = Date.now();
|
|
240
|
+
this.events.emit('peers_updated', this.getNetworkPeers());
|
|
241
|
+
}
|
|
242
|
+
getNetworkPeers() {
|
|
243
|
+
return Array.from(this.peers.values());
|
|
244
|
+
}
|
|
245
|
+
getNetworkStats() {
|
|
246
|
+
const snapshot = this.healthMonitor?.getSnapshot();
|
|
247
|
+
const totalLookups = snapshot?.totalLookups ?? 0;
|
|
248
|
+
const successfulLookups = snapshot?.successfulLookups ?? 0;
|
|
249
|
+
const successRate = totalLookups > 0 ? successfulLookups / totalLookups : 0;
|
|
250
|
+
const nodeCount = snapshot?.nodeCount ?? 0;
|
|
251
|
+
const discoveredPeers = this.peers.size;
|
|
252
|
+
// If peers are actively discovered, consider DHT usable even if strict thresholds fail.
|
|
253
|
+
const dhtHealthy = Boolean(snapshot?.isHealthy) || discoveredPeers > 0 || nodeCount > 0;
|
|
254
|
+
const healthReason = dhtHealthy
|
|
255
|
+
? `ok (nodes=${nodeCount}, peers=${discoveredPeers}, successRate=${(successRate * 100).toFixed(0)}%)`
|
|
256
|
+
: `insufficient activity (nodes=${nodeCount}, peers=${discoveredPeers}, lookups=${totalLookups})`;
|
|
257
|
+
return {
|
|
258
|
+
totalPeers: discoveredPeers,
|
|
259
|
+
dhtNodeCount: nodeCount,
|
|
260
|
+
dhtHealthy,
|
|
261
|
+
lastScanAt: this.lastScanAt,
|
|
262
|
+
totalLookups,
|
|
263
|
+
successfulLookups,
|
|
264
|
+
lookupSuccessRate: successRate,
|
|
265
|
+
averageLookupLatencyMs: snapshot?.averageLookupLatencyMs ?? 0,
|
|
266
|
+
healthReason,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
onPeersUpdated(callback) {
|
|
270
|
+
this.events.on('peers_updated', callback);
|
|
271
|
+
}
|
|
272
|
+
offPeersUpdated(callback) {
|
|
273
|
+
this.events.off('peers_updated', callback);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=dht-query-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dht-query-service.js","sourceRoot":"","sources":["../src/dht-query-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dht-query-service.test.d.ts","sourceRoot":"","sources":["../src/dht-query-service.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
import { resolveDiscoveryProviders, resolveMetadataSummaryPricing, resolveNetworkPeerProviders } from './dht-query-service.js';
|
|
4
|
+
test('metadata default pricing maps to input/output USD per million', () => {
|
|
5
|
+
const pricing = resolveMetadataSummaryPricing({
|
|
6
|
+
providers: [
|
|
7
|
+
{
|
|
8
|
+
provider: 'anthropic',
|
|
9
|
+
models: ['claude-sonnet-4-5-20250929'],
|
|
10
|
+
defaultPricing: {
|
|
11
|
+
inputUsdPerMillion: 11,
|
|
12
|
+
outputUsdPerMillion: 33,
|
|
13
|
+
},
|
|
14
|
+
maxConcurrency: 5,
|
|
15
|
+
currentLoad: 0,
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
});
|
|
19
|
+
assert.equal(pricing.inputUsdPerMillion, 11);
|
|
20
|
+
assert.equal(pricing.outputUsdPerMillion, 33);
|
|
21
|
+
});
|
|
22
|
+
test('missing model-specific pricing still resolves provider defaults', () => {
|
|
23
|
+
const pricing = resolveMetadataSummaryPricing({
|
|
24
|
+
providers: [
|
|
25
|
+
{
|
|
26
|
+
provider: 'openai',
|
|
27
|
+
models: ['gpt-4o', 'gpt-4o-mini'],
|
|
28
|
+
defaultPricing: {
|
|
29
|
+
inputUsdPerMillion: 7,
|
|
30
|
+
outputUsdPerMillion: 21,
|
|
31
|
+
},
|
|
32
|
+
maxConcurrency: 8,
|
|
33
|
+
currentLoad: 0,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
}, ['openai']);
|
|
37
|
+
assert.equal(pricing.inputUsdPerMillion, 7);
|
|
38
|
+
assert.equal(pricing.outputUsdPerMillion, 21);
|
|
39
|
+
});
|
|
40
|
+
test('discovery providers include buyer preferred and known defaults', () => {
|
|
41
|
+
const providers = resolveDiscoveryProviders({
|
|
42
|
+
seller: { enabledProviders: [] },
|
|
43
|
+
buyer: { preferredProviders: ['claude-code'] },
|
|
44
|
+
});
|
|
45
|
+
assert.ok(providers.includes('claude-code'));
|
|
46
|
+
assert.ok(providers.includes('anthropic'));
|
|
47
|
+
assert.ok(providers.includes('openrouter'));
|
|
48
|
+
});
|
|
49
|
+
test('discovery providers normalize package aliases and dedupe', () => {
|
|
50
|
+
const providers = resolveDiscoveryProviders({
|
|
51
|
+
seller: { enabledProviders: ['@antseed/provider-claude-code', 'claude-code'] },
|
|
52
|
+
buyer: { preferredProviders: ['antseed-provider-openrouter', 'openrouter'] },
|
|
53
|
+
});
|
|
54
|
+
const claudeCodeCount = providers.filter((p) => p === 'claude-code').length;
|
|
55
|
+
const openrouterCount = providers.filter((p) => p === 'openrouter').length;
|
|
56
|
+
assert.equal(claudeCodeCount, 1);
|
|
57
|
+
assert.equal(openrouterCount, 1);
|
|
58
|
+
});
|
|
59
|
+
test('network peer providers prefer metadata providers over topic inference', () => {
|
|
60
|
+
const providers = resolveNetworkPeerProviders({
|
|
61
|
+
providers: [
|
|
62
|
+
{
|
|
63
|
+
provider: 'claude-code',
|
|
64
|
+
models: ['x'],
|
|
65
|
+
defaultPricing: { inputUsdPerMillion: 0, outputUsdPerMillion: 0 },
|
|
66
|
+
maxConcurrency: 1,
|
|
67
|
+
currentLoad: 0,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
}, ['local-llm'], 'local-llm');
|
|
71
|
+
assert.deepEqual(providers, ['claude-code']);
|
|
72
|
+
});
|
|
73
|
+
test('network peer providers fallback accumulates inferred topics when metadata is unavailable', () => {
|
|
74
|
+
const providers = resolveNetworkPeerProviders(null, ['@antseed/provider-openrouter'], 'openrouter');
|
|
75
|
+
assert.deepEqual(providers, ['openrouter']);
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=dht-query-service.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dht-query-service.test.js","sourceRoot":"","sources":["../src/dht-query-service.test.ts"],"names":[],"mappings":"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"}
|