@cello-protocol/daemon 0.0.53 → 0.0.55
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/agent-handlers.d.ts +57 -0
- package/dist/agent-handlers.d.ts.map +1 -0
- package/dist/agent-handlers.js +360 -0
- package/dist/agent-handlers.js.map +1 -0
- package/dist/agent-id-migration.d.ts.map +1 -1
- package/dist/agent-id-migration.js +1 -0
- package/dist/agent-id-migration.js.map +1 -1
- package/dist/agent-loader.d.ts +3 -4
- package/dist/agent-loader.d.ts.map +1 -1
- package/dist/agent-loader.js +3 -4
- package/dist/agent-loader.js.map +1 -1
- package/dist/cbor-blob-migration.d.ts +8 -0
- package/dist/cbor-blob-migration.d.ts.map +1 -0
- package/dist/cbor-blob-migration.js +115 -0
- package/dist/cbor-blob-migration.js.map +1 -0
- package/dist/close-session-handler.d.ts +41 -0
- package/dist/close-session-handler.d.ts.map +1 -0
- package/dist/close-session-handler.js +399 -0
- package/dist/close-session-handler.js.map +1 -0
- package/dist/consortium-bootstrap.d.ts +83 -0
- package/dist/consortium-bootstrap.d.ts.map +1 -0
- package/dist/consortium-bootstrap.js +120 -0
- package/dist/consortium-bootstrap.js.map +1 -0
- package/dist/contact-handlers.d.ts +56 -0
- package/dist/contact-handlers.d.ts.map +1 -0
- package/dist/contact-handlers.js +303 -0
- package/dist/contact-handlers.js.map +1 -0
- package/dist/content-park-client.d.ts.map +1 -1
- package/dist/content-park-client.js +7 -7
- package/dist/content-park-client.js.map +1 -1
- package/dist/content-park.d.ts +15 -0
- package/dist/content-park.d.ts.map +1 -0
- package/dist/content-park.js +227 -0
- package/dist/content-park.js.map +1 -0
- package/dist/daemon.d.ts +4 -10
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +430 -4563
- package/dist/daemon.js.map +1 -1
- package/dist/db-identity-store.d.ts +31 -35
- package/dist/db-identity-store.d.ts.map +1 -1
- package/dist/db-identity-store.js +62 -66
- package/dist/db-identity-store.js.map +1 -1
- package/dist/directory-bootstrap.d.ts +27 -31
- package/dist/directory-bootstrap.d.ts.map +1 -1
- package/dist/directory-bootstrap.js +18 -21
- package/dist/directory-bootstrap.js.map +1 -1
- package/dist/frame-values.d.ts +3 -0
- package/dist/frame-values.d.ts.map +1 -0
- package/dist/frame-values.js +73 -0
- package/dist/frame-values.js.map +1 -0
- package/dist/identity-migration.d.ts +8 -8
- package/dist/identity-migration.d.ts.map +1 -1
- package/dist/identity-migration.js +30 -31
- package/dist/identity-migration.js.map +1 -1
- package/dist/inbound-seal-request.d.ts +17 -0
- package/dist/inbound-seal-request.d.ts.map +1 -0
- package/dist/inbound-seal-request.js +155 -0
- package/dist/inbound-seal-request.js.map +1 -0
- package/dist/inbound-sessions.d.ts +54 -0
- package/dist/inbound-sessions.d.ts.map +1 -0
- package/dist/inbound-sessions.js +603 -0
- package/dist/inbound-sessions.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -10
- package/dist/index.js.map +1 -1
- package/dist/initiate-session-handler.d.ts +22 -0
- package/dist/initiate-session-handler.d.ts.map +1 -0
- package/dist/initiate-session-handler.js +150 -0
- package/dist/initiate-session-handler.js.map +1 -0
- package/dist/network-directory-node.d.ts +6 -6
- package/dist/network-directory-node.d.ts.map +1 -1
- package/dist/network-directory-node.js +29 -28
- package/dist/network-directory-node.js.map +1 -1
- package/dist/notification-handlers.d.ts +32 -0
- package/dist/notification-handlers.d.ts.map +1 -0
- package/dist/notification-handlers.js +73 -0
- package/dist/notification-handlers.js.map +1 -0
- package/dist/outbound-sessions.d.ts +54 -0
- package/dist/outbound-sessions.d.ts.map +1 -0
- package/dist/outbound-sessions.js +429 -0
- package/dist/outbound-sessions.js.map +1 -0
- package/dist/park-envelope.d.ts.map +1 -1
- package/dist/park-envelope.js +3 -2
- package/dist/park-envelope.js.map +1 -1
- package/dist/register-handler.d.ts +35 -0
- package/dist/register-handler.d.ts.map +1 -0
- package/dist/register-handler.js +179 -0
- package/dist/register-handler.js.map +1 -0
- package/dist/registration-manager.d.ts.map +1 -1
- package/dist/registration-manager.js +3 -6
- package/dist/registration-manager.js.map +1 -1
- package/dist/relay-receipt-store.d.ts.map +1 -1
- package/dist/relay-receipt-store.js +1 -2
- package/dist/relay-receipt-store.js.map +1 -1
- package/dist/retry-queue.d.ts +18 -60
- package/dist/retry-queue.d.ts.map +1 -1
- package/dist/retry-queue.js +46 -97
- package/dist/retry-queue.js.map +1 -1
- package/dist/seal-coordinator.d.ts +47 -0
- package/dist/seal-coordinator.d.ts.map +1 -0
- package/dist/seal-coordinator.js +551 -0
- package/dist/seal-coordinator.js.map +1 -0
- package/dist/seal-flows.d.ts +50 -0
- package/dist/seal-flows.d.ts.map +1 -0
- package/dist/seal-flows.js +454 -0
- package/dist/seal-flows.js.map +1 -0
- package/dist/seal-frontier-verify.d.ts +9 -9
- package/dist/seal-frontier-verify.d.ts.map +1 -1
- package/dist/seal-frontier-verify.js +11 -12
- package/dist/seal-frontier-verify.js.map +1 -1
- package/dist/seal-leaf.d.ts +58 -0
- package/dist/seal-leaf.d.ts.map +1 -0
- package/dist/seal-leaf.js +111 -0
- package/dist/seal-leaf.js.map +1 -0
- package/dist/seal-receipt-upgrade.d.ts +1 -1
- package/dist/seal-receipt-upgrade.js +1 -1
- package/dist/seal-upgrade.d.ts +10 -10
- package/dist/seal-upgrade.d.ts.map +1 -1
- package/dist/seal-upgrade.js +23 -24
- package/dist/seal-upgrade.js.map +1 -1
- package/dist/session-assignment-parser.d.ts +16 -19
- package/dist/session-assignment-parser.d.ts.map +1 -1
- package/dist/session-assignment-parser.js +30 -29
- package/dist/session-assignment-parser.js.map +1 -1
- package/dist/session-ceremony.d.ts +3 -6
- package/dist/session-ceremony.d.ts.map +1 -1
- package/dist/session-ceremony.js +7 -9
- package/dist/session-ceremony.js.map +1 -1
- package/dist/session-connection-gater.d.ts +4 -2
- package/dist/session-connection-gater.d.ts.map +1 -1
- package/dist/session-connection-gater.js +16 -10
- package/dist/session-connection-gater.js.map +1 -1
- package/dist/session-content-handlers.d.ts +25 -0
- package/dist/session-content-handlers.d.ts.map +1 -0
- package/dist/session-content-handlers.js +436 -0
- package/dist/session-content-handlers.js.map +1 -0
- package/dist/session-name.d.ts +35 -0
- package/dist/session-name.d.ts.map +1 -0
- package/dist/session-name.js +60 -0
- package/dist/session-name.js.map +1 -0
- package/dist/session-node-manager.d.ts +47 -62
- package/dist/session-node-manager.d.ts.map +1 -1
- package/dist/session-node-manager.js +297 -97
- package/dist/session-node-manager.js.map +1 -1
- package/dist/session-read-handlers.d.ts +38 -0
- package/dist/session-read-handlers.d.ts.map +1 -0
- package/dist/session-read-handlers.js +233 -0
- package/dist/session-read-handlers.js.map +1 -0
- package/dist/session-relay-client.d.ts +8 -8
- package/dist/session-relay-client.d.ts.map +1 -1
- package/dist/session-relay-client.js +44 -46
- package/dist/session-relay-client.js.map +1 -1
- package/dist/session-tree.d.ts +11 -23
- package/dist/session-tree.d.ts.map +1 -1
- package/dist/session-tree.js +14 -26
- package/dist/session-tree.js.map +1 -1
- package/dist/signaling-connect.d.ts +13 -5
- package/dist/signaling-connect.d.ts.map +1 -1
- package/dist/signaling-connect.js +55 -13
- package/dist/signaling-connect.js.map +1 -1
- package/dist/sqlcipher-db.d.ts +18 -19
- package/dist/sqlcipher-db.d.ts.map +1 -1
- package/dist/sqlcipher-db.js +30 -30
- package/dist/sqlcipher-db.js.map +1 -1
- package/dist/telegram-doorbell.d.ts +38 -0
- package/dist/telegram-doorbell.d.ts.map +1 -0
- package/dist/telegram-doorbell.js +139 -0
- package/dist/telegram-doorbell.js.map +1 -0
- package/dist/types.d.ts +86 -79
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -1
- package/dist/types.js.map +1 -1
- package/dist/vocabulary.d.ts +30 -30
- package/dist/vocabulary.d.ts.map +1 -1
- package/dist/vocabulary.js +41 -49
- package/dist/vocabulary.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The OUTBOUND session path: discovery, the session request, and cross-node setup.
|
|
3
|
+
*
|
|
4
|
+
* DOD-SPINE-5. The initiator asks the directory to find the counterparty, requests a session, and —
|
|
5
|
+
* when the counterparty lives on a DIFFERENT directory node — opens a transient VISITING connection
|
|
6
|
+
* to that node to broker the handshake.
|
|
7
|
+
*
|
|
8
|
+
* The visiting connection is the subtle part, and it has already produced one serious bug: it is a
|
|
9
|
+
* fully authenticated stream, so the directory will drain its DURABLE notification queue down it.
|
|
10
|
+
* Anything a home stream must handle, a visiting stream must handle too (see registerSealListeners,
|
|
11
|
+
* which is why the seal listeners are a single bundle and not three separate registrations).
|
|
12
|
+
*/
|
|
13
|
+
import { SignalingManager } from "@cello-protocol/transport";
|
|
14
|
+
import { classifyOnlineResult } from "./cross-node-negotiation.js";
|
|
15
|
+
import { parseDiscoveryLookupResult, discoveryLookupErrorReason, parseSessionAssignment, sessionRequestErrorReason, resolveOutboundMoniker } from "./session-assignment-parser.js";
|
|
16
|
+
import { DbIdentityStore } from "./db-identity-store.js";
|
|
17
|
+
import { createSignalingConnect } from "./signaling-connect.js";
|
|
18
|
+
import { wireSessionCeremonyHandler, wireSealCeremonyHandler } from "./session-ceremony.js";
|
|
19
|
+
export function createOutboundSessions(deps) {
|
|
20
|
+
const { logger, sessionNodeManager, getKeyProvider, getPersistence, getAgentSignaling, waitForSignalingConnected, getFailoverEndpoint, resolveConsortiumRoster, registerSealListeners, sessionNegotiator, challengeVerifier, getManifestVersion, loadedAgents, } = deps;
|
|
21
|
+
// ─── DOD-SPINE-5: real client-side session negotiator (built internally) ──────
|
|
22
|
+
// The directory already brokers `session_request` → FROST-signed `session_assignment`
|
|
23
|
+
// live; the missing half was the CLIENT driver. This negotiator sends `session_request`
|
|
24
|
+
// over the CURRENT agent's OWN signaling stream (so the directory routes the signed
|
|
25
|
+
// assignment back to that agent — same per-agent routing SPINE-4 established), advertising
|
|
26
|
+
// the standing receiver's session endpoint (WIRE-001: the directory rejects a request
|
|
27
|
+
// with no initiator session Peer ID), then parses the returned assignment. Tests inject their own
|
|
28
|
+
// `sessionNegotiator`; the binary gets a real one.
|
|
29
|
+
// M3: a `session_assignment` frame carries no echoed request id, so two overlapping
|
|
30
|
+
// initiations on ONE agent's stream would race to resolve on whichever assignment
|
|
31
|
+
// arrives first — request A could complete with B's assignment. Guard with a per-agent
|
|
32
|
+
// single-flight slot (genuine single-slot, as the prior comment falsely claimed). Cross-
|
|
33
|
+
// agent concurrency is unaffected (separate streams). A directory-side echoed request id
|
|
34
|
+
// would allow true concurrency later; this is the correct minimum.
|
|
35
|
+
const negotiationInProgress = new Set();
|
|
36
|
+
// ─── Cross-node session establishment (Story B, item 2) ──────────────────────
|
|
37
|
+
// Helpers the negotiator composes: discover the target's home from replicated presence, then run
|
|
38
|
+
// the session_request over the RIGHT connection — the existing home stream when same-node, or a
|
|
39
|
+
// transient VISITING connection into the target's home node when cross-node. Directories never talk
|
|
40
|
+
// to each other; the client spans nodes on demand.
|
|
41
|
+
const sleepMs = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
42
|
+
/**
|
|
43
|
+
* Issue a discovery_lookup on `signaling` and await the 3-state answer (bounded). Distinguishes,
|
|
44
|
+
* for the caller's retry logic and truthful error surface:
|
|
45
|
+
* - send_failed (home stream down — TRANSPORT, never "old directory"),
|
|
46
|
+
* - timeout (no reply — old directory OR a slow/dropped reply on a new one; retry, fall back last),
|
|
47
|
+
* - error (directory DB fault — retryable, a DIRECTORY fault, not the counterparty being offline),
|
|
48
|
+
* - malformed (a reply that didn't parse — protocol anomaly, retryable, surfaced distinctly),
|
|
49
|
+
* - result (the 3-state answer).
|
|
50
|
+
* Emits the mandated observability events: directory.discovery.lookup on a result,
|
|
51
|
+
* directory.discovery.lookup.failed on a directory error / malformed reply.
|
|
52
|
+
*/
|
|
53
|
+
async function runDiscoveryLookup(signaling, targetHex, timeoutMs, correlationId) {
|
|
54
|
+
let resolveFrame;
|
|
55
|
+
const pending = new Promise((r) => { resolveFrame = r; });
|
|
56
|
+
const unregister = signaling.registerInboundHandler((frame) => {
|
|
57
|
+
const t = frame["type"];
|
|
58
|
+
if (t === "discovery_lookup_result" || t === "discovery_lookup_error")
|
|
59
|
+
resolveFrame(frame);
|
|
60
|
+
});
|
|
61
|
+
try {
|
|
62
|
+
const sent = await signaling.sendRaw({
|
|
63
|
+
type: "discovery_lookup",
|
|
64
|
+
target_pubkey: new Uint8Array(Buffer.from(targetHex, "hex")),
|
|
65
|
+
});
|
|
66
|
+
if (!sent.ok) {
|
|
67
|
+
// The home stream is down — cannot look up (and today's local-only fallback would fail the
|
|
68
|
+
// same way). Surface the real transport reason, not an "old directory" misdiagnosis.
|
|
69
|
+
return { kind: "send_failed", reason: sent.reason ?? "signaling_unavailable" };
|
|
70
|
+
}
|
|
71
|
+
let timer;
|
|
72
|
+
const timeoutP = new Promise((r) => { timer = setTimeout(() => r({ type: "__timeout__" }), timeoutMs); });
|
|
73
|
+
const frame = await Promise.race([pending, timeoutP]);
|
|
74
|
+
clearTimeout(timer);
|
|
75
|
+
if (frame["type"] === "__timeout__")
|
|
76
|
+
return { kind: "timeout" };
|
|
77
|
+
if (frame["type"] === "discovery_lookup_error") {
|
|
78
|
+
const reason = discoveryLookupErrorReason(frame);
|
|
79
|
+
logger.warn("directory.discovery.lookup.failed", { target: targetHex.slice(0, 16), reason, correlationId });
|
|
80
|
+
return { kind: "error", reason };
|
|
81
|
+
}
|
|
82
|
+
const parsed = parseDiscoveryLookupResult(frame);
|
|
83
|
+
if (!parsed) {
|
|
84
|
+
// A reply came back but did not parse — a protocol/version anomaly on a directory that DID
|
|
85
|
+
// respond. Surface it distinctly from a clean directory DB error, and never as availability.
|
|
86
|
+
logger.warn("directory.discovery.lookup.failed", { target: targetHex.slice(0, 16), reason: "malformed_reply", correlationId });
|
|
87
|
+
return { kind: "malformed" };
|
|
88
|
+
}
|
|
89
|
+
logger.info("directory.discovery.lookup", {
|
|
90
|
+
target: targetHex.slice(0, 16),
|
|
91
|
+
state: parsed.state,
|
|
92
|
+
owningNode: parsed.owningNodeIds[0] ?? null,
|
|
93
|
+
correlationId,
|
|
94
|
+
});
|
|
95
|
+
return { kind: "result", state: parsed.state, owningNodeIds: parsed.owningNodeIds };
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
unregister();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/** Send a session_request over `signaling` and await the assignment / error (the extracted core). */
|
|
102
|
+
async function runSessionRequestOverSignaling(signaling, targetHex, sr, correlationId, agentName) {
|
|
103
|
+
let resolveFrame;
|
|
104
|
+
const pending = new Promise((r) => { resolveFrame = r; });
|
|
105
|
+
const unregister = signaling.registerInboundHandler((frame) => {
|
|
106
|
+
const t = frame["type"];
|
|
107
|
+
if (t === "session_assignment" || t === "session_request_error")
|
|
108
|
+
resolveFrame(frame);
|
|
109
|
+
});
|
|
110
|
+
// MONIKER-2 AC1: the outbound name rides the request (agent name, or the MONIKER-1
|
|
111
|
+
// override), re-validated at offer construction (defense in depth) and OMITTED — never
|
|
112
|
+
// an empty string — when absent or invalid. A failure reading it must never block the
|
|
113
|
+
// session (spec §8: the label degrades, the session forms), but it is logged loudly.
|
|
114
|
+
let moniker;
|
|
115
|
+
try {
|
|
116
|
+
const outboundName = new DbIdentityStore(sessionNodeManager.getDb(), logger).getOutboundName(agentName);
|
|
117
|
+
moniker = resolveOutboundMoniker(outboundName);
|
|
118
|
+
// Review F4: omit-not-send is the designed degradation, but an agent whose STORED name
|
|
119
|
+
// fails the rule should be visible, not silently nameless on the wire.
|
|
120
|
+
if (outboundName !== null && moniker === undefined) {
|
|
121
|
+
logger.debug("moniker.outbound.invalid_name_omitted", { agentName, correlationId });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
logger.warn("moniker.outbound.read_failed", {
|
|
126
|
+
agentName,
|
|
127
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
128
|
+
correlationId,
|
|
129
|
+
});
|
|
130
|
+
moniker = undefined;
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const sent = await signaling.sendRaw({
|
|
134
|
+
type: "session_request",
|
|
135
|
+
target_pubkey: new Uint8Array(Buffer.from(targetHex, "hex")),
|
|
136
|
+
initiator_session_peer_id: sr.peerId,
|
|
137
|
+
initiator_session_addrs: sr.addrs,
|
|
138
|
+
wants_session_offer: true,
|
|
139
|
+
...(moniker !== undefined ? { moniker } : {}),
|
|
140
|
+
});
|
|
141
|
+
if (!sent.ok) {
|
|
142
|
+
return { ok: false, reason: sent.reason ?? "directory_unreachable", guidance: sent.guidance ?? "Could not send session_request over the directory signaling stream." };
|
|
143
|
+
}
|
|
144
|
+
let timer;
|
|
145
|
+
const timeoutP = new Promise((r) => { timer = setTimeout(() => r({ type: "__timeout__" }), 30_000); });
|
|
146
|
+
const frame = await Promise.race([pending, timeoutP]);
|
|
147
|
+
clearTimeout(timer);
|
|
148
|
+
if (frame["type"] === "__timeout__") {
|
|
149
|
+
return { ok: false, reason: "timeout", guidance: "The directory did not return a session assignment within 30s. Retry once cello status shows directory_signaling connected." };
|
|
150
|
+
}
|
|
151
|
+
if (frame["type"] === "session_request_error") {
|
|
152
|
+
const reason = sessionRequestErrorReason(frame);
|
|
153
|
+
return { ok: false, reason, guidance: `The directory refused the session request (${reason}). Ensure the counterparty is registered and online.` };
|
|
154
|
+
}
|
|
155
|
+
const raw = frame["assignment"];
|
|
156
|
+
const assignment = raw ? parseSessionAssignment(raw) : null;
|
|
157
|
+
if (!assignment) {
|
|
158
|
+
return { ok: false, reason: "assignment_parse_failed", guidance: "The directory's session_assignment was missing or malformed." };
|
|
159
|
+
}
|
|
160
|
+
logger.info("session.negotiate.assignment.received", { agentName, correlationId, signatureType: assignment.signature_type });
|
|
161
|
+
return { ok: true, assignment };
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
unregister();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Open a transient VISITING signaling connection into a specific directory node (the target's home /
|
|
169
|
+
* broker) and wire what a cross-node initiator needs there:
|
|
170
|
+
* - the delegated-signer ceremony handler (the broker asks the initiator to co-sign the assignment
|
|
171
|
+
* over THIS connection); and
|
|
172
|
+
* - Fix #1 (cross-node seal-liveness): the seal ceremony handler + session_sealed/unilateral
|
|
173
|
+
* listeners, because for a cross-node CLOSE the broker ALSO pushes seal_verified then session_sealed
|
|
174
|
+
* over the connection the initiator holds to it. The seal FROST still runs over the agent's OWN
|
|
175
|
+
* roster (getNode: () => nodeRef) — only the control frames traverse this stream.
|
|
176
|
+
* Transient and initiator-only. The caller MUST stop() it after the assignment (setup path) or after
|
|
177
|
+
* the seal reaches a terminal outcome (close path).
|
|
178
|
+
*/
|
|
179
|
+
function openVisitingConnection(agentName, agentKeyProvider, agentPubkeyHex, endpoint, correlationId, nodeId) {
|
|
180
|
+
let nodeRef = null;
|
|
181
|
+
const connect = createSignalingConnect({
|
|
182
|
+
getDirectoryEndpoint: () => endpoint,
|
|
183
|
+
getAuthIdentity: () => ({ keyProvider: agentKeyProvider, pubkeyHex: agentPubkeyHex }),
|
|
184
|
+
logger,
|
|
185
|
+
challengeVerifier,
|
|
186
|
+
getManifestVersion,
|
|
187
|
+
visiting: true, // cross-node item 3: the directory must NOT write presence for this connection
|
|
188
|
+
publishNode: (n) => { nodeRef = n; },
|
|
189
|
+
});
|
|
190
|
+
// maxReconnectAttempts: 1 — a transient connection should fail fast, not reconnect-loop forever.
|
|
191
|
+
const mgr = new SignalingManager({ connect, logger, maxReconnectAttempts: 1, maxBackoffMs: 3_000 });
|
|
192
|
+
wireSessionCeremonyHandler({
|
|
193
|
+
agentName,
|
|
194
|
+
persistence: getPersistence(agentName),
|
|
195
|
+
agentPubkeyHex,
|
|
196
|
+
keyProvider: agentKeyProvider,
|
|
197
|
+
getNode: () => nodeRef,
|
|
198
|
+
getDirectoryEndpoint: getFailoverEndpoint,
|
|
199
|
+
getConsortiumEndpoints: resolveConsortiumRoster,
|
|
200
|
+
signaling: mgr,
|
|
201
|
+
logger,
|
|
202
|
+
});
|
|
203
|
+
// Fix #1 (cross-node seal-liveness): a visiting connection must ALSO be able to complete the SEAL.
|
|
204
|
+
// The broker (the node this visiting connection targets) pushes seal_verified then session_sealed to
|
|
205
|
+
// whichever stream the initiator holds to it — for a cross-node close that is THIS visiting stream.
|
|
206
|
+
// Run the seal FROST ceremony over the agent's own node (getNode: () => nodeRef, exactly as the
|
|
207
|
+
// session ceremony above) and reply/resolve on this stream. Harmless on a setup-only visiting
|
|
208
|
+
// connection: these frames never arrive before it is released after handoff.
|
|
209
|
+
wireSealCeremonyHandler({
|
|
210
|
+
agentName,
|
|
211
|
+
persistence: getPersistence(agentName),
|
|
212
|
+
agentPubkeyHex,
|
|
213
|
+
keyProvider: agentKeyProvider,
|
|
214
|
+
getNode: () => nodeRef,
|
|
215
|
+
getDirectoryEndpoint: getFailoverEndpoint,
|
|
216
|
+
getConsortiumEndpoints: resolveConsortiumRoster,
|
|
217
|
+
signaling: mgr,
|
|
218
|
+
logger,
|
|
219
|
+
});
|
|
220
|
+
// FIX (Seam B review): this VISITING stream used to register only the sealed + unilateral-confirmed
|
|
221
|
+
// listeners. That silently lost seal receipts — the directory drains its DURABLE notification queue
|
|
222
|
+
// on ANY stream that authenticates, visiting included, and deletes each row once sent. A
|
|
223
|
+
// seal_unilateral_notification pushed down here hit no handler, was dropped, and its row was gone;
|
|
224
|
+
// the absent party never ratified and the seal stayed unilateral forever. Every stream that can
|
|
225
|
+
// carry a seal frame now gets every seal listener — and the coordinator no longer lets it be
|
|
226
|
+
// wired any other way.
|
|
227
|
+
registerSealListeners(mgr, agentName, agentPubkeyHex);
|
|
228
|
+
logger.info("signaling.visiting.connected", { agentName, node: nodeId, correlationId });
|
|
229
|
+
return {
|
|
230
|
+
mgr,
|
|
231
|
+
stop: async (reason) => {
|
|
232
|
+
logger.info("signaling.visiting.released", { agentName, node: nodeId, reason, correlationId });
|
|
233
|
+
await mgr.stop();
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
// Fix #1 (cross-node seal-liveness): the broker node (the counterparty's home) for each cross-node
|
|
238
|
+
// session we initiated, keyed `${agentName}:${sessionIdHex}`. Set when runCrossNodeSetup establishes
|
|
239
|
+
// the session; read by cello_close_session so it can re-open a visiting connection to the broker and
|
|
240
|
+
// complete the seal there. The broker pushes seal_verified/session_sealed, but the initiator RELEASES
|
|
241
|
+
// its visiting connection after setup — so without reconnecting, the close times out
|
|
242
|
+
// (seal_unilateral_timeout) and the seal only completes whenever the daemon next happens to reconnect.
|
|
243
|
+
// Presence of an entry means the session is cross-node (same-node sessions never go through
|
|
244
|
+
// runCrossNodeSetup). In-memory only: a close in the SAME process (the common case) is covered; a close
|
|
245
|
+
// after a daemon restart falls back to the pre-fix behavior (deferred hardening: persist on the row).
|
|
246
|
+
const crossNodeBrokerBySession = new Map();
|
|
247
|
+
/**
|
|
248
|
+
* Resolve `owningNodeId` through the signed manifest and run the session_request over a transient
|
|
249
|
+
* visiting connection there. A node id that doesn't resolve in the roster is a hard error
|
|
250
|
+
* (discovery_node_unresolvable) — never a dial to an unvalidated endpoint.
|
|
251
|
+
*/
|
|
252
|
+
async function runCrossNodeSetup(agentName, agentKeyProvider, agentPubkeyHex, owningNodeId, targetHex, sr, correlationId) {
|
|
253
|
+
const roster = await resolveConsortiumRoster();
|
|
254
|
+
const target = roster?.find((e) => e.nodeId === owningNodeId) ?? null;
|
|
255
|
+
if (!target) {
|
|
256
|
+
// Manifest MISS — the node genuinely isn't in the signed roster. A hard, non-retryable cause
|
|
257
|
+
// (distinct from a reachable-but-unconnectable node below).
|
|
258
|
+
logger.warn("session.crossnode.failed", { agentName, brokerNode: owningNodeId, reason: "discovery_node_unresolvable", correlationId });
|
|
259
|
+
return { ok: false, reason: "discovery_node_unresolvable", guidance: `The counterparty's home node (${owningNodeId}) is not in the signed consortium manifest. It may have left the consortium.` };
|
|
260
|
+
}
|
|
261
|
+
logger.info("session.crossnode.initiated", { agentName, brokerNode: owningNodeId, correlationId });
|
|
262
|
+
const visiting = openVisitingConnection(agentName, agentKeyProvider, agentPubkeyHex, { peerId: target.peerId, multiaddr: target.multiaddr }, correlationId, owningNodeId);
|
|
263
|
+
// Track the release reason across the finally (result is block-scoped in the try).
|
|
264
|
+
let releaseReason = "failure";
|
|
265
|
+
try {
|
|
266
|
+
if (!(await waitForSignalingConnected(visiting.mgr, 10_000))) {
|
|
267
|
+
// The node RESOLVED but the visiting dial/auth didn't complete in time — a TRANSIENT
|
|
268
|
+
// cross-region condition (latency, blip, cold handshake), NOT a manifest miss. Distinct
|
|
269
|
+
// reason, and the caller's retry loop treats it as retryable (re-discover → retry).
|
|
270
|
+
logger.warn("session.crossnode.failed", { agentName, brokerNode: owningNodeId, reason: "visiting_connection_unreachable", correlationId });
|
|
271
|
+
return { ok: false, reason: "visiting_connection_unreachable", guidance: `Could not establish a visiting connection to the counterparty's home node (${owningNodeId}) within 10s. Retry.` };
|
|
272
|
+
}
|
|
273
|
+
const result = await runSessionRequestOverSignaling(visiting.mgr, targetHex, sr, correlationId, agentName);
|
|
274
|
+
if (result.ok) {
|
|
275
|
+
releaseReason = "handoff-complete";
|
|
276
|
+
// Fix #1: remember the broker for this session so cello_close_session can reconnect to complete the seal.
|
|
277
|
+
const brokerSessionIdHex = Buffer.from(result.assignment.session_id).toString("hex");
|
|
278
|
+
crossNodeBrokerBySession.set(`${agentName}:${brokerSessionIdHex}`, owningNodeId);
|
|
279
|
+
logger.info("session.crossnode.established", { agentName, brokerNode: owningNodeId, correlationId });
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
logger.warn("session.crossnode.failed", { agentName, brokerNode: owningNodeId, reason: result.reason, correlationId });
|
|
283
|
+
}
|
|
284
|
+
return result;
|
|
285
|
+
}
|
|
286
|
+
finally {
|
|
287
|
+
await visiting.stop(releaseReason);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
const resolvedSessionNegotiator = sessionNegotiator ?? {
|
|
291
|
+
negotiate: async (ctx) => {
|
|
292
|
+
const kp = getKeyProvider(ctx.agentName);
|
|
293
|
+
const agentRec = loadedAgents.find((a) => a.name === ctx.agentName);
|
|
294
|
+
if (!kp || !agentRec) {
|
|
295
|
+
return { ok: false, reason: "agent_not_found", guidance: `Agent '${ctx.agentName}' is not loaded on this daemon.` };
|
|
296
|
+
}
|
|
297
|
+
if (negotiationInProgress.has(ctx.agentName)) {
|
|
298
|
+
return {
|
|
299
|
+
ok: false,
|
|
300
|
+
reason: "session_negotiation_in_progress",
|
|
301
|
+
guidance: `Another session initiation is already in progress for agent '${ctx.agentName}'. Wait for it to finish, then retry.`,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
const targetHex = typeof ctx.params["target_pubkey"] === "string"
|
|
305
|
+
? ctx.params["target_pubkey"]
|
|
306
|
+
: typeof ctx.params["counterparty_pubkey"] === "string"
|
|
307
|
+
? ctx.params["counterparty_pubkey"]
|
|
308
|
+
: "";
|
|
309
|
+
if (!/^[0-9a-fA-F]{64}$/.test(targetHex)) {
|
|
310
|
+
return {
|
|
311
|
+
ok: false,
|
|
312
|
+
reason: "invalid_target_pubkey",
|
|
313
|
+
guidance: "cello_initiate_session requires 'target_pubkey' as the counterparty's 32-byte hex K_local public key.",
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const sr = sessionNodeManager.getStandingReceiverInfo(ctx.agentName);
|
|
317
|
+
if (!sr) {
|
|
318
|
+
return {
|
|
319
|
+
ok: false,
|
|
320
|
+
reason: "standing_receiver_unavailable",
|
|
321
|
+
guidance: "The standing receiver is not ready, so no initiator session endpoint can be advertised. Retry once the daemon has finished starting.",
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
const { signaling } = getAgentSignaling(ctx.agentName, kp, agentRec.pubkey);
|
|
325
|
+
if (!(await waitForSignalingConnected(signaling, 10_000))) {
|
|
326
|
+
return {
|
|
327
|
+
ok: false,
|
|
328
|
+
reason: "directory_signaling_timeout",
|
|
329
|
+
guidance: `Agent '${ctx.agentName}' could not establish its directory signaling stream within 10s. Check CELLO_DIRECTORY_URL and that the directory is reachable, then retry.`,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
// Single-flight claimed → the discover-first flow (one discovery + up to 3 session_request
|
|
333
|
+
// attempts, possibly over a transient visiting connection) runs under ONE slot; released in
|
|
334
|
+
// finally. A single directory-side echoed request id would allow true concurrency later.
|
|
335
|
+
negotiationInProgress.add(ctx.agentName);
|
|
336
|
+
try {
|
|
337
|
+
// DISCOVER FIRST. Because identity + presence are fully replicated, the agent's OWN home
|
|
338
|
+
// stream answers "where is the target?" authoritatively-enough (advisory — the target node's
|
|
339
|
+
// live #streams check stays the authority; a stale answer just triggers the retry below).
|
|
340
|
+
const homeNodeId = signaling.currentDirectoryNodeId;
|
|
341
|
+
const backoffs = [1_000, 3_000]; // between attempts — covers re-home + replication lag
|
|
342
|
+
const MAX_ATTEMPTS = 3;
|
|
343
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
344
|
+
const disc = await runDiscoveryLookup(signaling, targetHex, 5_000, ctx.correlationId);
|
|
345
|
+
// TRANSPORT: the home stream is down — retry (it may reconnect); local-only fallback would
|
|
346
|
+
// fail the same way. Exhausted → the TRUTHFUL transport reason, never a false "offline".
|
|
347
|
+
if (disc.kind === "send_failed") {
|
|
348
|
+
logger.warn("session.discovery.send_failed", { agentName: ctx.agentName, attempt, reason: disc.reason, correlationId: ctx.correlationId });
|
|
349
|
+
if (attempt < MAX_ATTEMPTS) {
|
|
350
|
+
await sleepMs(backoffs[attempt - 1]);
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
return { ok: false, reason: "directory_unreachable", guidance: "The home directory stream is not connected, so the counterparty's location could not be looked up. Check cello status (directory_signaling), then retry." };
|
|
354
|
+
}
|
|
355
|
+
// NO REPLY: an old directory (predates discovery) OR a slow/dropped reply on a new one. Retry;
|
|
356
|
+
// fall back to local-only behavior ONLY as a last resort (after the retries), so that a
|
|
357
|
+
// single dropped reply does not misroute a reachable cross-node peer to the home node.
|
|
358
|
+
if (disc.kind === "timeout") {
|
|
359
|
+
logger.warn("session.discovery.no_reply", { agentName: ctx.agentName, attempt, correlationId: ctx.correlationId });
|
|
360
|
+
if (attempt < MAX_ATTEMPTS) {
|
|
361
|
+
await sleepMs(backoffs[attempt - 1]);
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
logger.info("session.discovery.unsupported_fallback", { agentName: ctx.agentName, correlationId: ctx.correlationId });
|
|
365
|
+
return await runSessionRequestOverSignaling(signaling, targetHex, sr, ctx.correlationId, ctx.agentName);
|
|
366
|
+
}
|
|
367
|
+
// DIRECTORY-SIDE lookup fault (DB error / malformed reply): RETRYABLE — but a DIRECTORY fault,
|
|
368
|
+
// reported truthfully as directory_unreachable, NEVER as the counterparty being offline.
|
|
369
|
+
if (disc.kind === "error" || disc.kind === "malformed") {
|
|
370
|
+
logger.info("directory.discovery.lookup.retry", { agentName: ctx.agentName, attempt, kind: disc.kind, correlationId: ctx.correlationId });
|
|
371
|
+
if (attempt < MAX_ATTEMPTS) {
|
|
372
|
+
await sleepMs(backoffs[attempt - 1]);
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
return { ok: false, reason: "directory_unreachable", guidance: "The directory could not resolve the counterparty's location (a directory-side lookup error) after several attempts. Retry shortly." };
|
|
376
|
+
}
|
|
377
|
+
// A 3-state RESULT. Route it (pure classifier).
|
|
378
|
+
const action = classifyOnlineResult(disc.state, disc.owningNodeIds, homeNodeId);
|
|
379
|
+
// State 3: no such agent — a bad address, not a transient outage. NO retry (distinct code).
|
|
380
|
+
if (action.kind === "unknown_agent") {
|
|
381
|
+
return { ok: false, reason: "unknown_agent", guidance: "No agent is registered under that public key — the counterparty address is unknown. Verify the pubkey with the counterparty's operator." };
|
|
382
|
+
}
|
|
383
|
+
// State 2: known but offline. Definitive — NO retry storm.
|
|
384
|
+
if (action.kind === "offline") {
|
|
385
|
+
return { ok: false, reason: "counterparty_offline", guidance: "The counterparty exists but is not currently online. Have its operator bring it online (cello_status), then retry." };
|
|
386
|
+
}
|
|
387
|
+
// Online but no owner named — transient, re-discover.
|
|
388
|
+
if (action.kind === "retry") {
|
|
389
|
+
logger.info("directory.discovery.lookup.retry", { agentName: ctx.agentName, attempt, kind: "online_no_owner", correlationId: ctx.correlationId });
|
|
390
|
+
if (attempt < MAX_ATTEMPTS) {
|
|
391
|
+
await sleepMs(backoffs[attempt - 1]);
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
return { ok: false, reason: "counterparty_offline", guidance: "The directory reported the counterparty online but named no home node. Retry shortly." };
|
|
395
|
+
}
|
|
396
|
+
const result = action.kind === "same_node"
|
|
397
|
+
// SAME-NODE: the target is on the node we're already connected to. The existing path runs
|
|
398
|
+
// unchanged — ZERO visiting connections, ZERO new frames beyond the one discovery_lookup.
|
|
399
|
+
? await runSessionRequestOverSignaling(signaling, targetHex, sr, ctx.correlationId, ctx.agentName)
|
|
400
|
+
// CROSS-NODE: reach into the target's home over a transient visiting connection.
|
|
401
|
+
: await runCrossNodeSetup(ctx.agentName, kp, agentRec.pubkey, action.owningNodeId, targetHex, sr, ctx.correlationId);
|
|
402
|
+
// RETRY triggers: (a) the broker reported target_offline (stale replicated presence or a
|
|
403
|
+
// re-home between discovery and the request); (b) a transient visiting-connection failure
|
|
404
|
+
// (cross-region blip). Both re-discover → retry, bounded.
|
|
405
|
+
if (!result.ok && (result.reason === "target_offline" || result.reason === "visiting_connection_unreachable")) {
|
|
406
|
+
logger.info("session.crossnode.stale_discovery_retry", { agentName: ctx.agentName, attempt, reason: result.reason, correlationId: ctx.correlationId });
|
|
407
|
+
if (attempt < MAX_ATTEMPTS) {
|
|
408
|
+
await sleepMs(backoffs[attempt - 1]);
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
// Exhausted: keep the truthful transient-connection reason; a stale target_offline surfaces
|
|
412
|
+
// as counterparty_offline (state 2).
|
|
413
|
+
return result.reason === "visiting_connection_unreachable"
|
|
414
|
+
? { ok: false, reason: "visiting_connection_unreachable", guidance: "The counterparty's home node was reachable at discovery but its visiting connection could not be established after several attempts. Retry shortly." }
|
|
415
|
+
: { ok: false, reason: "counterparty_offline", guidance: "The counterparty was online at discovery but not reachable at its home node after several attempts (it may be re-homing). Retry shortly." };
|
|
416
|
+
}
|
|
417
|
+
return result;
|
|
418
|
+
}
|
|
419
|
+
return { ok: false, reason: "counterparty_offline", guidance: "Session establishment did not succeed after several attempts. Retry shortly." };
|
|
420
|
+
}
|
|
421
|
+
finally {
|
|
422
|
+
negotiationInProgress.delete(ctx.agentName);
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
};
|
|
426
|
+
// DAEMON-003: Initialize RetryQueue and NonceDedupStore (AC-008).
|
|
427
|
+
return { openVisitingConnection, crossNodeBrokerBySession, resolvedSessionNegotiator };
|
|
428
|
+
}
|
|
429
|
+
//# sourceMappingURL=outbound-sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-sessions.js","sourceRoot":"","sources":["../src/outbound-sessions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"park-envelope.d.ts","sourceRoot":"","sources":["../src/park-envelope.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"park-envelope.d.ts","sourceRoot":"","sources":["../src/park-envelope.ts"],"names":[],"mappings":"AA8BA,OAAO,EAA2B,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGnF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAW3F;AAED,sGAAsG;AACtG,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,MAAM,WAAW,YAAY;IAC3B,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,UAAU,CAAC;IACpB,+EAA+E;IAC/E,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,6DAA6D;IAC7D,YAAY,CAAC,EAAE,UAAU,CAAC;IAC1B,yEAAyE;IACzE,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AAED,MAAM,MAAM,eAAe,GACvB,mBAAmB,GACnB,eAAe,GACf,yBAAyB,GACzB,sBAAsB,CAAC;AAE3B,MAAM,MAAM,eAAe,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,CAAC;AAEpF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,OAAO,EAAE,UAAU,CAAC;IACpB,YAAY,EAAE,UAAU,CAAC;IACzB,OAAO,EAAE,UAAU,CAAC;IACpB,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,cAAc,CAAC,EAAE,UAAU,CAAC;CAC7B,GAAG,UAAU,CASb;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,MAAM,EAAE,WAAW,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,UAAU,CAAC;IAC5B,WAAW,EAAE,UAAU,CAAC;IACxB,OAAO,EAAE,UAAU,CAAC;IACpB,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,cAAc,CAAC,EAAE,UAAU,CAAC;CAC7B,GAAG,OAAO,CAAC,UAAU,CAAC,CAetB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,UAAU,GAAG,YAAY,CA0BtE;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,GAAG,EAAE,YAAY,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,UAAU,CAAC;IAC5B,WAAW,EAAE,UAAU,CAAC;IACxB,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C,GAAG,eAAe,CA8BlB"}
|
package/dist/park-envelope.js
CHANGED
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
* Crypto: Ed25519 (RFC 8032), SHA-256 (FIPS 180-4).
|
|
27
27
|
*/
|
|
28
28
|
import { timingSafeEqual } from "node:crypto";
|
|
29
|
-
import {
|
|
29
|
+
import { decode as cborDecode } from "cbor-x";
|
|
30
|
+
import { encodeCbor } from "@cello-protocol/protocol-types";
|
|
30
31
|
import { verify, sealToRecipient } from "@cello-protocol/crypto";
|
|
31
32
|
import { buildParkContentTbs } from "@cello-protocol/protocol-types";
|
|
32
33
|
/**
|
|
@@ -66,7 +67,7 @@ export const PARK_ENVELOPE_VERSION = 2;
|
|
|
66
67
|
* exact drift that made this a downgrade attack: verification existed, but was opt-in).
|
|
67
68
|
*/
|
|
68
69
|
export function encodeParkEnvelope(args) {
|
|
69
|
-
return
|
|
70
|
+
return encodeCbor([
|
|
70
71
|
PARK_ENVELOPE_VERSION,
|
|
71
72
|
args.content,
|
|
72
73
|
args.structure1Cbor ?? null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"park-envelope.js","sourceRoot":"","sources":["../src/park-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"park-envelope.js","sourceRoot":"","sources":["../src/park-envelope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { IpcHandler } from "./ipc-server.js";
|
|
2
|
+
import type { Logger } from "./types.js";
|
|
3
|
+
import type { KeyProvider } from "@cello-protocol/crypto";
|
|
4
|
+
import type { SignalingManager, CelloNode } from "@cello-protocol/transport";
|
|
5
|
+
import type { DbRegistrationPersistence } from "./db-identity-store.js";
|
|
6
|
+
import type { IManifestProvider } from "@cello-protocol/transport";
|
|
7
|
+
export interface RegisterHandlerDeps {
|
|
8
|
+
handlers: Map<string, IpcHandler>;
|
|
9
|
+
logger: Logger;
|
|
10
|
+
keyProviders: Map<string, KeyProvider>;
|
|
11
|
+
getPersistence: (agentName: string) => DbRegistrationPersistence;
|
|
12
|
+
getAgentSignaling: (agentName: string, keyProvider: KeyProvider, pubkeyHex: string) => {
|
|
13
|
+
signaling: SignalingManager;
|
|
14
|
+
getNode: () => CelloNode | null;
|
|
15
|
+
};
|
|
16
|
+
waitForSignalingConnected: (mgr: SignalingManager, timeoutMs: number) => Promise<boolean>;
|
|
17
|
+
dropAgentSignaling: (agentName: string) => Promise<void>;
|
|
18
|
+
startAgentInternal: (name: string) => {
|
|
19
|
+
ok: true;
|
|
20
|
+
} | {
|
|
21
|
+
ok: false;
|
|
22
|
+
reason: string;
|
|
23
|
+
guidance: string;
|
|
24
|
+
};
|
|
25
|
+
directoryEndpointResolver?: () => Promise<import("./signaling-connect.js").DirectoryEndpoint | null>;
|
|
26
|
+
loadedAgents: Array<{
|
|
27
|
+
name: string;
|
|
28
|
+
pubkey: string;
|
|
29
|
+
keyProvider: KeyProvider;
|
|
30
|
+
}>;
|
|
31
|
+
registrationGuidance: (reason: string) => string;
|
|
32
|
+
manifestProvider?: IManifestProvider;
|
|
33
|
+
}
|
|
34
|
+
export declare function registerRegisterHandler(deps: RegisterHandlerDeps): void;
|
|
35
|
+
//# sourceMappingURL=register-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-handler.d.ts","sourceRoot":"","sources":["../src/register-handler.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAKnE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACvC,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,yBAAyB,CAAC;IACjE,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,KAAK;QAAE,SAAS,EAAE,gBAAgB,CAAC;QAAC,OAAO,EAAE,MAAM,SAAS,GAAG,IAAI,CAAA;KAAE,CAAC;IACxJ,yBAAyB,EAAE,CAAC,GAAG,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1F,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACrG,yBAAyB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,wBAAwB,EAAE,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACrG,YAAY,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,WAAW,CAAA;KAAE,CAAC,CAAC;IAChF,oBAAoB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IACjD,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;CACtC;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAmKvE"}
|