@cello-protocol/client 0.0.5 → 0.0.7

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/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;
@@ -256,5 +262,7 @@ export declare function createClient(node: CelloNode, keyProvider: KeyProvider,
256
262
  hashHex: string;
257
263
  enqueuedAt: number;
258
264
  }>;
265
+ /** Open the persistent signaling stream to the directory if not already open. Call after setDirectoryEndpoint(). */
266
+ announceToDirectory(): Promise<void>;
259
267
  };
260
268
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
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
- // HIGH-1: directoryEndpoint is NOT required for construction — the signer can verify
495
- // signatures even without a live directory. Pass undefined for directoryNodes.
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
- directoryNodes: undefined,
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
@@ -3164,6 +3198,17 @@ class CelloClientImpl {
3164
3198
  });
3165
3199
  }
3166
3200
  }
3201
+ /**
3202
+ * Open the persistent signaling stream to the directory if not already open.
3203
+ * Call this after setDirectoryEndpoint() to announce presence to the directory.
3204
+ * Safe to call multiple times — no-op if stream is already open.
3205
+ * Best-effort: failure is non-fatal.
3206
+ */
3207
+ async announceToDirectory() {
3208
+ if (this.#directoryEndpoint && !this.#persistentSignalingStream) {
3209
+ await this.#openPersistentSignalingStream().catch(() => { });
3210
+ }
3211
+ }
3167
3212
  // ─── REG-001: Agent registration ─────────────────────────────────────────────
3168
3213
  /**
3169
3214
  * Register this agent with the directory.
@@ -3189,7 +3234,7 @@ class CelloClientImpl {
3189
3234
  *
3190
3235
  * Crypto refs: NIST FIPS 204 (ML-DSA-44), RFC 9591 (FROST), FIPS 180-4 (SHA-256)
3191
3236
  */
