@cello-protocol/client 0.0.4 → 0.0.6
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/db/migrations/V1__client_schema.sql +21 -0
- package/db/migrations/V2__client_schema_structured.sql +274 -0
- package/dist/client.d.ts +7 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +84 -15
- package/dist/client.js.map +1 -1
- package/dist/mcp-server.d.ts +17 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +275 -18
- package/dist/mcp-server.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- V1__client_schema.sql
|
|
2
|
+
-- CELLO-PERSIST-009: Initial client-side encrypted database schema.
|
|
3
|
+
--
|
|
4
|
+
-- Tables:
|
|
5
|
+
-- client_store — opaque key/value blob store (implements ClientStore interface)
|
|
6
|
+
--
|
|
7
|
+
-- Note: schema_migrations is NOT created here. The migration runner bootstraps
|
|
8
|
+
-- that table itself before executing any migration files, so it must not appear
|
|
9
|
+
-- inside a migration transaction.
|
|
10
|
+
--
|
|
11
|
+
-- All data at rest is protected by SQLCipher (AES-256-CBC with PBKDF2 key derivation).
|
|
12
|
+
-- The db_key is never stored here — it is derived at runtime from identity_key via HKDF.
|
|
13
|
+
|
|
14
|
+
-- Opaque key/value store backing the ClientStore interface.
|
|
15
|
+
-- key: stable string identifier (session keys, trust data, key material, etc.)
|
|
16
|
+
-- value: raw bytes (BLOB)
|
|
17
|
+
CREATE TABLE IF NOT EXISTS client_store (
|
|
18
|
+
key TEXT NOT NULL PRIMARY KEY,
|
|
19
|
+
value BLOB NOT NULL,
|
|
20
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
21
|
+
);
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
-- V2__client_schema_structured.sql
|
|
2
|
+
-- CELLO-PERSIST-024: Structured client-side SQLCipher schema.
|
|
3
|
+
--
|
|
4
|
+
-- This migration:
|
|
5
|
+
-- 1. Drops the V1 client_store table (placeholder KV store, no production users)
|
|
6
|
+
-- 2. Creates 18 structured tables covering all durable state
|
|
7
|
+
--
|
|
8
|
+
-- All data at rest is protected by SQLCipher (AES-256-CBC with PBKDF2 key derivation).
|
|
9
|
+
-- The db_key is never stored here — derived at runtime from K_local via HKDF.
|
|
10
|
+
|
|
11
|
+
-- Drop the placeholder KV table — all state migrates to structured tables.
|
|
12
|
+
DROP TABLE IF EXISTS client_store;
|
|
13
|
+
|
|
14
|
+
-- ── 1. agents ────────────────────────────────────────────────
|
|
15
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
16
|
+
pubkey TEXT NOT NULL,
|
|
17
|
+
agent_name TEXT NOT NULL DEFAULT '',
|
|
18
|
+
key_file_path TEXT NOT NULL,
|
|
19
|
+
ml_dsa_key_file_path TEXT,
|
|
20
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
21
|
+
last_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
22
|
+
is_active INTEGER NOT NULL DEFAULT 1,
|
|
23
|
+
PRIMARY KEY (pubkey)
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
-- ── 2. registration_state ────────────────────────────────────
|
|
27
|
+
CREATE TABLE IF NOT EXISTS registration_state (
|
|
28
|
+
agent_pubkey TEXT NOT NULL,
|
|
29
|
+
agent_id TEXT NOT NULL,
|
|
30
|
+
primary_pubkey TEXT NOT NULL,
|
|
31
|
+
ml_dsa_pubkey TEXT NOT NULL,
|
|
32
|
+
registered_at INTEGER NOT NULL,
|
|
33
|
+
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active')),
|
|
34
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
35
|
+
PRIMARY KEY (agent_pubkey),
|
|
36
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE,
|
|
37
|
+
UNIQUE (agent_id)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
-- ── 3. frost_key_shares ──────────────────────────────────────
|
|
41
|
+
CREATE TABLE IF NOT EXISTS frost_key_shares (
|
|
42
|
+
agent_pubkey TEXT NOT NULL,
|
|
43
|
+
epoch_id TEXT NOT NULL,
|
|
44
|
+
primary_pubkey TEXT NOT NULL,
|
|
45
|
+
identifier TEXT NOT NULL,
|
|
46
|
+
signing_share BLOB NOT NULL,
|
|
47
|
+
threshold INTEGER NOT NULL,
|
|
48
|
+
participants INTEGER NOT NULL,
|
|
49
|
+
commitments_cbor BLOB NOT NULL,
|
|
50
|
+
verifying_shares_cbor BLOB NOT NULL,
|
|
51
|
+
dkg_method TEXT NOT NULL CHECK (dkg_method IN ('trusted_dealer','network_dkg')),
|
|
52
|
+
is_active INTEGER NOT NULL DEFAULT 1,
|
|
53
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
54
|
+
validated_at TEXT,
|
|
55
|
+
PRIMARY KEY (agent_pubkey, epoch_id),
|
|
56
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE
|
|
57
|
+
);
|
|
58
|
+
CREATE UNIQUE INDEX IF NOT EXISTS uq_frost_key_shares_active
|
|
59
|
+
ON frost_key_shares(agent_pubkey) WHERE is_active = 1;
|
|
60
|
+
|
|
61
|
+
-- ── 4. ml_dsa_keypairs ───────────────────────────────────────
|
|
62
|
+
CREATE TABLE IF NOT EXISTS ml_dsa_keypairs (
|
|
63
|
+
agent_pubkey TEXT NOT NULL,
|
|
64
|
+
ml_dsa_pubkey TEXT NOT NULL,
|
|
65
|
+
secret_key_blob BLOB NOT NULL,
|
|
66
|
+
algorithm TEXT NOT NULL DEFAULT 'ML-DSA-44',
|
|
67
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
68
|
+
PRIMARY KEY (agent_pubkey),
|
|
69
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
-- ── 5. connection_policy ─────────────────────────────────────
|
|
73
|
+
CREATE TABLE IF NOT EXISTS connection_policy (
|
|
74
|
+
agent_pubkey TEXT NOT NULL,
|
|
75
|
+
mode TEXT NOT NULL CHECK (mode IN ('open','selective','guarded','closed')),
|
|
76
|
+
review_mode TEXT NOT NULL CHECK (review_mode IN ('deterministic','inference')),
|
|
77
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
78
|
+
PRIMARY KEY (agent_pubkey),
|
|
79
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
-- ── 6. connection_policy_requirements ───────────────────────
|
|
83
|
+
CREATE TABLE IF NOT EXISTS connection_policy_requirements (
|
|
84
|
+
agent_pubkey TEXT NOT NULL,
|
|
85
|
+
position INTEGER NOT NULL,
|
|
86
|
+
signal_type TEXT NOT NULL CHECK (signal_type IN ('endorsement','attestation','pseudonym_age','registration_age')),
|
|
87
|
+
condition_json TEXT NOT NULL,
|
|
88
|
+
PRIMARY KEY (agent_pubkey, position),
|
|
89
|
+
FOREIGN KEY (agent_pubkey) REFERENCES connection_policy(agent_pubkey) ON DELETE CASCADE
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
-- ── 7. connections ───────────────────────────────────────────
|
|
93
|
+
CREATE TABLE IF NOT EXISTS connections (
|
|
94
|
+
connection_id TEXT NOT NULL,
|
|
95
|
+
agent_pubkey TEXT NOT NULL,
|
|
96
|
+
counterparty_pubkey TEXT NOT NULL,
|
|
97
|
+
counterparty_primary_pubkey TEXT NOT NULL DEFAULT '',
|
|
98
|
+
counterparty_ml_dsa_pubkey TEXT NOT NULL DEFAULT '',
|
|
99
|
+
established_at INTEGER NOT NULL,
|
|
100
|
+
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active')),
|
|
101
|
+
profile_unchecked INTEGER NOT NULL DEFAULT 0,
|
|
102
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
103
|
+
PRIMARY KEY (connection_id),
|
|
104
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE,
|
|
105
|
+
UNIQUE (agent_pubkey, counterparty_pubkey)
|
|
106
|
+
);
|
|
107
|
+
CREATE INDEX IF NOT EXISTS idx_connections_agent ON connections(agent_pubkey);
|
|
108
|
+
|
|
109
|
+
-- ── 8. endorsements ──────────────────────────────────────────
|
|
110
|
+
CREATE TABLE IF NOT EXISTS endorsements (
|
|
111
|
+
agent_pubkey TEXT NOT NULL,
|
|
112
|
+
endorser_pubkey TEXT NOT NULL,
|
|
113
|
+
endorser_ml_dsa_pubkey BLOB NOT NULL,
|
|
114
|
+
target_pubkey TEXT NOT NULL,
|
|
115
|
+
endorsement_type TEXT NOT NULL,
|
|
116
|
+
created_at INTEGER NOT NULL,
|
|
117
|
+
expires_at INTEGER NOT NULL,
|
|
118
|
+
endorser_ml_dsa_sig BLOB NOT NULL,
|
|
119
|
+
received_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
120
|
+
PRIMARY KEY (agent_pubkey, endorser_pubkey),
|
|
121
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE
|
|
122
|
+
);
|
|
123
|
+
CREATE INDEX IF NOT EXISTS idx_endorsements_expires ON endorsements(expires_at);
|
|
124
|
+
|
|
125
|
+
-- ── 9. attestations ──────────────────────────────────────────
|
|
126
|
+
CREATE TABLE IF NOT EXISTS attestations (
|
|
127
|
+
agent_pubkey TEXT NOT NULL,
|
|
128
|
+
attester_pubkey TEXT NOT NULL,
|
|
129
|
+
attestation_type TEXT NOT NULL,
|
|
130
|
+
attester_ml_dsa_pubkey BLOB NOT NULL,
|
|
131
|
+
attestation_data BLOB NOT NULL,
|
|
132
|
+
created_at INTEGER NOT NULL,
|
|
133
|
+
expires_at INTEGER NOT NULL,
|
|
134
|
+
attester_ml_dsa_sig BLOB NOT NULL,
|
|
135
|
+
received_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
136
|
+
PRIMARY KEY (agent_pubkey, attester_pubkey, attestation_type),
|
|
137
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE
|
|
138
|
+
);
|
|
139
|
+
CREATE INDEX IF NOT EXISTS idx_attestations_expires ON attestations(expires_at);
|
|
140
|
+
|
|
141
|
+
-- ── 10. peers ────────────────────────────────────────────────
|
|
142
|
+
CREATE TABLE IF NOT EXISTS peers (
|
|
143
|
+
agent_pubkey TEXT NOT NULL,
|
|
144
|
+
peer_pubkey_hex TEXT NOT NULL,
|
|
145
|
+
peer_id TEXT NOT NULL,
|
|
146
|
+
multiaddrs TEXT NOT NULL,
|
|
147
|
+
added_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
148
|
+
last_seen_at TEXT,
|
|
149
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
150
|
+
PRIMARY KEY (agent_pubkey, peer_pubkey_hex),
|
|
151
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE
|
|
152
|
+
);
|
|
153
|
+
CREATE UNIQUE INDEX IF NOT EXISTS uq_peers_peer_id ON peers(agent_pubkey, peer_id);
|
|
154
|
+
|
|
155
|
+
-- ── 11. sessions ─────────────────────────────────────────────
|
|
156
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
157
|
+
session_id TEXT NOT NULL,
|
|
158
|
+
agent_pubkey TEXT NOT NULL,
|
|
159
|
+
counterparty_pubkey BLOB NOT NULL,
|
|
160
|
+
counterparty_peer_id TEXT NOT NULL,
|
|
161
|
+
counterparty_multiaddrs TEXT NOT NULL,
|
|
162
|
+
relay_peer_id TEXT NOT NULL,
|
|
163
|
+
relay_multiaddrs TEXT NOT NULL,
|
|
164
|
+
directory_peer_id TEXT NOT NULL,
|
|
165
|
+
directory_multiaddrs TEXT NOT NULL,
|
|
166
|
+
directory_pubkey BLOB NOT NULL,
|
|
167
|
+
genesis_prev_root BLOB NOT NULL,
|
|
168
|
+
last_seen_seq INTEGER NOT NULL DEFAULT 0,
|
|
169
|
+
last_sent_seq INTEGER NOT NULL DEFAULT 0,
|
|
170
|
+
next_expected_seq INTEGER NOT NULL DEFAULT 1,
|
|
171
|
+
status TEXT NOT NULL CHECK (status IN ('active','transport_lost','sealing','sealed','seal_rejected','seal_deferred')),
|
|
172
|
+
desynchronized INTEGER NOT NULL DEFAULT 0,
|
|
173
|
+
leaf_count INTEGER NOT NULL DEFAULT 0,
|
|
174
|
+
sealed_root BLOB,
|
|
175
|
+
seal_type TEXT CHECK (seal_type IN ('frost','bilateral','unilateral')),
|
|
176
|
+
close_timestamp INTEGER,
|
|
177
|
+
frost_signature BLOB,
|
|
178
|
+
signer_pubkey BLOB,
|
|
179
|
+
directory_signature BLOB,
|
|
180
|
+
checkpoint_status TEXT NOT NULL DEFAULT 'pending' CHECK (checkpoint_status IN ('pending','confirmed')),
|
|
181
|
+
checkpoint_peak_hash TEXT,
|
|
182
|
+
checkpoint_leaf_index INTEGER,
|
|
183
|
+
checkpoint_sibling_hashes TEXT,
|
|
184
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
185
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
186
|
+
PRIMARY KEY (session_id, agent_pubkey),
|
|
187
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE
|
|
188
|
+
);
|
|
189
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_agent ON sessions(agent_pubkey, status);
|
|
190
|
+
|
|
191
|
+
-- ── 12. session_tree_leaves ──────────────────────────────────
|
|
192
|
+
CREATE TABLE IF NOT EXISTS session_tree_leaves (
|
|
193
|
+
session_id TEXT NOT NULL,
|
|
194
|
+
agent_pubkey TEXT NOT NULL,
|
|
195
|
+
leaf_index INTEGER NOT NULL,
|
|
196
|
+
leaf_kind TEXT NOT NULL CHECK (leaf_kind IN ('msg','ctrl')),
|
|
197
|
+
s2_cbor BLOB NOT NULL,
|
|
198
|
+
sequence_number INTEGER NOT NULL,
|
|
199
|
+
accepted_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
200
|
+
PRIMARY KEY (session_id, agent_pubkey, leaf_index),
|
|
201
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE,
|
|
202
|
+
FOREIGN KEY (session_id, agent_pubkey) REFERENCES sessions(session_id, agent_pubkey) ON DELETE CASCADE
|
|
203
|
+
);
|
|
204
|
+
CREATE INDEX IF NOT EXISTS idx_session_tree_leaves_seq
|
|
205
|
+
ON session_tree_leaves(session_id, agent_pubkey, sequence_number);
|
|
206
|
+
|
|
207
|
+
-- ── 13. pending_hashes ───────────────────────────────────────
|
|
208
|
+
CREATE TABLE IF NOT EXISTS pending_hashes (
|
|
209
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
|
210
|
+
agent_pubkey TEXT NOT NULL,
|
|
211
|
+
session_id TEXT NOT NULL,
|
|
212
|
+
hash_hex TEXT NOT NULL,
|
|
213
|
+
enqueued_at INTEGER NOT NULL,
|
|
214
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE,
|
|
215
|
+
UNIQUE (agent_pubkey, session_id, hash_hex)
|
|
216
|
+
);
|
|
217
|
+
CREATE INDEX IF NOT EXISTS idx_pending_hashes_agent_session
|
|
218
|
+
ON pending_hashes(agent_pubkey, session_id);
|
|
219
|
+
|
|
220
|
+
-- ── 14. relay_ack_receipts ───────────────────────────────────
|
|
221
|
+
CREATE TABLE IF NOT EXISTS relay_ack_receipts (
|
|
222
|
+
hash_hex TEXT NOT NULL,
|
|
223
|
+
agent_pubkey TEXT NOT NULL,
|
|
224
|
+
session_id TEXT NOT NULL,
|
|
225
|
+
relay_id TEXT NOT NULL,
|
|
226
|
+
relay_pubkey_hex TEXT NOT NULL,
|
|
227
|
+
sequence_number INTEGER NOT NULL,
|
|
228
|
+
relay_timestamp INTEGER NOT NULL,
|
|
229
|
+
signature_hex TEXT NOT NULL,
|
|
230
|
+
acked_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
231
|
+
PRIMARY KEY (hash_hex, agent_pubkey),
|
|
232
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
-- ── 15. backup_metadata ──────────────────────────────────────
|
|
236
|
+
CREATE TABLE IF NOT EXISTS backup_metadata (
|
|
237
|
+
agent_pubkey TEXT NOT NULL,
|
|
238
|
+
completed_at TEXT NOT NULL,
|
|
239
|
+
destination_url TEXT NOT NULL,
|
|
240
|
+
checksum TEXT NOT NULL,
|
|
241
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
242
|
+
PRIMARY KEY (agent_pubkey),
|
|
243
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
-- ── 16. known_relays ─────────────────────────────────────────
|
|
247
|
+
CREATE TABLE IF NOT EXISTS known_relays (
|
|
248
|
+
relay_id TEXT NOT NULL PRIMARY KEY,
|
|
249
|
+
relay_pubkey_hex TEXT NOT NULL,
|
|
250
|
+
source TEXT NOT NULL,
|
|
251
|
+
last_seen_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
-- ── 17. pending_connection_requests ──────────────────────────
|
|
255
|
+
CREATE TABLE IF NOT EXISTS pending_connection_requests (
|
|
256
|
+
request_id TEXT NOT NULL,
|
|
257
|
+
agent_pubkey TEXT NOT NULL,
|
|
258
|
+
from_pubkey TEXT NOT NULL,
|
|
259
|
+
package_cbor BLOB NOT NULL,
|
|
260
|
+
arrived_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
261
|
+
round INTEGER NOT NULL DEFAULT 1,
|
|
262
|
+
PRIMARY KEY (request_id, agent_pubkey),
|
|
263
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
-- ── 18. decided_connection_requests ──────────────────────────
|
|
267
|
+
CREATE TABLE IF NOT EXISTS decided_connection_requests (
|
|
268
|
+
request_id TEXT NOT NULL,
|
|
269
|
+
agent_pubkey TEXT NOT NULL,
|
|
270
|
+
decision TEXT NOT NULL CHECK (decision IN ('accepted','rejected','more_disclosure')),
|
|
271
|
+
decided_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
272
|
+
PRIMARY KEY (request_id, agent_pubkey),
|
|
273
|
+
FOREIGN KEY (agent_pubkey) REFERENCES agents(pubkey) ON DELETE CASCADE
|
|
274
|
+
);
|
package/dist/client.d.ts
CHANGED
|
@@ -162,10 +162,15 @@ export declare function createClient(node: CelloNode, keyProvider: KeyProvider,
|
|
|
162
162
|
}): void;
|
|
163
163
|
/** CONNREQ-002: list active connection records. */
|
|
164
164
|
listConnections(): import("@cello-protocol/protocol-types").ClientConnectionRecord[];
|
|
165
|
-
/** CONNREQ-002: send connection_request to target B and await final outcome.
|
|
165
|
+
/** CONNREQ-002 / AC-008 (DX-001): send connection_request to target B and await final outcome.
|
|
166
|
+
* Per-stage timeouts: dialTimeoutMs (stage 'dial'), sendTimeoutMs (stage 'send'),
|
|
167
|
+
* waitTimeoutMs (stage 'wait'). Timeout result includes the stage that fired. */
|
|
166
168
|
cello_request_connection(opts: {
|
|
167
169
|
target_pubkey: string;
|
|
168
170
|
package_cbor: Uint8Array;
|
|
171
|
+
dialTimeoutMs?: number;
|
|
172
|
+
sendTimeoutMs?: number;
|
|
173
|
+
waitTimeoutMs?: number;
|
|
169
174
|
}): Promise<{
|
|
170
175
|
result: "established";
|
|
171
176
|
connection_id: string;
|
|
@@ -181,6 +186,7 @@ export declare function createClient(node: CelloNode, keyProvider: KeyProvider,
|
|
|
181
186
|
requested_items: unknown[];
|
|
182
187
|
} | {
|
|
183
188
|
result: "timeout";
|
|
189
|
+
stage: "dial" | "send" | "wait";
|
|
184
190
|
} | {
|
|
185
191
|
result: "error";
|
|
186
192
|
reason: string;
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2GG;AAaH,OAAO,KAAK,EAAa,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAG1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EACV,WAAW,EAA+B,UAAU,EAAE,aAAa,EAGpE,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -491,13 +491,24 @@ class CelloClientImpl {
|
|
|
491
491
|
return;
|
|
492
492
|
}
|
|
493
493
|
// Reconstruct FrostThresholdSigner (config only — secret is in module-level store).
|
|
494
|
-
//
|
|
495
|
-
//
|
|
494
|
+
// AC-003 (DX-001): directoryNodeStubs MUST be populated from the current directoryEndpoint
|
|
495
|
+
// so that the signer can participate in FROST signing ceremonies (round-trip frames
|
|
496
|
+
// to directory via libp2p). Without directoryNodeStubs, the signer can verify but cannot
|
|
497
|
+
// participate in ceremonies — causing directory_below_threshold on session initiation.
|
|
496
498
|
if (!this.#thresholdSigner) {
|
|
499
|
+
let directoryNodeStubsForSigner;
|
|
500
|
+
if (this.#directoryEndpoint) {
|
|
501
|
+
directoryNodeStubsForSigner = [new NetworkDirectoryNode({
|
|
502
|
+
id: this.#directoryEndpoint.peer_id,
|
|
503
|
+
node: this.#node,
|
|
504
|
+
directoryPeerId: this.#directoryEndpoint.peer_id,
|
|
505
|
+
directoryMultiaddrs: this.#directoryEndpoint.multiaddrs,
|
|
506
|
+
})];
|
|
507
|
+
}
|
|
497
508
|
this.#thresholdSigner = new FrostThresholdSigner({
|
|
498
509
|
threshold: row.threshold,
|
|
499
510
|
participants: row.participants,
|
|
500
|
-
|
|
511
|
+
directoryNodeStubs: directoryNodeStubsForSigner,
|
|
501
512
|
}, Buffer.from(myPubkeyHex, "hex"));
|
|
502
513
|
}
|
|
503
514
|
// Set primary_pubkey from stored commitments[0]
|
|
@@ -782,6 +793,29 @@ class CelloClientImpl {
|
|
|
782
793
|
setHashQueue(queue) {
|
|
783
794
|
this.#hashQueue = queue;
|
|
784
795
|
}
|
|
796
|
+
/**
|
|
797
|
+
* AC-003 (DX-001): Set directory endpoint after construction (composition root pattern).
|
|
798
|
+
* Called by cello-mcp.ts background task before loadPersistedState() so that
|
|
799
|
+
* loadPersistedState() can populate directoryNodeStubs in the reconstructed FrostThresholdSigner.
|
|
800
|
+
*/
|
|
801
|
+
setDirectoryEndpoint(endpoint) {
|
|
802
|
+
this.#directoryEndpoint = endpoint;
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* AC-003 (DX-001): Wire threshold signer after construction.
|
|
806
|
+
* Called by cello-mcp.ts background task only when the agent is not yet registered
|
|
807
|
+
* (bootstrap ran). Registered agents reconstruct the signer from DB in loadPersistedState().
|
|
808
|
+
*/
|
|
809
|
+
setThresholdSigner(signer) {
|
|
810
|
+
this.#thresholdSigner = signer;
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* PERSIST-024: Wire persistence layer after construction.
|
|
814
|
+
* Called by cello-mcp.ts background task after SQLCipher store opens.
|
|
815
|
+
*/
|
|
816
|
+
setPersistence(persistence) {
|
|
817
|
+
this.#persistence = persistence;
|
|
818
|
+
}
|
|
785
819
|
addPeer(peerPubkeyHex, peerId, multiaddrs) {
|
|
786
820
|
this.#peers.set(peerPubkeyHex, { peerId, multiaddrs, connected: true });
|
|
787
821
|
// PERSIST-024: persist peer to DB
|
|
@@ -3189,7 +3223,7 @@ class CelloClientImpl {
|
|
|
3189
3223
|
*
|
|
3190
3224
|
* Crypto refs: NIST FIPS 204 (ML-DSA-44), RFC 9591 (FROST), FIPS 180-4 (SHA-256)
|
|
3191
3225
|
*/
|
|
3192
|
-
async register(phoneStub, preAuthToken) {
|
|
3226
|
+
async register(phoneStub = "", preAuthToken) {
|
|
3193
3227
|
// Step 1: already registered — return error
|
|
3194
3228
|
if (this.#registrationState) {
|
|
3195
3229
|
return { error: "already_registered" };
|
|
@@ -3765,8 +3799,13 @@ class CelloClientImpl {
|
|
|
3765
3799
|
* { result: 'rejected', reason } — target rejected
|
|
3766
3800
|
* { result: 'insufficient', unmet_requirements } — target found requirements unmet
|
|
3767
3801
|
* { result: 'disclosure_requested', connection_request_id, requested_items } — Round 2 request (unblocks sender)
|
|
3768
|
-
* { result: 'timeout' } — no response within
|
|
3802
|
+
* { result: 'timeout', stage } — no response within timeout; stage identifies which phase timed out
|
|
3769
3803
|
* { result: 'error', reason } — directory-level error (not_registered, target_not_found, etc.)
|
|
3804
|
+
*
|
|
3805
|
+
* AC-008 (DX-001): per-stage timeouts:
|
|
3806
|
+
* dialTimeoutMs — stage 'dial': timeout for opening the persistent signaling stream (default: connectionTimeoutMs)
|
|
3807
|
+
* sendTimeoutMs — stage 'send': timeout for sending the frame (default: connectionTimeoutMs)
|
|
3808
|
+
* waitTimeoutMs — stage 'wait': timeout for target response (default: connectionTimeoutMs)
|
|
3770
3809
|
*/
|
|
3771
3810
|
async cello_request_connection(opts) {
|
|
3772
3811
|
const targetPubkeyHex = opts.target_pubkey;
|
|
@@ -3786,12 +3825,22 @@ class CelloClientImpl {
|
|
|
3786
3825
|
resolveOutcome = resolve;
|
|
3787
3826
|
});
|
|
3788
3827
|
this.#pendingConnectionRequestResolvers.set(targetPubkeyHex, resolveOutcome);
|
|
3789
|
-
//
|
|
3828
|
+
// AC-008 (DX-001): per-stage timeouts. Fall back to #connectionTimeoutMs if not provided.
|
|
3829
|
+
const dialTimeoutMs = opts.dialTimeoutMs ?? this.#connectionTimeoutMs;
|
|
3830
|
+
const sendTimeoutMs = opts.sendTimeoutMs ?? this.#connectionTimeoutMs;
|
|
3831
|
+
const waitTimeoutMs = opts.waitTimeoutMs ?? this.#connectionTimeoutMs;
|
|
3832
|
+
// Stage 1 — dial: Ensure the persistent signaling stream is open within dialTimeoutMs.
|
|
3790
3833
|
if (!this.#persistentSignalingStream) {
|
|
3791
|
-
|
|
3792
|
-
|
|
3834
|
+
let dialTimedOut = false;
|
|
3835
|
+
let opened = false;
|
|
3836
|
+
await Promise.race([
|
|
3837
|
+
this.#openPersistentSignalingStream().then((result) => { opened = result; }),
|
|
3838
|
+
new Promise((resolve) => setTimeout(() => { dialTimedOut = true; resolve(); }, dialTimeoutMs)),
|
|
3839
|
+
]);
|
|
3840
|
+
if (dialTimedOut || !opened) {
|
|
3793
3841
|
this.#pendingConnectionRequestResolvers.delete(targetPubkeyHex);
|
|
3794
|
-
|
|
3842
|
+
this.#logger.warn("client.connection.request.stage.timeout", { stage: "dial", timeoutMs: dialTimeoutMs, targetPubkeyOrAgentId: targetPubkeyHex });
|
|
3843
|
+
return { result: "timeout", stage: "dial" };
|
|
3795
3844
|
}
|
|
3796
3845
|
}
|
|
3797
3846
|
// Mint a correlationId for this outbound connection request flow.
|
|
@@ -3804,20 +3853,39 @@ class CelloClientImpl {
|
|
|
3804
3853
|
target_pubkey: targetPubkeyHex,
|
|
3805
3854
|
package_cbor: opts.package_cbor,
|
|
3806
3855
|
});
|
|
3807
|
-
|
|
3808
|
-
|
|
3856
|
+
// Stage 2 — send: Deliver the frame within sendTimeoutMs.
|
|
3857
|
+
// The .send() call is synchronous but may throw if the stream has disconnected.
|
|
3858
|
+
// Wrap in a race so an unresponsive stream doesn't block indefinitely.
|
|
3859
|
+
let sendTimedOut = false;
|
|
3860
|
+
let sendError = false;
|
|
3861
|
+
await Promise.race([
|
|
3862
|
+
new Promise((resolve) => {
|
|
3863
|
+
try {
|
|
3864
|
+
this.#persistentSignalingStream.send(lp.encode.single(frameBytes));
|
|
3865
|
+
}
|
|
3866
|
+
catch {
|
|
3867
|
+
sendError = true;
|
|
3868
|
+
}
|
|
3869
|
+
resolve();
|
|
3870
|
+
}),
|
|
3871
|
+
new Promise((resolve) => setTimeout(() => { sendTimedOut = true; resolve(); }, sendTimeoutMs)),
|
|
3872
|
+
]);
|
|
3873
|
+
if (sendTimedOut) {
|
|
3874
|
+
this.#pendingConnectionRequestResolvers.delete(targetPubkeyHex);
|
|
3875
|
+
this.#logger.warn("client.connection.request.stage.timeout", { stage: "send", timeoutMs: sendTimeoutMs, targetPubkeyOrAgentId: targetPubkeyHex });
|
|
3876
|
+
return { result: "timeout", stage: "send" };
|
|
3809
3877
|
}
|
|
3810
|
-
|
|
3878
|
+
if (sendError) {
|
|
3811
3879
|
this.#pendingConnectionRequestResolvers.delete(targetPubkeyHex);
|
|
3812
3880
|
return { result: "error", reason: "directory_unreachable" };
|
|
3813
3881
|
}
|
|
3814
|
-
//
|
|
3882
|
+
// Stage 3 — wait: Race outcome vs waitTimeoutMs (was: connectionTimeoutMs).
|
|
3815
3883
|
// DB-001: timeout cleans this slot without affecting concurrent requests to other targets.
|
|
3816
3884
|
let frame = null;
|
|
3817
3885
|
let timedOut = false;
|
|
3818
3886
|
await Promise.race([
|
|
3819
3887
|
outcomePromise.then((f) => { frame = f; }),
|
|
3820
|
-
new Promise((resolve) => setTimeout(() => { timedOut = true; resolve(); },
|
|
3888
|
+
new Promise((resolve) => setTimeout(() => { timedOut = true; resolve(); }, waitTimeoutMs)),
|
|
3821
3889
|
]);
|
|
3822
3890
|
// Clean up this target's resolver slot on timeout
|
|
3823
3891
|
// (on successful resolution, the signaling reader already deleted it)
|
|
@@ -3825,7 +3893,8 @@ class CelloClientImpl {
|
|
|
3825
3893
|
this.#pendingConnectionRequestResolvers.delete(targetPubkeyHex);
|
|
3826
3894
|
}
|
|
3827
3895
|
if (timedOut || !frame) {
|
|
3828
|
-
|
|
3896
|
+
this.#logger.warn("client.connection.request.stage.timeout", { stage: "wait", timeoutMs: waitTimeoutMs, targetPubkeyOrAgentId: targetPubkeyHex });
|
|
3897
|
+
return { result: "timeout", stage: "wait" };
|
|
3829
3898
|
}
|
|
3830
3899
|
const type = frame["type"];
|
|
3831
3900
|
if (type === "connection_established") {
|