@iicp/client 0.5.7 → 0.7.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/dist/availability.d.ts +30 -0
- package/dist/availability.d.ts.map +1 -0
- package/dist/availability.js +64 -0
- package/dist/availability.js.map +1 -0
- package/dist/backends/base.d.ts +35 -0
- package/dist/backends/base.d.ts.map +1 -0
- package/dist/backends/base.js +97 -0
- package/dist/backends/base.js.map +1 -0
- package/dist/backends/index.d.ts +13 -0
- package/dist/backends/index.d.ts.map +1 -0
- package/dist/backends/index.js +30 -0
- package/dist/backends/index.js.map +1 -0
- package/dist/backends/llamacpp.d.ts +18 -0
- package/dist/backends/llamacpp.d.ts.map +1 -0
- package/dist/backends/llamacpp.js +17 -0
- package/dist/backends/llamacpp.js.map +1 -0
- package/dist/backends/openai_compat.d.ts +6 -10
- package/dist/backends/openai_compat.d.ts.map +1 -1
- package/dist/backends/openai_compat.js +5 -78
- package/dist/backends/openai_compat.js.map +1 -1
- package/dist/backends/vllm.d.ts +19 -0
- package/dist/backends/vllm.d.ts.map +1 -0
- package/dist/backends/vllm.js +17 -0
- package/dist/backends/vllm.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +34 -2
- package/dist/cli.js.map +1 -1
- package/dist/idempotency.d.ts +17 -0
- package/dist/idempotency.d.ts.map +1 -0
- package/dist/idempotency.js +39 -0
- package/dist/idempotency.js.map +1 -0
- package/dist/iicp_tcp.d.ts +4 -1
- package/dist/iicp_tcp.d.ts.map +1 -1
- package/dist/iicp_tcp.js +3 -0
- package/dist/iicp_tcp.js.map +1 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -1
- package/dist/index.js.map +1 -1
- package/dist/nat_detection.d.ts +4 -0
- package/dist/nat_detection.d.ts.map +1 -1
- package/dist/nat_detection.js +19 -0
- package/dist/nat_detection.js.map +1 -1
- package/dist/node.d.ts +45 -1
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +349 -59
- package/dist/node.js.map +1 -1
- package/dist/otel_tracer.d.ts +26 -0
- package/dist/otel_tracer.d.ts.map +1 -0
- package/dist/otel_tracer.js +96 -0
- package/dist/otel_tracer.js.map +1 -0
- package/dist/peer_manager.d.ts +54 -0
- package/dist/peer_manager.d.ts.map +1 -0
- package/dist/peer_manager.js +184 -0
- package/dist/peer_manager.js.map +1 -0
- package/dist/relay_session.d.ts +42 -0
- package/dist/relay_session.d.ts.map +1 -0
- package/dist/relay_session.js +276 -0
- package/dist/relay_session.js.map +1 -0
- package/dist/relay_worker_client.d.ts +37 -0
- package/dist/relay_worker_client.d.ts.map +1 -0
- package/dist/relay_worker_client.js +216 -0
- package/dist/relay_worker_client.js.map +1 -0
- package/dist/scheduler.d.ts +23 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +42 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/token_validator.d.ts +15 -0
- package/dist/token_validator.d.ts.map +1 -0
- package/dist/token_validator.js +34 -0
- package/dist/token_validator.js.map +1 -0
- package/dist/trust_auditor.d.ts +34 -0
- package/dist/trust_auditor.d.ts.map +1 -0
- package/dist/trust_auditor.js +123 -0
- package/dist/trust_auditor.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenTelemetry span helpers for IICP SDK nodes — ADR-014 TRACE-01/TRACE-02.
|
|
3
|
+
*
|
|
4
|
+
* Node-side spans:
|
|
5
|
+
* iicp.task.validate (TRACE-01) — request parsing, nonce check, auth
|
|
6
|
+
* iicp.task.execute (TRACE-02) — handler dispatch and response
|
|
7
|
+
*
|
|
8
|
+
* Behaviour:
|
|
9
|
+
* - When @opentelemetry/api is installed AND OTEL_EXPORTER_OTLP_ENDPOINT is set:
|
|
10
|
+
* exports spans to the configured collector via OTLP/HTTP.
|
|
11
|
+
* - Otherwise: uses a no-op tracer — call sites need no conditionals.
|
|
12
|
+
*
|
|
13
|
+
* W3C traceparent propagation is handled in node.ts at the HTTP layer; this
|
|
14
|
+
* module manages the span lifecycle within the node process.
|
|
15
|
+
*/
|
|
16
|
+
interface SpanLike {
|
|
17
|
+
setAttribute(key: string, value: string | number | boolean): void;
|
|
18
|
+
recordException(err: Error): void;
|
|
19
|
+
end(): void;
|
|
20
|
+
}
|
|
21
|
+
/** TRACE-01: iicp.task.validate — wraps request parsing and auth check. */
|
|
22
|
+
export declare function withTaskValidateSpan<T>(taskId: string, fn: (span: SpanLike) => T): Promise<T>;
|
|
23
|
+
/** TRACE-02: iicp.task.execute — wraps handler dispatch and response. */
|
|
24
|
+
export declare function withTaskExecuteSpan<T>(taskId: string, intent: string, fn: (span: SpanLike) => Promise<T>): Promise<T>;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=otel_tracer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel_tracer.d.ts","sourceRoot":"","sources":["../src/otel_tracer.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;GAcG;AAEH,UAAU,QAAQ;IAChB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IAClE,eAAe,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,CAAC;IAClC,GAAG,IAAI,IAAI,CAAC;CACb;AAqDD,2EAA2E;AAC3E,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CASnG;AAED,yEAAyE;AACzE,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAa3H"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* OpenTelemetry span helpers for IICP SDK nodes — ADR-014 TRACE-01/TRACE-02.
|
|
5
|
+
*
|
|
6
|
+
* Node-side spans:
|
|
7
|
+
* iicp.task.validate (TRACE-01) — request parsing, nonce check, auth
|
|
8
|
+
* iicp.task.execute (TRACE-02) — handler dispatch and response
|
|
9
|
+
*
|
|
10
|
+
* Behaviour:
|
|
11
|
+
* - When @opentelemetry/api is installed AND OTEL_EXPORTER_OTLP_ENDPOINT is set:
|
|
12
|
+
* exports spans to the configured collector via OTLP/HTTP.
|
|
13
|
+
* - Otherwise: uses a no-op tracer — call sites need no conditionals.
|
|
14
|
+
*
|
|
15
|
+
* W3C traceparent propagation is handled in node.ts at the HTTP layer; this
|
|
16
|
+
* module manages the span lifecycle within the node process.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.withTaskValidateSpan = withTaskValidateSpan;
|
|
20
|
+
exports.withTaskExecuteSpan = withTaskExecuteSpan;
|
|
21
|
+
class NoopSpan {
|
|
22
|
+
setAttribute(_key, _value) { }
|
|
23
|
+
recordException(_err) { }
|
|
24
|
+
end() { }
|
|
25
|
+
}
|
|
26
|
+
class NoopTracer {
|
|
27
|
+
startSpan(_name) { return new NoopSpan(); }
|
|
28
|
+
}
|
|
29
|
+
let _tracer = null;
|
|
30
|
+
let _initialised = false;
|
|
31
|
+
async function _init() {
|
|
32
|
+
if (_tracer)
|
|
33
|
+
return _tracer;
|
|
34
|
+
if (_initialised)
|
|
35
|
+
return new NoopTracer();
|
|
36
|
+
_initialised = true;
|
|
37
|
+
const endpoint = process.env["OTEL_EXPORTER_OTLP_ENDPOINT"] ?? "";
|
|
38
|
+
try {
|
|
39
|
+
const api = await import("@opentelemetry/api").catch(() => null);
|
|
40
|
+
if (!api) {
|
|
41
|
+
_tracer = new NoopTracer();
|
|
42
|
+
return _tracer;
|
|
43
|
+
}
|
|
44
|
+
if (endpoint) {
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
|
+
const sdk = await import("@opentelemetry/sdk-trace-node").catch(() => null);
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
48
|
+
const exp = await import("@opentelemetry/exporter-trace-otlp-http").catch(() => null);
|
|
49
|
+
if (sdk && exp) {
|
|
50
|
+
const provider = new sdk.NodeTracerProvider();
|
|
51
|
+
const exporter = new exp.OTLPTraceExporter({ url: endpoint });
|
|
52
|
+
provider.addSpanProcessor(new sdk.BatchSpanProcessor(exporter));
|
|
53
|
+
provider.register();
|
|
54
|
+
_tracer = api.trace.getTracer("iicp.client");
|
|
55
|
+
return _tracer;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
_tracer = api.trace.getTracer("iicp.client");
|
|
59
|
+
return _tracer;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
_tracer = new NoopTracer();
|
|
63
|
+
return _tracer;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** TRACE-01: iicp.task.validate — wraps request parsing and auth check. */
|
|
67
|
+
async function withTaskValidateSpan(taskId, fn) {
|
|
68
|
+
const tracer = await _init();
|
|
69
|
+
const span = tracer.startSpan("iicp.task.validate");
|
|
70
|
+
span.setAttribute("iicp.task_id", taskId);
|
|
71
|
+
try {
|
|
72
|
+
return fn(span);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
span.end();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** TRACE-02: iicp.task.execute — wraps handler dispatch and response. */
|
|
79
|
+
async function withTaskExecuteSpan(taskId, intent, fn) {
|
|
80
|
+
const tracer = await _init();
|
|
81
|
+
const span = tracer.startSpan("iicp.task.execute");
|
|
82
|
+
span.setAttribute("iicp.task_id", taskId);
|
|
83
|
+
span.setAttribute("iicp.intent", intent);
|
|
84
|
+
try {
|
|
85
|
+
return await fn(span);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
if (err instanceof Error)
|
|
89
|
+
span.recordException(err);
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
span.end();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=otel_tracer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel_tracer.js","sourceRoot":"","sources":["../src/otel_tracer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 2 mesh layer — peer discovery, gossip, and relay support (parity Block F, #340).
|
|
3
|
+
*
|
|
4
|
+
* Port of iicp-adapter `network/peer_manager.py` + `handlers/{peers,relay}.py` (ADR-009,
|
|
5
|
+
* ADR-022). Bootstraps an initial peer set from the directory, gossips a random known peer
|
|
6
|
+
* every 30s with an HMAC-SHA256-signed exchange (reusing the pricing HMAC key), prunes
|
|
7
|
+
* peers idle for 90s, and resolves relay targets for POST /v1/relay forwarding.
|
|
8
|
+
*/
|
|
9
|
+
export interface PeerInfo {
|
|
10
|
+
node_id: string;
|
|
11
|
+
endpoint: string;
|
|
12
|
+
region: string;
|
|
13
|
+
last_seen: string;
|
|
14
|
+
last_contact: number;
|
|
15
|
+
/** R3: relay election fields — advertised in gossip exchange */
|
|
16
|
+
relay_capable?: boolean;
|
|
17
|
+
relay_accept_port?: number;
|
|
18
|
+
relay_load?: number;
|
|
19
|
+
}
|
|
20
|
+
export declare class PeerManager {
|
|
21
|
+
private readonly directoryUrl;
|
|
22
|
+
private readonly nodeToken;
|
|
23
|
+
private peers;
|
|
24
|
+
private ownId;
|
|
25
|
+
private ownEndpoint;
|
|
26
|
+
private readonly ownRelayCapable;
|
|
27
|
+
private readonly ownRelayAcceptPort;
|
|
28
|
+
private timer;
|
|
29
|
+
constructor(directoryUrl: string, nodeToken?: string, opts?: {
|
|
30
|
+
relayCapable?: boolean;
|
|
31
|
+
relayAcceptPort?: number;
|
|
32
|
+
});
|
|
33
|
+
getPeers(): PeerInfo[];
|
|
34
|
+
relayTarget(nodeId: string): PeerInfo | undefined;
|
|
35
|
+
/** Merge incoming peer entries. Returns the count of newly added peers. */
|
|
36
|
+
mergePeers(incoming: Array<Partial<PeerInfo>>): number;
|
|
37
|
+
/** R3: return relay-capable peers, for relay election. */
|
|
38
|
+
getRelayCandidates(): PeerInfo[];
|
|
39
|
+
/** R3: deterministic relay election — rank by load, tiebreak by SHA-256 hash. */
|
|
40
|
+
electRelay(workerId: string): Promise<(PeerInfo & {
|
|
41
|
+
_relayHost: string;
|
|
42
|
+
_relayPort: number;
|
|
43
|
+
}) | null>;
|
|
44
|
+
/** Drop peers not contacted within the expiry window. Returns count pruned. */
|
|
45
|
+
prune(): number;
|
|
46
|
+
/** Verify an inbound /v1/peers HMAC signature. No token configured → accept. */
|
|
47
|
+
verifyExchange(body: string, signature: string | undefined | null): boolean;
|
|
48
|
+
start(nodeId: string, ownEndpoint?: string): Promise<void>;
|
|
49
|
+
stop(): void;
|
|
50
|
+
gossipRound(): Promise<void>;
|
|
51
|
+
private bootstrap;
|
|
52
|
+
private exchange;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=peer_manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer_manager.d.ts","sourceRoot":"","sources":["../src/peer_manager.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAQH,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAC1C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,KAAK,CAA6C;gBAGxD,YAAY,EAAE,MAAM,EACpB,SAAS,SAAK,EACd,IAAI,GAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAO;IAQjE,QAAQ,IAAI,QAAQ,EAAE;IAItB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIjD,2EAA2E;IAC3E,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM;IAqBtD,0DAA0D;IAC1D,kBAAkB,IAAI,QAAQ,EAAE;IAIhC,iFAAiF;IAC3E,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,QAAQ,GAAG;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;IAsB3G,+EAA+E;IAC/E,KAAK,IAAI,MAAM;IAYf,gFAAgF;IAChF,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO;IAMrE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,SAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5D,IAAI,IAAI,IAAI;IAIN,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;YAWpB,SAAS;YAaT,QAAQ;CAkCvB"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Phase 2 mesh layer — peer discovery, gossip, and relay support (parity Block F, #340).
|
|
5
|
+
*
|
|
6
|
+
* Port of iicp-adapter `network/peer_manager.py` + `handlers/{peers,relay}.py` (ADR-009,
|
|
7
|
+
* ADR-022). Bootstraps an initial peer set from the directory, gossips a random known peer
|
|
8
|
+
* every 30s with an HMAC-SHA256-signed exchange (reusing the pricing HMAC key), prunes
|
|
9
|
+
* peers idle for 90s, and resolves relay targets for POST /v1/relay forwarding.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PeerManager = void 0;
|
|
13
|
+
const pricing_js_1 = require("./pricing.js");
|
|
14
|
+
const GOSSIP_INTERVAL_MS = 30_000;
|
|
15
|
+
const PEER_EXPIRY_MS = 90_000;
|
|
16
|
+
const BOOTSTRAP_LIMIT = 5;
|
|
17
|
+
class PeerManager {
|
|
18
|
+
directoryUrl;
|
|
19
|
+
nodeToken;
|
|
20
|
+
peers = new Map();
|
|
21
|
+
ownId = "";
|
|
22
|
+
ownEndpoint = "";
|
|
23
|
+
ownRelayCapable;
|
|
24
|
+
ownRelayAcceptPort;
|
|
25
|
+
timer;
|
|
26
|
+
constructor(directoryUrl, nodeToken = "", opts = {}) {
|
|
27
|
+
this.directoryUrl = directoryUrl.replace(/\/$/, "");
|
|
28
|
+
this.nodeToken = nodeToken;
|
|
29
|
+
this.ownRelayCapable = opts.relayCapable ?? false;
|
|
30
|
+
this.ownRelayAcceptPort = opts.relayAcceptPort ?? 9485;
|
|
31
|
+
}
|
|
32
|
+
getPeers() {
|
|
33
|
+
return [...this.peers.values()];
|
|
34
|
+
}
|
|
35
|
+
relayTarget(nodeId) {
|
|
36
|
+
return this.peers.get(nodeId);
|
|
37
|
+
}
|
|
38
|
+
/** Merge incoming peer entries. Returns the count of newly added peers. */
|
|
39
|
+
mergePeers(incoming) {
|
|
40
|
+
const now = Date.now();
|
|
41
|
+
let added = 0;
|
|
42
|
+
for (const p of incoming) {
|
|
43
|
+
const nid = p.node_id;
|
|
44
|
+
if (!nid || nid === this.ownId)
|
|
45
|
+
continue;
|
|
46
|
+
if (!this.peers.has(nid))
|
|
47
|
+
added++;
|
|
48
|
+
this.peers.set(nid, {
|
|
49
|
+
node_id: nid,
|
|
50
|
+
endpoint: p.endpoint ?? "",
|
|
51
|
+
region: p.region ?? "",
|
|
52
|
+
last_seen: p.last_seen ?? "",
|
|
53
|
+
last_contact: now,
|
|
54
|
+
relay_capable: p.relay_capable ?? false,
|
|
55
|
+
relay_accept_port: p.relay_accept_port ?? 9485,
|
|
56
|
+
relay_load: p.relay_load ?? 0,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return added;
|
|
60
|
+
}
|
|
61
|
+
/** R3: return relay-capable peers, for relay election. */
|
|
62
|
+
getRelayCandidates() {
|
|
63
|
+
return [...this.peers.values()].filter((p) => p.relay_capable && p.endpoint);
|
|
64
|
+
}
|
|
65
|
+
/** R3: deterministic relay election — rank by load, tiebreak by SHA-256 hash. */
|
|
66
|
+
async electRelay(workerId) {
|
|
67
|
+
const { createHash } = await import("node:crypto");
|
|
68
|
+
const candidates = this.getRelayCandidates();
|
|
69
|
+
if (candidates.length === 0)
|
|
70
|
+
return null;
|
|
71
|
+
const scored = candidates.map((p) => {
|
|
72
|
+
const load = p.relay_load ?? 0;
|
|
73
|
+
const hash = createHash("sha256").update(`${workerId}:${p.node_id}`).digest("hex");
|
|
74
|
+
return { p, score: [load, hash] };
|
|
75
|
+
});
|
|
76
|
+
scored.sort((a, b) => {
|
|
77
|
+
if (a.score[0] !== b.score[0])
|
|
78
|
+
return a.score[0] - b.score[0];
|
|
79
|
+
return a.score[1] < b.score[1] ? -1 : 1;
|
|
80
|
+
});
|
|
81
|
+
const elected = scored[0].p;
|
|
82
|
+
const url = new URL(elected.endpoint.startsWith("http") ? elected.endpoint : `http://${elected.endpoint}`);
|
|
83
|
+
return {
|
|
84
|
+
...elected,
|
|
85
|
+
_relayHost: url.hostname,
|
|
86
|
+
_relayPort: elected.relay_accept_port ?? 9485,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** Drop peers not contacted within the expiry window. Returns count pruned. */
|
|
90
|
+
prune() {
|
|
91
|
+
const cutoff = Date.now() - PEER_EXPIRY_MS;
|
|
92
|
+
let pruned = 0;
|
|
93
|
+
for (const [nid, p] of this.peers) {
|
|
94
|
+
if (p.last_contact < cutoff) {
|
|
95
|
+
this.peers.delete(nid);
|
|
96
|
+
pruned++;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return pruned;
|
|
100
|
+
}
|
|
101
|
+
/** Verify an inbound /v1/peers HMAC signature. No token configured → accept. */
|
|
102
|
+
verifyExchange(body, signature) {
|
|
103
|
+
if (!this.nodeToken)
|
|
104
|
+
return true;
|
|
105
|
+
if (!signature)
|
|
106
|
+
return false;
|
|
107
|
+
return (0, pricing_js_1.signBody)(body, this.nodeToken) === signature;
|
|
108
|
+
}
|
|
109
|
+
async start(nodeId, ownEndpoint = "") {
|
|
110
|
+
this.ownId = nodeId;
|
|
111
|
+
this.ownEndpoint = ownEndpoint;
|
|
112
|
+
await this.bootstrap();
|
|
113
|
+
this.timer = setInterval(() => {
|
|
114
|
+
void this.gossipRound();
|
|
115
|
+
}, GOSSIP_INTERVAL_MS);
|
|
116
|
+
}
|
|
117
|
+
stop() {
|
|
118
|
+
if (this.timer)
|
|
119
|
+
clearInterval(this.timer);
|
|
120
|
+
}
|
|
121
|
+
async gossipRound() {
|
|
122
|
+
const peers = this.getPeers();
|
|
123
|
+
if (peers.length === 0) {
|
|
124
|
+
await this.bootstrap();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const target = peers[Math.floor(Math.random() * peers.length)];
|
|
128
|
+
await this.exchange(target);
|
|
129
|
+
this.prune();
|
|
130
|
+
}
|
|
131
|
+
async bootstrap() {
|
|
132
|
+
try {
|
|
133
|
+
const url = `${this.directoryUrl}/v1/bootstrap?limit=${BOOTSTRAP_LIMIT}`;
|
|
134
|
+
const resp = await fetch(url, { signal: AbortSignal.timeout(5000) });
|
|
135
|
+
if (resp.ok) {
|
|
136
|
+
const body = (await resp.json());
|
|
137
|
+
this.mergePeers(body.peers ?? []);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
/* directory unreachable — keep persisted/known peers */
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async exchange(target) {
|
|
145
|
+
// R3: send full peer objects + own relay entry so recipients can elect us as a relay.
|
|
146
|
+
const peers = [...this.peers.values()];
|
|
147
|
+
const knownPeers = [...peers];
|
|
148
|
+
if (this.ownId) {
|
|
149
|
+
knownPeers.push({
|
|
150
|
+
node_id: this.ownId,
|
|
151
|
+
endpoint: this.ownEndpoint,
|
|
152
|
+
relay_capable: this.ownRelayCapable,
|
|
153
|
+
relay_accept_port: this.ownRelayAcceptPort,
|
|
154
|
+
relay_load: 0,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
const body = JSON.stringify({ known_peers: knownPeers });
|
|
158
|
+
const headers = { "Content-Type": "application/json" };
|
|
159
|
+
if (this.nodeToken)
|
|
160
|
+
headers["X-IICP-Signature"] = (0, pricing_js_1.signBody)(body, this.nodeToken);
|
|
161
|
+
try {
|
|
162
|
+
const resp = await fetch(`${target.endpoint.replace(/\/$/, "")}/v1/peers`, {
|
|
163
|
+
method: "POST",
|
|
164
|
+
headers,
|
|
165
|
+
body,
|
|
166
|
+
signal: AbortSignal.timeout(5000),
|
|
167
|
+
});
|
|
168
|
+
if (resp.ok) {
|
|
169
|
+
const data = (await resp.json());
|
|
170
|
+
this.mergePeers(data.peers ?? []);
|
|
171
|
+
const t = this.peers.get(target.node_id);
|
|
172
|
+
if (t)
|
|
173
|
+
t.last_contact = Date.now();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
const t = this.peers.get(target.node_id);
|
|
178
|
+
if (t)
|
|
179
|
+
t.last_contact = 0;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
exports.PeerManager = PeerManager;
|
|
184
|
+
//# sourceMappingURL=peer_manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer_manager.js","sourceRoot":"","sources":["../src/peer_manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relay-as-last-resort — ADR-041 tier-3, Part 3 R1 (#341).
|
|
3
|
+
*
|
|
4
|
+
* TypeScript port of iicp-client-python/relay_session.py.
|
|
5
|
+
* Workers behind CGNAT hold an outbound IICP-TCP connection here.
|
|
6
|
+
* The relay pushes CALL frames down when /v1/relay is invoked and routes
|
|
7
|
+
* RESPONSE frames back to the waiting HTTP handler.
|
|
8
|
+
*/
|
|
9
|
+
import * as net from "node:net";
|
|
10
|
+
export declare class RelayWorkerSession {
|
|
11
|
+
readonly workerId: string;
|
|
12
|
+
private readonly _socket;
|
|
13
|
+
private readonly _pending;
|
|
14
|
+
private _writeLocked;
|
|
15
|
+
constructor(workerId: string, socket: net.Socket);
|
|
16
|
+
/** Push a task CALL to the worker and await the RESPONSE (via Promise). */
|
|
17
|
+
forwardTask(task: unknown, timeoutMs?: number): Promise<Record<string, unknown>>;
|
|
18
|
+
/** Called by relay accept server when a RESPONSE arrives from the worker. */
|
|
19
|
+
onResponse(callId: string, result: Record<string, unknown>): void;
|
|
20
|
+
}
|
|
21
|
+
export declare class RelaySessionRegistry {
|
|
22
|
+
private readonly _sessions;
|
|
23
|
+
bind(workerId: string, session: RelayWorkerSession): void;
|
|
24
|
+
unbind(workerId: string): void;
|
|
25
|
+
get(workerId: string): RelayWorkerSession | undefined;
|
|
26
|
+
isBound(workerId: string): boolean;
|
|
27
|
+
boundWorkerIds(): string[];
|
|
28
|
+
}
|
|
29
|
+
export declare class RelayAcceptServer {
|
|
30
|
+
private readonly _registry;
|
|
31
|
+
private readonly _host;
|
|
32
|
+
private readonly _port;
|
|
33
|
+
private _server?;
|
|
34
|
+
constructor(registry: RelaySessionRegistry, opts?: {
|
|
35
|
+
host?: string;
|
|
36
|
+
port?: number;
|
|
37
|
+
});
|
|
38
|
+
start(): Promise<void>;
|
|
39
|
+
stop(): Promise<void>;
|
|
40
|
+
private _handleConnection;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=relay_session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay_session.d.ts","sourceRoot":"","sources":["../src/relay_session.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AA0ChC,qBAAa,kBAAkB;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgE;IACzF,OAAO,CAAC,YAAY,CAAS;gBAEjB,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM;IAKhD,2EAA2E;IACrE,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,SAAU,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAyBvF,6EAA6E;IAC7E,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAOlE;AAID,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyC;IAEnE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAIzD,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAI9B,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAIrD,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIlC,cAAc,IAAI,MAAM,EAAE;CAG3B;AAID,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuB;IACjD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,OAAO,CAAC,CAAa;gBAEjB,QAAQ,EAAE,oBAAoB,EAAE,IAAI,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAO;IAMvF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAUP,iBAAiB;CAkGhC"}
|