3192
- async register(phoneStub, preAuthToken) {
3237
+ async register(phoneStub = "", preAuthToken) {
3193
3238
  // Step 1: already registered — return error
3194
3239
  if (this.#registrationState) {
3195
3240
  return { error: "already_registered" };
@@ -3765,8 +3810,13 @@ class CelloClientImpl {
3765
3810
  * { result: 'rejected', reason } — target rejected
3766
3811
  * { result: 'insufficient', unmet_requirements } — target found requirements unmet
3767
3812
  * { result: 'disclosure_requested', connection_request_id, requested_items } — Round 2 request (unblocks sender)
3768
- * { result: 'timeout' } — no response within connectionTimeoutMs
3813
+ * { result: 'timeout', stage } — no response within timeout; stage identifies which phase timed out
3769
3814
  * { result: 'error', reason } — directory-level error (not_registered, target_not_found, etc.)
3815
+ *
3816
+ * AC-008 (DX-001): per-stage timeouts:
3817
+ * dialTimeoutMs — stage 'dial': timeout for opening the persistent signaling stream (default: connectionTimeoutMs)
3818
+ * sendTimeoutMs — stage 'send': timeout for sending the frame (default: connectionTimeoutMs)
3819
+ * waitTimeoutMs — stage 'wait': timeout for target response (default: connectionTimeoutMs)
3770
3820
  */
3771
3821
  async cello_request_connection(opts) {
3772
3822
  const targetPubkeyHex = opts.target_pubkey;
@@ -3786,12 +3836,22 @@ class CelloClientImpl {
3786
3836
  resolveOutcome = resolve;
3787
3837
  });
3788
3838
  this.#pendingConnectionRequestResolvers.set(targetPubkeyHex, resolveOutcome);
3789
- // Ensure the persistent signaling stream is open
3839
+ // AC-008 (DX-001): per-stage timeouts. Fall back to #connectionTimeoutMs if not provided.
3840
+ const dialTimeoutMs = opts.dialTimeoutMs ?? this.#connectionTimeoutMs;
3841
+ const sendTimeoutMs = opts.sendTimeoutMs ?? this.#connectionTimeoutMs;
3842
+ const waitTimeoutMs = opts.waitTimeoutMs ?? this.#connectionTimeoutMs;
3843
+ // Stage 1 — dial: Ensure the persistent signaling stream is open within dialTimeoutMs.
3790
3844
  if (!this.#persistentSignalingStream) {
3791
- const opened = await this.#openPersistentSignalingStream();
3792
- if (!opened) {
3845
+ let dialTimedOut = false;
3846
+ let opened = false;
3847
+ await Promise.race([
3848
+ this.#openPersistentSignalingStream().then((result) => { opened = result; }),
3849
+ new Promise((resolve) => setTimeout(() => { dialTimedOut = true; resolve(); }, dialTimeoutMs)),
3850
+ ]);
3851
+ if (dialTimedOut || !opened) {
3793
3852
  this.#pendingConnectionRequestResolvers.delete(targetPubkeyHex);
3794
- return { result: "error", reason: "directory_unreachable" };
3853
+ this.#logger.warn("client.connection.request.stage.timeout", { stage: "dial", timeoutMs: dialTimeoutMs, targetPubkeyOrAgentId: targetPubkeyHex });
3854
+ return { result: "timeout", stage: "dial" };
3795
3855
  }
3796
3856
  }
3797
3857
  // Mint a correlationId for this outbound connection request flow.
@@ -3804,20 +3864,39 @@ class CelloClientImpl {
3804
3864
  target_pubkey: targetPubkeyHex,
3805
3865
  package_cbor: opts.package_cbor,
3806
3866
  });
3807
- try {
3808
- this.#persistentSignalingStream.send(lp.encode.single(frameBytes));
3867
+ // Stage 2 — send: Deliver the frame within sendTimeoutMs.
3868
+ // The .send() call is synchronous but may throw if the stream has disconnected.
3869
+ // Wrap in a race so an unresponsive stream doesn't block indefinitely.
3870
+ let sendTimedOut = false;
3871
+ let sendError = false;
3872
+ await Promise.race([
3873
+ new Promise((resolve) => {
3874
+ try {
3875
+ this.#persistentSignalingStream.send(lp.encode.single(frameBytes));
3876
+ }
3877
+ catch {
3878
+ sendError = true;
3879
+ }
3880
+ resolve();
3881
+ }),
3882
+ new Promise((resolve) => setTimeout(() => { sendTimedOut = true; resolve(); }, sendTimeoutMs)),
3883
+ ]);
3884
+ if (sendTimedOut) {
3885
+ this.#pendingConnectionRequestResolvers.delete(targetPubkeyHex);
3886
+ this.#logger.warn("client.connection.request.stage.timeout", { stage: "send", timeoutMs: sendTimeoutMs, targetPubkeyOrAgentId: targetPubkeyHex });
3887
+ return { result: "timeout", stage: "send" };
3809
3888
  }
3810
- catch {
3889
+ if (sendError) {
3811
3890
  this.#pendingConnectionRequestResolvers.delete(targetPubkeyHex);
3812
3891
  return { result: "error", reason: "directory_unreachable" };
3813
3892
  }
3814
- // Race: outcome vs connectionTimeoutMs
3893
+ // Stage 3 — wait: Race outcome vs waitTimeoutMs (was: connectionTimeoutMs).
3815
3894
  // DB-001: timeout cleans this slot without affecting concurrent requests to other targets.
3816
3895
  let frame = null;
3817
3896
  let timedOut = false;
3818
3897
  await Promise.race([
3819
3898
  outcomePromise.then((f) => { frame = f; }),
3820
- new Promise((resolve) => setTimeout(() => { timedOut = true; resolve(); }, this.#connectionTimeoutMs)),
3899
+ new Promise((resolve) => setTimeout(() => { timedOut = true; resolve(); }, waitTimeoutMs)),
3821
3900
  ]);
3822
3901
  // Clean up this target's resolver slot on timeout
3823
3902
  // (on successful resolution, the signaling reader already deleted it)
@@ -3825,7 +3904,8 @@ class CelloClientImpl {
3825
3904
  this.#pendingConnectionRequestResolvers.delete(targetPubkeyHex);
3826
3905
  }
3827
3906
  if (timedOut || !frame) {
3828
- return { result: "timeout" };
3907
+ this.#logger.warn("client.connection.request.stage.timeout", { stage: "wait", timeoutMs: waitTimeoutMs, targetPubkeyOrAgentId: targetPubkeyHex });
3908
+ return { result: "timeout", stage: "wait" };
3829
3909
  }
3830
3910
  const type = frame["type"];
3831
3911
  if (type === "connection_established") {