@antseed/node 0.1.0 → 0.1.2
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/LICENSE +674 -0
- package/README.md +7 -5
- package/dist/discovery/http-metadata-resolver.d.ts +6 -0
- package/dist/discovery/http-metadata-resolver.d.ts.map +1 -1
- package/dist/discovery/http-metadata-resolver.js +32 -4
- package/dist/discovery/http-metadata-resolver.js.map +1 -1
- package/dist/discovery/peer-lookup.d.ts +1 -0
- package/dist/discovery/peer-lookup.d.ts.map +1 -1
- package/dist/discovery/peer-lookup.js +10 -25
- package/dist/discovery/peer-lookup.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/seller-provider.d.ts +13 -1
- package/dist/interfaces/seller-provider.d.ts.map +1 -1
- package/dist/node.d.ts +13 -3
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +146 -21
- package/dist/node.js.map +1 -1
- package/dist/proxy/proxy-mux.d.ts +3 -1
- package/dist/proxy/proxy-mux.d.ts.map +1 -1
- package/dist/proxy/proxy-mux.js +9 -5
- package/dist/proxy/proxy-mux.js.map +1 -1
- package/dist/types/http.d.ts +1 -0
- package/dist/types/http.d.ts.map +1 -1
- package/dist/types/http.js +1 -1
- package/dist/types/http.js.map +1 -1
- package/package.json +14 -10
- package/contracts/AntseedEscrow.sol +0 -310
- package/contracts/MockUSDC.sol +0 -64
- package/contracts/README.md +0 -102
- package/src/config/encryption.test.ts +0 -49
- package/src/config/encryption.ts +0 -53
- package/src/config/plugin-config-manager.test.ts +0 -92
- package/src/config/plugin-config-manager.ts +0 -153
- package/src/config/plugin-loader.ts +0 -90
- package/src/discovery/announcer.ts +0 -169
- package/src/discovery/bootstrap.ts +0 -57
- package/src/discovery/default-metadata-resolver.ts +0 -18
- package/src/discovery/dht-health.ts +0 -136
- package/src/discovery/dht-node.ts +0 -191
- package/src/discovery/http-metadata-resolver.ts +0 -47
- package/src/discovery/index.ts +0 -15
- package/src/discovery/metadata-codec.ts +0 -453
- package/src/discovery/metadata-resolver.ts +0 -7
- package/src/discovery/metadata-server.ts +0 -73
- package/src/discovery/metadata-validator.ts +0 -172
- package/src/discovery/peer-lookup.ts +0 -122
- package/src/discovery/peer-metadata.ts +0 -34
- package/src/discovery/peer-selector.ts +0 -134
- package/src/discovery/profile-manager.ts +0 -131
- package/src/discovery/profile-search.ts +0 -100
- package/src/discovery/reputation-verifier.ts +0 -54
- package/src/index.ts +0 -61
- package/src/interfaces/buyer-router.ts +0 -21
- package/src/interfaces/plugin.ts +0 -36
- package/src/interfaces/seller-provider.ts +0 -81
- package/src/metering/index.ts +0 -6
- package/src/metering/receipt-generator.ts +0 -105
- package/src/metering/receipt-verifier.ts +0 -102
- package/src/metering/session-tracker.ts +0 -145
- package/src/metering/storage.ts +0 -600
- package/src/metering/token-counter.ts +0 -127
- package/src/metering/usage-aggregator.ts +0 -236
- package/src/node.ts +0 -1698
- package/src/p2p/connection-auth.ts +0 -152
- package/src/p2p/connection-manager.ts +0 -916
- package/src/p2p/handshake.ts +0 -162
- package/src/p2p/ice-config.ts +0 -59
- package/src/p2p/identity.ts +0 -110
- package/src/p2p/index.ts +0 -11
- package/src/p2p/keepalive.ts +0 -118
- package/src/p2p/message-protocol.ts +0 -171
- package/src/p2p/nat-traversal.ts +0 -169
- package/src/p2p/payment-codec.ts +0 -165
- package/src/p2p/payment-mux.ts +0 -153
- package/src/p2p/reconnect.ts +0 -117
- package/src/payments/balance-manager.ts +0 -77
- package/src/payments/buyer-payment-manager.ts +0 -414
- package/src/payments/disputes.ts +0 -72
- package/src/payments/evm/escrow-client.ts +0 -263
- package/src/payments/evm/keypair.ts +0 -31
- package/src/payments/evm/signatures.ts +0 -103
- package/src/payments/evm/wallet.ts +0 -42
- package/src/payments/index.ts +0 -50
- package/src/payments/settlement.ts +0 -40
- package/src/payments/types.ts +0 -79
- package/src/proxy/index.ts +0 -3
- package/src/proxy/provider-detection.ts +0 -78
- package/src/proxy/proxy-mux.ts +0 -173
- package/src/proxy/request-codec.ts +0 -294
- package/src/reputation/index.ts +0 -6
- package/src/reputation/rating-manager.ts +0 -118
- package/src/reputation/report-manager.ts +0 -91
- package/src/reputation/trust-engine.ts +0 -120
- package/src/reputation/trust-score.ts +0 -74
- package/src/reputation/uptime-tracker.ts +0 -155
- package/src/routing/default-router.ts +0 -75
- package/src/types/bittorrent-dht.d.ts +0 -19
- package/src/types/buyer.ts +0 -37
- package/src/types/capability.ts +0 -34
- package/src/types/connection.ts +0 -29
- package/src/types/http.ts +0 -20
- package/src/types/index.ts +0 -14
- package/src/types/metering.ts +0 -175
- package/src/types/nat-api.d.ts +0 -29
- package/src/types/peer-profile.ts +0 -25
- package/src/types/peer.ts +0 -62
- package/src/types/plugin-config.ts +0 -31
- package/src/types/protocol.ts +0 -162
- package/src/types/provider.ts +0 -40
- package/src/types/rating.ts +0 -23
- package/src/types/report.ts +0 -30
- package/src/types/seller.ts +0 -38
- package/src/types/staking.ts +0 -23
- package/src/utils/debug.ts +0 -30
- package/src/utils/hex.ts +0 -14
- package/tests/balance-manager.test.ts +0 -156
- package/tests/bootstrap.test.ts +0 -108
- package/tests/buyer-payment-manager.test.ts +0 -358
- package/tests/connection-auth.test.ts +0 -87
- package/tests/default-router.test.ts +0 -148
- package/tests/evm-keypair.test.ts +0 -173
- package/tests/identity.test.ts +0 -133
- package/tests/message-protocol.test.ts +0 -212
- package/tests/metadata-codec.test.ts +0 -165
- package/tests/metadata-validator.test.ts +0 -261
- package/tests/metering-storage.test.ts +0 -244
- package/tests/payment-codec.test.ts +0 -95
- package/tests/payment-mux.test.ts +0 -191
- package/tests/peer-selector.test.ts +0 -184
- package/tests/provider-detection.test.ts +0 -107
- package/tests/proxy-mux-security.test.ts +0 -38
- package/tests/receipt.test.ts +0 -215
- package/tests/reputation-integration.test.ts +0 -195
- package/tests/request-codec.test.ts +0 -144
- package/tests/token-counter.test.ts +0 -122
- package/tsconfig.json +0 -9
- package/vitest.config.ts +0 -7
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { verifySignature, hexToBytes } from "../p2p/identity.js";
|
|
2
|
-
import type { DHTNode } from "./dht-node.js";
|
|
3
|
-
import { providerTopic, capabilityTopic, topicToInfoHash } from "./dht-node.js";
|
|
4
|
-
import type { PeerMetadata } from "./peer-metadata.js";
|
|
5
|
-
import { encodeMetadataForSigning } from "./metadata-codec.js";
|
|
6
|
-
import type { MetadataResolver } from "./metadata-resolver.js";
|
|
7
|
-
|
|
8
|
-
export interface LookupConfig {
|
|
9
|
-
dht: DHTNode;
|
|
10
|
-
metadataResolver: MetadataResolver;
|
|
11
|
-
requireValidSignature: boolean;
|
|
12
|
-
allowStaleMetadata: boolean;
|
|
13
|
-
maxAnnouncementAgeMs: number;
|
|
14
|
-
maxResults: number;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const DEFAULT_LOOKUP_CONFIG: Omit<LookupConfig, "dht" | "metadataResolver"> = {
|
|
18
|
-
requireValidSignature: true,
|
|
19
|
-
allowStaleMetadata: false,
|
|
20
|
-
maxAnnouncementAgeMs: 30 * 60 * 1000,
|
|
21
|
-
maxResults: 50,
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export interface LookupResult {
|
|
25
|
-
metadata: PeerMetadata;
|
|
26
|
-
host: string;
|
|
27
|
-
port: number;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export class PeerLookup {
|
|
31
|
-
private readonly config: LookupConfig;
|
|
32
|
-
|
|
33
|
-
constructor(config: LookupConfig) {
|
|
34
|
-
this.config = config;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async findSellers(provider: string): Promise<LookupResult[]> {
|
|
38
|
-
const topic = providerTopic(provider);
|
|
39
|
-
const infoHash = topicToInfoHash(topic);
|
|
40
|
-
const peers = await this.config.dht.lookup(infoHash);
|
|
41
|
-
|
|
42
|
-
const results: LookupResult[] = [];
|
|
43
|
-
for (const peer of peers) {
|
|
44
|
-
if (results.length >= this.config.maxResults) {
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const metadata = await this.config.metadataResolver.resolve(peer);
|
|
49
|
-
if (metadata === null) {
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (this.config.requireValidSignature) {
|
|
54
|
-
const valid = await this.verifyMetadataSignature(metadata);
|
|
55
|
-
if (!valid) {
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (!this.config.allowStaleMetadata && this.isStale(metadata)) {
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
results.push({
|
|
65
|
-
metadata,
|
|
66
|
-
host: peer.host,
|
|
67
|
-
port: peer.port,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return results;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async findByCapability(capability: string, name?: string): Promise<LookupResult[]> {
|
|
75
|
-
const topic = capabilityTopic(capability, name);
|
|
76
|
-
const infoHash = topicToInfoHash(topic);
|
|
77
|
-
const peers = await this.config.dht.lookup(infoHash);
|
|
78
|
-
|
|
79
|
-
const results: LookupResult[] = [];
|
|
80
|
-
for (const peer of peers) {
|
|
81
|
-
if (results.length >= this.config.maxResults) {
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const metadata = await this.config.metadataResolver.resolve(peer);
|
|
86
|
-
if (metadata === null) {
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (this.config.requireValidSignature) {
|
|
91
|
-
const valid = await this.verifyMetadataSignature(metadata);
|
|
92
|
-
if (!valid) {
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (!this.config.allowStaleMetadata && this.isStale(metadata)) {
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
results.push({
|
|
102
|
-
metadata,
|
|
103
|
-
host: peer.host,
|
|
104
|
-
port: peer.port,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return results;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async verifyMetadataSignature(metadata: PeerMetadata): Promise<boolean> {
|
|
112
|
-
const dataToVerify = encodeMetadataForSigning(metadata);
|
|
113
|
-
const publicKey = hexToBytes(metadata.peerId);
|
|
114
|
-
const signature = hexToBytes(metadata.signature);
|
|
115
|
-
return verifySignature(publicKey, signature, dataToVerify);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
isStale(metadata: PeerMetadata): boolean {
|
|
119
|
-
const age = Date.now() - metadata.timestamp;
|
|
120
|
-
return age > this.config.maxAnnouncementAgeMs;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { PeerId } from "../types/peer.js";
|
|
2
|
-
import type { PeerOffering } from "../types/capability.js";
|
|
3
|
-
|
|
4
|
-
export const METADATA_VERSION = 2;
|
|
5
|
-
|
|
6
|
-
export interface TokenPricingUsdPerMillion {
|
|
7
|
-
inputUsdPerMillion: number;
|
|
8
|
-
outputUsdPerMillion: number;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface ProviderAnnouncement {
|
|
12
|
-
provider: string;
|
|
13
|
-
models: string[];
|
|
14
|
-
defaultPricing: TokenPricingUsdPerMillion;
|
|
15
|
-
modelPricing?: Record<string, TokenPricingUsdPerMillion>;
|
|
16
|
-
maxConcurrency: number;
|
|
17
|
-
currentLoad: number;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface PeerMetadata {
|
|
21
|
-
peerId: PeerId;
|
|
22
|
-
version: number;
|
|
23
|
-
providers: ProviderAnnouncement[];
|
|
24
|
-
offerings?: PeerOffering[];
|
|
25
|
-
region: string;
|
|
26
|
-
timestamp: number;
|
|
27
|
-
stakeAmountUSDC?: number;
|
|
28
|
-
trustScore?: number;
|
|
29
|
-
evmAddress?: string;
|
|
30
|
-
onChainReputation?: number;
|
|
31
|
-
onChainSessionCount?: number;
|
|
32
|
-
onChainDisputeCount?: number;
|
|
33
|
-
signature: string;
|
|
34
|
-
}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
export interface ScoringWeights {
|
|
2
|
-
price: number;
|
|
3
|
-
capacity: number;
|
|
4
|
-
latency: number;
|
|
5
|
-
reputation: number;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export const DEFAULT_SCORING_WEIGHTS: ScoringWeights = {
|
|
9
|
-
price: 0.35,
|
|
10
|
-
capacity: 0.25,
|
|
11
|
-
latency: 0.25,
|
|
12
|
-
reputation: 0.15,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export interface PeerCandidate {
|
|
16
|
-
peerId: string;
|
|
17
|
-
region: string;
|
|
18
|
-
inputUsdPerMillion: number;
|
|
19
|
-
maxConcurrency: number;
|
|
20
|
-
currentLoad: number;
|
|
21
|
-
latencyMs: number;
|
|
22
|
-
reputation: number;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface ScoredPeer {
|
|
26
|
-
candidate: PeerCandidate;
|
|
27
|
-
score: number;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Score a single peer candidate.
|
|
32
|
-
*
|
|
33
|
-
* - priceScore: cheapestInputPrice / candidate.inputUsdPerMillion (capped at 1.0)
|
|
34
|
-
* - capacityScore: (maxConcurrency - currentLoad) / maxConcurrency
|
|
35
|
-
* - latencyScore: 1 - (latencyMs / 15000), clamped to [0, 1]
|
|
36
|
-
* - reputationScore: candidate.reputation (expected 0..1)
|
|
37
|
-
*/
|
|
38
|
-
export function scorePeer(
|
|
39
|
-
candidate: PeerCandidate,
|
|
40
|
-
cheapestInputPrice: number,
|
|
41
|
-
weights: ScoringWeights = DEFAULT_SCORING_WEIGHTS
|
|
42
|
-
): number {
|
|
43
|
-
// Price score
|
|
44
|
-
const priceScore =
|
|
45
|
-
candidate.inputUsdPerMillion > 0
|
|
46
|
-
? Math.min(cheapestInputPrice / candidate.inputUsdPerMillion, 1.0)
|
|
47
|
-
: 1.0;
|
|
48
|
-
|
|
49
|
-
// Capacity score
|
|
50
|
-
const capacityScore =
|
|
51
|
-
candidate.maxConcurrency > 0
|
|
52
|
-
? (candidate.maxConcurrency - candidate.currentLoad) /
|
|
53
|
-
candidate.maxConcurrency
|
|
54
|
-
: 0;
|
|
55
|
-
|
|
56
|
-
// Latency score
|
|
57
|
-
const latencyScore = Math.max(0, Math.min(1, 1 - candidate.latencyMs / 15000));
|
|
58
|
-
|
|
59
|
-
// Reputation score
|
|
60
|
-
const reputationScore = Math.max(0, Math.min(1, candidate.reputation));
|
|
61
|
-
|
|
62
|
-
const score =
|
|
63
|
-
weights.price * priceScore +
|
|
64
|
-
weights.capacity * capacityScore +
|
|
65
|
-
weights.latency * latencyScore +
|
|
66
|
-
weights.reputation * reputationScore;
|
|
67
|
-
|
|
68
|
-
return Math.max(0, Math.min(1, score));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function rankPeers(
|
|
72
|
-
candidates: PeerCandidate[],
|
|
73
|
-
weights: ScoringWeights = DEFAULT_SCORING_WEIGHTS
|
|
74
|
-
): ScoredPeer[] {
|
|
75
|
-
if (candidates.length === 0) {
|
|
76
|
-
return [];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const cheapestInputPrice = Math.min(
|
|
80
|
-
...candidates.map((c) => c.inputUsdPerMillion).filter((p) => p > 0)
|
|
81
|
-
);
|
|
82
|
-
const effectiveCheapest = Number.isFinite(cheapestInputPrice)
|
|
83
|
-
? cheapestInputPrice
|
|
84
|
-
: 0;
|
|
85
|
-
|
|
86
|
-
const scored: ScoredPeer[] = candidates.map((candidate) => ({
|
|
87
|
-
candidate,
|
|
88
|
-
score: scorePeer(candidate, effectiveCheapest, weights),
|
|
89
|
-
}));
|
|
90
|
-
|
|
91
|
-
scored.sort((a, b) => b.score - a.score);
|
|
92
|
-
return scored;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function selectBestPeer(
|
|
96
|
-
candidates: PeerCandidate[],
|
|
97
|
-
weights: ScoringWeights = DEFAULT_SCORING_WEIGHTS
|
|
98
|
-
): ScoredPeer | null {
|
|
99
|
-
const ranked = rankPeers(candidates, weights);
|
|
100
|
-
return ranked[0] ?? null;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function selectDiversePeers(
|
|
104
|
-
candidates: PeerCandidate[],
|
|
105
|
-
count: number,
|
|
106
|
-
weights: ScoringWeights = DEFAULT_SCORING_WEIGHTS
|
|
107
|
-
): ScoredPeer[] {
|
|
108
|
-
const ranked = rankPeers(candidates, weights);
|
|
109
|
-
if (ranked.length <= count) {
|
|
110
|
-
return ranked;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const selected: ScoredPeer[] = [];
|
|
114
|
-
const seenRegions = new Set<string>();
|
|
115
|
-
|
|
116
|
-
// First pass: pick the best from each unique region
|
|
117
|
-
for (const peer of ranked) {
|
|
118
|
-
if (selected.length >= count) break;
|
|
119
|
-
if (!seenRegions.has(peer.candidate.region)) {
|
|
120
|
-
seenRegions.add(peer.candidate.region);
|
|
121
|
-
selected.push(peer);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Second pass: fill remaining slots by score
|
|
126
|
-
for (const peer of ranked) {
|
|
127
|
-
if (selected.length >= count) break;
|
|
128
|
-
if (!selected.includes(peer)) {
|
|
129
|
-
selected.push(peer);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return selected;
|
|
134
|
-
}
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { createHash } from 'node:crypto';
|
|
4
|
-
import type { PeerId } from '../types/peer.js';
|
|
5
|
-
import type { PeerProfile, ProfileCapability } from '../types/peer-profile.js';
|
|
6
|
-
import type { Identity } from '../p2p/identity.js';
|
|
7
|
-
import { signData } from '../p2p/identity.js';
|
|
8
|
-
import { bytesToHex } from '../utils/hex.js';
|
|
9
|
-
|
|
10
|
-
export interface ProfileManagerConfig {
|
|
11
|
-
configDir: string;
|
|
12
|
-
identity?: Identity;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export class ProfileManager {
|
|
16
|
-
private readonly configDir: string;
|
|
17
|
-
private readonly identity: Identity | undefined;
|
|
18
|
-
private profile: PeerProfile | null = null;
|
|
19
|
-
|
|
20
|
-
constructor(config: ProfileManagerConfig) {
|
|
21
|
-
this.configDir = config.configDir;
|
|
22
|
-
this.identity = config.identity;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Create a new peer profile.
|
|
27
|
-
*/
|
|
28
|
-
createProfile(data: {
|
|
29
|
-
displayName: string;
|
|
30
|
-
description: string;
|
|
31
|
-
tags?: string[];
|
|
32
|
-
capabilities?: ProfileCapability[];
|
|
33
|
-
region?: string;
|
|
34
|
-
languages?: string[];
|
|
35
|
-
website?: string;
|
|
36
|
-
avatar?: string;
|
|
37
|
-
}): PeerProfile {
|
|
38
|
-
if (!this.identity) {
|
|
39
|
-
throw new Error('Identity required to create profile');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const now = Date.now();
|
|
43
|
-
this.profile = {
|
|
44
|
-
peerId: this.identity.peerId as PeerId,
|
|
45
|
-
displayName: data.displayName,
|
|
46
|
-
description: data.description,
|
|
47
|
-
tags: data.tags ?? [],
|
|
48
|
-
capabilities: data.capabilities ?? ['inference'],
|
|
49
|
-
region: data.region ?? 'unknown',
|
|
50
|
-
languages: data.languages ?? ['en'],
|
|
51
|
-
website: data.website,
|
|
52
|
-
avatar: data.avatar,
|
|
53
|
-
createdAt: now,
|
|
54
|
-
updatedAt: now,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
return this.profile;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Update an existing profile.
|
|
62
|
-
*/
|
|
63
|
-
updateProfile(updates: Partial<Omit<PeerProfile, 'peerId' | 'createdAt'>>): PeerProfile {
|
|
64
|
-
if (!this.profile) {
|
|
65
|
-
throw new Error('No profile exists — call createProfile first');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
this.profile = {
|
|
69
|
-
...this.profile,
|
|
70
|
-
...updates,
|
|
71
|
-
peerId: this.profile.peerId, // immutable
|
|
72
|
-
createdAt: this.profile.createdAt, // immutable
|
|
73
|
-
updatedAt: Date.now(),
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
return this.profile;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Get the current profile.
|
|
81
|
-
*/
|
|
82
|
-
getProfile(): PeerProfile | null {
|
|
83
|
-
return this.profile;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Get SHA-256 hash of the profile for metadata announcements.
|
|
88
|
-
*/
|
|
89
|
-
getProfileHash(): string {
|
|
90
|
-
if (!this.profile) return '';
|
|
91
|
-
const json = JSON.stringify(this.profile);
|
|
92
|
-
return createHash('sha256').update(json).digest('hex');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Sign the profile hash with the identity's private key.
|
|
97
|
-
*/
|
|
98
|
-
async getProfileSignature(): Promise<string> {
|
|
99
|
-
if (!this.identity || !this.profile) {
|
|
100
|
-
throw new Error('Identity and profile required for signing');
|
|
101
|
-
}
|
|
102
|
-
const hash = this.getProfileHash();
|
|
103
|
-
const hashBytes = new TextEncoder().encode(hash);
|
|
104
|
-
const signature = await signData(this.identity.privateKey, hashBytes);
|
|
105
|
-
return bytesToHex(signature);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Save profile to disk.
|
|
110
|
-
*/
|
|
111
|
-
async save(): Promise<void> {
|
|
112
|
-
if (!this.profile) return;
|
|
113
|
-
await mkdir(this.configDir, { recursive: true });
|
|
114
|
-
const filePath = join(this.configDir, 'profile.json');
|
|
115
|
-
await writeFile(filePath, JSON.stringify(this.profile, null, 2), 'utf-8');
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Load profile from disk.
|
|
120
|
-
*/
|
|
121
|
-
async load(): Promise<void> {
|
|
122
|
-
const filePath = join(this.configDir, 'profile.json');
|
|
123
|
-
try {
|
|
124
|
-
const raw = await readFile(filePath, 'utf-8');
|
|
125
|
-
this.profile = JSON.parse(raw) as PeerProfile;
|
|
126
|
-
} catch {
|
|
127
|
-
// File doesn't exist — no profile yet
|
|
128
|
-
this.profile = null;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import type { PeerProfile, ProfileCapability } from '../types/peer-profile.js';
|
|
2
|
-
|
|
3
|
-
export interface ProfileSearchQuery {
|
|
4
|
-
capability?: ProfileCapability;
|
|
5
|
-
tags?: string[];
|
|
6
|
-
region?: string;
|
|
7
|
-
text?: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface ProfileSearchResult {
|
|
11
|
-
profile: PeerProfile;
|
|
12
|
-
relevanceScore: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* In-memory search index for cached peer profiles.
|
|
17
|
-
*/
|
|
18
|
-
export class ProfileSearchIndex {
|
|
19
|
-
private profiles: Map<string, PeerProfile> = new Map();
|
|
20
|
-
|
|
21
|
-
addProfile(profile: PeerProfile): void {
|
|
22
|
-
this.profiles.set(profile.peerId, profile);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
removeProfile(peerId: string): void {
|
|
26
|
-
this.profiles.delete(peerId);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
getProfile(peerId: string): PeerProfile | null {
|
|
30
|
-
return this.profiles.get(peerId) ?? null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
getAllProfiles(): PeerProfile[] {
|
|
34
|
-
return Array.from(this.profiles.values());
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Search profiles with relevance scoring.
|
|
39
|
-
*/
|
|
40
|
-
search(query: ProfileSearchQuery): ProfileSearchResult[] {
|
|
41
|
-
const results: ProfileSearchResult[] = [];
|
|
42
|
-
|
|
43
|
-
for (const profile of this.profiles.values()) {
|
|
44
|
-
let score = 0;
|
|
45
|
-
|
|
46
|
-
// Filter by capability (hard filter)
|
|
47
|
-
if (query.capability) {
|
|
48
|
-
if (!profile.capabilities.includes(query.capability)) continue;
|
|
49
|
-
score += 10;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Filter by region (boost score)
|
|
53
|
-
if (query.region) {
|
|
54
|
-
if (profile.region.toLowerCase() === query.region.toLowerCase()) {
|
|
55
|
-
score += 5;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Tag matching (boost score)
|
|
60
|
-
if (query.tags && query.tags.length > 0) {
|
|
61
|
-
const profileTags = new Set(profile.tags.map(t => t.toLowerCase()));
|
|
62
|
-
let tagMatches = 0;
|
|
63
|
-
for (const tag of query.tags) {
|
|
64
|
-
if (profileTags.has(tag.toLowerCase())) {
|
|
65
|
-
tagMatches++;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
if (tagMatches > 0) {
|
|
69
|
-
score += tagMatches * 3;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Text search in name and description
|
|
74
|
-
if (query.text) {
|
|
75
|
-
const text = query.text.toLowerCase();
|
|
76
|
-
if (profile.displayName.toLowerCase().includes(text)) {
|
|
77
|
-
score += 8;
|
|
78
|
-
}
|
|
79
|
-
if (profile.description.toLowerCase().includes(text)) {
|
|
80
|
-
score += 4;
|
|
81
|
-
}
|
|
82
|
-
if (profile.tags.some(t => t.toLowerCase().includes(text))) {
|
|
83
|
-
score += 2;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (score > 0) {
|
|
88
|
-
results.push({ profile, relevanceScore: score });
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Sort by relevance (descending)
|
|
93
|
-
results.sort((a, b) => b.relevanceScore - a.relevanceScore);
|
|
94
|
-
return results;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
get size(): number {
|
|
98
|
-
return this.profiles.size;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import type { BaseEscrowClient } from "../payments/evm/escrow-client.js";
|
|
2
|
-
import type { PeerMetadata } from "./peer-metadata.js";
|
|
3
|
-
|
|
4
|
-
export interface ReputationVerification {
|
|
5
|
-
/** Whether the claimed reputation matches on-chain data. */
|
|
6
|
-
valid: boolean;
|
|
7
|
-
/** The actual on-chain reputation score (weighted average). */
|
|
8
|
-
actualReputation: number;
|
|
9
|
-
/** The actual on-chain session count. */
|
|
10
|
-
actualSessionCount: number;
|
|
11
|
-
/** The actual on-chain dispute count. */
|
|
12
|
-
actualDisputeCount: number;
|
|
13
|
-
/** The claimed on-chain reputation score from metadata. */
|
|
14
|
-
claimedReputation?: number;
|
|
15
|
-
/** The claimed on-chain session count from metadata. */
|
|
16
|
-
claimedSessionCount?: number;
|
|
17
|
-
/** The claimed on-chain dispute count from metadata. */
|
|
18
|
-
claimedDisputeCount?: number;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Verify a peer's claimed on-chain reputation against the Base contract.
|
|
23
|
-
* Queries the escrow contract using the peer's evmAddress and compares
|
|
24
|
-
* claimed vs actual reputation values.
|
|
25
|
-
*/
|
|
26
|
-
export async function verifyReputation(
|
|
27
|
-
escrowClient: BaseEscrowClient,
|
|
28
|
-
metadata: PeerMetadata,
|
|
29
|
-
): Promise<ReputationVerification> {
|
|
30
|
-
if (!metadata.evmAddress) {
|
|
31
|
-
throw new Error("Metadata does not contain an evmAddress");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const reputation = await escrowClient.getReputation(metadata.evmAddress);
|
|
35
|
-
|
|
36
|
-
const actualReputation = reputation.weightedAverage;
|
|
37
|
-
const actualSessionCount = reputation.sessionCount;
|
|
38
|
-
const actualDisputeCount = reputation.disputeCount;
|
|
39
|
-
|
|
40
|
-
const valid =
|
|
41
|
-
metadata.onChainReputation === actualReputation &&
|
|
42
|
-
metadata.onChainSessionCount === actualSessionCount &&
|
|
43
|
-
metadata.onChainDisputeCount === actualDisputeCount;
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
valid,
|
|
47
|
-
actualReputation,
|
|
48
|
-
actualSessionCount,
|
|
49
|
-
actualDisputeCount,
|
|
50
|
-
claimedReputation: metadata.onChainReputation,
|
|
51
|
-
claimedSessionCount: metadata.onChainSessionCount,
|
|
52
|
-
claimedDisputeCount: metadata.onChainDisputeCount,
|
|
53
|
-
};
|
|
54
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// Main facade
|
|
2
|
-
export { AntseedNode, type NodeConfig, type BuyerPaymentConfig, type NodePaymentsConfig } from './node.js';
|
|
3
|
-
export type { Provider, TaskRequest, TaskEvent, SkillRequest, SkillResponse } from './interfaces/seller-provider.js';
|
|
4
|
-
export type { Router } from './interfaces/buyer-router.js';
|
|
5
|
-
|
|
6
|
-
// Types (re-export everything)
|
|
7
|
-
export * from './types/index.js';
|
|
8
|
-
|
|
9
|
-
// Submodule re-exports (commonly used)
|
|
10
|
-
export { loadOrCreateIdentity, type Identity } from './p2p/identity.js';
|
|
11
|
-
export { DHTNode, DEFAULT_DHT_CONFIG } from './discovery/dht-node.js';
|
|
12
|
-
export { OFFICIAL_BOOTSTRAP_NODES, mergeBootstrapNodes, toBootstrapConfig } from './discovery/bootstrap.js';
|
|
13
|
-
export { type PeerMetadata, type ProviderAnnouncement } from './discovery/peer-metadata.js';
|
|
14
|
-
export { MetadataServer, type MetadataServerConfig } from './discovery/metadata-server.js';
|
|
15
|
-
export { MeteringStorage } from './metering/storage.js';
|
|
16
|
-
export { BalanceManager } from './payments/balance-manager.js';
|
|
17
|
-
export { BaseEscrowClient, type BaseEscrowConfig } from './payments/evm/escrow-client.js';
|
|
18
|
-
export { identityToEvmWallet, identityToEvmAddress } from './payments/evm/keypair.js';
|
|
19
|
-
export { NatTraversal, type NatMapping, type NatTraversalResult } from './p2p/nat-traversal.js';
|
|
20
|
-
export { BuyerPaymentManager } from './payments/buyer-payment-manager.js';
|
|
21
|
-
export type { BuyerSessionState, BuyerSessionStatus } from './payments/buyer-payment-manager.js';
|
|
22
|
-
export { ProxyMux } from './proxy/proxy-mux.js';
|
|
23
|
-
export { resolveProvider } from './proxy/provider-detection.js';
|
|
24
|
-
export { DefaultRouter, type DefaultRouterConfig } from './routing/default-router.js';
|
|
25
|
-
|
|
26
|
-
export type { AntseedPlugin, AntseedProviderPlugin, AntseedRouterPlugin, PluginConfigKey, ConfigField } from './interfaces/plugin.js'
|
|
27
|
-
export { ProfileManager } from './discovery/profile-manager.js';
|
|
28
|
-
export type { PeerProfile, ProfileCapability } from './types/peer-profile.js';
|
|
29
|
-
|
|
30
|
-
// Reputation
|
|
31
|
-
export { TrustScoreEngine } from './reputation/trust-engine.js';
|
|
32
|
-
export { UptimeTracker } from './reputation/uptime-tracker.js';
|
|
33
|
-
export { computeTrustScore, DEFAULT_TRUST_WEIGHTS } from './reputation/trust-score.js';
|
|
34
|
-
export type { TrustScore, TrustComponents } from './reputation/trust-score.js';
|
|
35
|
-
export type { UptimeWindow, PeerUptimeRecord } from './reputation/uptime-tracker.js';
|
|
36
|
-
export { ReportManager } from './reputation/report-manager.js';
|
|
37
|
-
export type { PeerReport, ReportReason, ReportEvidence, ReportStatus } from './types/report.js';
|
|
38
|
-
export { RatingManager } from './reputation/rating-manager.js';
|
|
39
|
-
export type { PeerRating, RatingDimension, AggregateRating } from './types/rating.js';
|
|
40
|
-
|
|
41
|
-
// Profile search
|
|
42
|
-
export { ProfileSearchIndex } from './discovery/profile-search.js';
|
|
43
|
-
export type { ProfileSearchQuery, ProfileSearchResult } from './discovery/profile-search.js';
|
|
44
|
-
|
|
45
|
-
// Plugin config & loading
|
|
46
|
-
export { encryptValue, decryptValue, deriveMachineKey, generateSalt } from './config/encryption.js'
|
|
47
|
-
export {
|
|
48
|
-
loadPluginConfig,
|
|
49
|
-
savePluginConfig,
|
|
50
|
-
addInstance,
|
|
51
|
-
removeInstance,
|
|
52
|
-
getInstance,
|
|
53
|
-
getInstances,
|
|
54
|
-
updateInstanceConfig,
|
|
55
|
-
} from './config/plugin-config-manager.js'
|
|
56
|
-
export {
|
|
57
|
-
loadPluginModule,
|
|
58
|
-
loadAllPlugins,
|
|
59
|
-
type LoadedProvider,
|
|
60
|
-
type LoadedRouter,
|
|
61
|
-
} from './config/plugin-loader.js'
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { PeerInfo } from '../types/peer.js';
|
|
2
|
-
import type { SerializedHttpRequest } from '../types/http.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Interface that buyer nodes implement for peer selection.
|
|
6
|
-
*
|
|
7
|
-
* The SDK discovers available sellers via DHT. Your router decides
|
|
8
|
-
* which seller to send each request to based on price, latency,
|
|
9
|
-
* reputation, capacity, or any custom logic.
|
|
10
|
-
*
|
|
11
|
-
* If you don't provide a router, the SDK uses a default that selects
|
|
12
|
-
* the cheapest peer with reputation above a minimum threshold.
|
|
13
|
-
*/
|
|
14
|
-
export interface Router {
|
|
15
|
-
selectPeer(req: SerializedHttpRequest, peers: PeerInfo[]): PeerInfo | null;
|
|
16
|
-
onResult(peer: PeerInfo, result: {
|
|
17
|
-
success: boolean;
|
|
18
|
-
latencyMs: number;
|
|
19
|
-
tokens: number;
|
|
20
|
-
}): void;
|
|
21
|
-
}
|
package/src/interfaces/plugin.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { Provider } from './seller-provider.js'
|
|
2
|
-
import type { Router } from './buyer-router.js'
|
|
3
|
-
|
|
4
|
-
export interface ConfigField {
|
|
5
|
-
key: string
|
|
6
|
-
label: string
|
|
7
|
-
type: 'string' | 'number' | 'boolean' | 'secret' | 'string[]'
|
|
8
|
-
required?: boolean
|
|
9
|
-
default?: unknown
|
|
10
|
-
description?: string
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/** @deprecated Use ConfigField instead */
|
|
14
|
-
export type PluginConfigKey = ConfigField
|
|
15
|
-
|
|
16
|
-
export interface AntseedPluginBase {
|
|
17
|
-
name: string
|
|
18
|
-
displayName: string
|
|
19
|
-
version: string
|
|
20
|
-
description: string
|
|
21
|
-
configSchema?: ConfigField[]
|
|
22
|
-
/** @deprecated Use configSchema instead */
|
|
23
|
-
configKeys?: ConfigField[]
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface AntseedProviderPlugin extends AntseedPluginBase {
|
|
27
|
-
type: 'provider'
|
|
28
|
-
createProvider(config: Record<string, string>): Provider | Promise<Provider>
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface AntseedRouterPlugin extends AntseedPluginBase {
|
|
32
|
-
type: 'router'
|
|
33
|
-
createRouter(config: Record<string, string>): Router | Promise<Router>
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export type AntseedPlugin = AntseedProviderPlugin | AntseedRouterPlugin
|