Skip to content

clean up echo flow once more#9

Merged
AustinKelsay merged 2 commits intomasterfrom
staging
Oct 22, 2025
Merged

clean up echo flow once more#9
AustinKelsay merged 2 commits intomasterfrom
staging

Conversation

@AustinKelsay
Copy link
Copy Markdown
Member

@AustinKelsay AustinKelsay commented Oct 22, 2025

Summary by CodeRabbit

  • Chores

    • Pinned an internal dependency version for stability.
  • Tests

    • Added tests validating key-share echo confirmation payloads (legacy token and hex-challenge cases, plus invalid inputs).
  • Refactor

    • Reworked key-share echo listening to use a compatible echo waiter with improved relay resolution, timeout handling, logging, and robust cleanup/error handling.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Oct 22, 2025

Walkthrough

Introduces a local compatibility module awaitShareEchoCompat, replaces the prior awaitShareEcho import in the keyset hook to use the new implementation, pins the @frostr/igloo-core dependency to 0.2.4, and adds tests for the echo-confirmation predicate.

Changes

Cohort / File(s) Summary
Dependency constraint tightening
package.json
Removed caret from @frostr/igloo-core version, changing "^0.2.4" to "0.2.4"
Echo confirmation compatibility layer
src/keyset/awaitShareEchoCompat.ts
New module exporting AwaitShareEchoOptions type, isEchoConfirmationPayload() predicate, and awaitShareEchoCompat() function with relay resolution, Bifrost node setup, message filtering for '/echo/req', timeout handling, logging, and robust cleanup/error handling
Integration change
src/components/keyset/useShareEchoListener.ts
Replaced import/call of awaitShareEcho (from @frostr/igloo-core) with awaitShareEchoCompat (local module) and updated call site accordingly
Test coverage
tests/awaitShareEchoCompat.test.ts
New tests for isEchoConfirmationPayload() validating legacy token acceptance ('echo', whitespace/case variants), even-length hex challenges, and rejection of invalid/odd-length/empty inputs

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant awaitShareEchoCompat as awaitShareEchoCompat()
    participant resolveEchoRelays as resolveEchoRelays()
    participant Bifrost as Bifrost Node
    participant Network as Network

    Caller->>awaitShareEchoCompat: call(groupCred, shareCred, options)
    awaitShareEchoCompat->>resolveEchoRelays: resolve relays (explicit → decode → defaults)
    resolveEchoRelays-->>awaitShareEchoCompat: relays
    awaitShareEchoCompat->>Bifrost: create node with merged eventConfig & relays
    Note right of Bifrost #D3E5FF: Listener registered for '/echo/req'
    par Listen & Timeout
        Bifrost->>awaitShareEchoCompat: message(payload) on '/echo/req'
        awaitShareEchoCompat->>awaitShareEchoCompat: isEchoConfirmationPayload(payload)?
        alt valid
            awaitShareEchoCompat->>Caller: resolve(true)
            awaitShareEchoCompat->>Bifrost: cleanup
        else invalid
            Note right of awaitShareEchoCompat #FFF4D6: continue waiting
        end
    and
        awaitShareEchoCompat->>awaitShareEchoCompat: timeout / error / close
        awaitShareEchoCompat->>Caller: reject(error)
        awaitShareEchoCompat->>Bifrost: cleanup
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped in code, a patch in tow,
Awaiting echoes soft and low,
Relays found, timeouts kept neat,
Validators check each hex and beat,
Clean-up done — a rabbit's quiet glow.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title “clean up echo flow once more” is vague because it does not clearly convey the primary changes such as introducing the new awaitShareEchoCompat function, updating the listener import to use it, tightening the dependency version in package.json, and adding corresponding tests for echo confirmation payloads. Please update the title to succinctly reflect the main changes, for example “Introduce awaitShareEchoCompat and update echo listener imports.”
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch staging

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
tests/awaitShareEchoCompat.test.ts (1)

1-25: LGTM! Consider adding tests for the main function.

The test coverage for isEchoConfirmationPayload is comprehensive, covering legacy tokens, valid hex challenges, and various invalid inputs. However, the main awaitShareEchoCompat function is not tested. Consider adding tests to verify:

  • Successful echo confirmation receipt
  • Timeout behavior
  • Error handling and cleanup
  • Connection closed scenarios

As per coding guidelines: Test files should exercise both happy paths and failure modes.

src/keyset/awaitShareEchoCompat.ts (3)

19-33: Consider improving type safety for decoded group.

The function uses any for the decoded group (line 24) and accesses properties without type safety. If @frostr/igloo-core exports a type for the decoded group structure, use it instead of any. Otherwise, define a local interface for the expected shape.

+interface DecodedGroup {
+  relays?: string[];
+  relayUrls?: string[];
+  relay_urls?: string[];
+}
+
 function resolveEchoRelays(groupCredential: string, explicitRelays?: string[]): string[] {
   if (Array.isArray(explicitRelays) && explicitRelays.length > 0) {
     return explicitRelays;
   }
   try {
-    const decoded: any = decodeGroup(groupCredential);
+    const decoded = decodeGroup(groupCredential) as DecodedGroup;
     const relays: unknown = decoded?.relays ?? decoded?.relayUrls ?? decoded?.relay_urls;

52-77: Consider improving type safety for the node.

The node variable is typed as any | null (line 60), which bypasses TypeScript's type checking. If @frostr/igloo-core exports a type for the Bifrost node, use it. Otherwise, the cleanup and resource management logic is solid with proper timeout clearing and node closing.

As per coding guidelines: Use TypeScript with proper typing.


1-10: Consider adding module-level documentation.

The echo confirmation flow is non-obvious. Consider adding a brief JSDoc comment at the module level explaining:

  • What echo confirmation is in the context of shared keys
  • Why this compatibility layer exists
  • The typical flow (connect → listen for /echo/req → validate → resolve)

As per coding guidelines: Document non-obvious flows with concise comments, especially around key lifecycle management.

Example:

+/**
+ * Compatibility module for awaiting echo confirmations in shared key workflows.
+ * 
+ * When a share credential is distributed, the recipient sends an echo confirmation
+ * via a '/echo/req' message. This module wraps igloo-core's Bifrost node to listen
+ * for and validate that confirmation, resolving when the echo is received or
+ * rejecting on timeout/error.
+ */
 import {
   createBifrostNode,
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 032f47a and 584cd4d.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • package.json (1 hunks)
  • src/components/keyset/useShareEchoListener.ts (2 hunks)
  • src/keyset/awaitShareEchoCompat.ts (1 hunks)
  • tests/awaitShareEchoCompat.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

All import specifiers must include .js extensions (TypeScript ESM requirement) even though source files are .ts/.tsx

Files:

  • src/keyset/awaitShareEchoCompat.ts
  • src/components/keyset/useShareEchoListener.ts
src/keyset/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/keyset/**/*.ts: Keep key exchange and credential helpers under src/keyset/
Document non-obvious flows with concise comments, especially around key lifecycle management

Files:

  • src/keyset/awaitShareEchoCompat.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use TypeScript with ESM, 2-space indentation, single quotes, and trailing commas
Order imports from shallow-to-deep
Use camelCase for utility function and variable names
Use SCREAMING_SNAKE_CASE for constants

Files:

  • src/keyset/awaitShareEchoCompat.ts
  • src/components/keyset/useShareEchoListener.ts
  • tests/awaitShareEchoCompat.test.ts
src/components/**

📄 CodeRabbit inference engine (CLAUDE.md)

All UI components should live under src/components/

Files:

  • src/components/keyset/useShareEchoListener.ts
src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Name React components using PascalCase

Files:

  • src/components/keyset/useShareEchoListener.ts
**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.ts: Allow colocated test files named feature.test.ts beside implementations
Test files should exercise both happy paths and failure modes

Files:

  • tests/awaitShareEchoCompat.test.ts
🧬 Code graph analysis (2)
src/components/keyset/useShareEchoListener.ts (1)
src/keyset/awaitShareEchoCompat.ts (1)
  • awaitShareEchoCompat (52-160)
tests/awaitShareEchoCompat.test.ts (1)
src/keyset/awaitShareEchoCompat.ts (1)
  • isEchoConfirmationPayload (44-50)
🔇 Additional comments (6)
package.json (1)

31-31: Verify the rationale for pinning the exact version.

Removing the caret (^) prevents automatic patch updates for @frostr/igloo-core. While this provides stability, it also blocks automatic security patches. Ensure this exact pinning is intentional and that you have a process to monitor and update this dependency for security fixes.

src/components/keyset/useShareEchoListener.ts (2)

3-3: LGTM!

The import correctly uses the .js extension as required for TypeScript ESM.

As per coding guidelines: All import specifiers must include .js extensions.


134-138: LGTM!

The migration from awaitShareEcho to awaitShareEchoCompat maintains the same function signature and options structure. The debug logging integration is preserved correctly.

src/keyset/awaitShareEchoCompat.ts (3)

1-15: LGTM!

The imports and type definitions are well-structured. The AwaitShareEchoOptions type provides clear configurability for relays, timeout, and event logging.


44-50: LGTM!

The isEchoConfirmationPayload function correctly validates both legacy "echo" tokens (case-insensitive) and hex challenges. The logic is well-tested in the test file.


146-160: LGTM!

The async connection handling is well-implemented:

  • Properly voids the floating promise with void connectNode(node)
  • Checks settled flag before proceeding
  • Comprehensive error handling with try-catch
  • All paths resolve through safeResolve or safeReject

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/keyset/awaitShareEchoCompat.ts (1)

64-73: Good fix: centralized teardown via cleanupBifrostNode.

Switching to cleanupBifrostNode addresses prior listener-leak risk and simplifies resource cleanup. No further action needed here.

🧹 Nitpick comments (3)
src/keyset/awaitShareEchoCompat.ts (3)

61-61: Make timeout type cross‑env safe.

Prefer ReturnType over NodeJS.Timeout for broader TS compatibility.

Apply this diff:

-  let timeoutId: NodeJS.Timeout | null = null;
+  let timeoutId: ReturnType<typeof setTimeout> | null = null;

112-121: Strengthen message typing; avoid any with a small type guard.

Use unknown + a narrow guard to prevent accidental runtime errors and improve TS help.

Apply this diff:

-      const onMessage = (payload: any) => {
-        if (!payload || payload.tag !== '/echo/req') {
+      const onMessage = (payload: unknown) => {
+        if (!isEchoMessage(payload) || payload.tag !== '/echo/req') {
           return;
         }
         if (!isEchoConfirmationPayload(payload.data)) {
           return;
         }
         prefixLogger('info', 'Echo confirmation received', payload);
         safeResolve(true);
       };

Add this helper near the other validators:

function isEchoMessage(val: unknown): val is { tag: string; data: unknown } {
  return !!val && typeof (val as any).tag === 'string' && 'data' in (val as any);
}

52-56: Add a brief doc comment for key lifecycle (clarity).

A short header improves maintainability per keyset guidelines.

Apply this diff:

+/**
+ * Await an echo confirmation:
+ * - creates a Bifrost node, subscribes to 'message'/'error'/'closed'
+ * - resolves true on a valid '/echo/req' echo payload; rejects on error/timeout/early close
+ * - always cleans up via cleanupBifrostNode
+ */
 export async function awaitShareEchoCompat(

As per coding guidelines.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 584cd4d and 12fa319.

📒 Files selected for processing (1)
  • src/keyset/awaitShareEchoCompat.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

All import specifiers must include .js extensions (TypeScript ESM requirement) even though source files are .ts/.tsx

Files:

  • src/keyset/awaitShareEchoCompat.ts
src/keyset/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/keyset/**/*.ts: Keep key exchange and credential helpers under src/keyset/
Document non-obvious flows with concise comments, especially around key lifecycle management

Files:

  • src/keyset/awaitShareEchoCompat.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use TypeScript with ESM, 2-space indentation, single quotes, and trailing commas
Order imports from shallow-to-deep
Use camelCase for utility function and variable names
Use SCREAMING_SNAKE_CASE for constants

Files:

  • src/keyset/awaitShareEchoCompat.ts
🔇 Additional comments (1)
src/keyset/awaitShareEchoCompat.ts (1)

112-136: Extract the canonical echo request tag into a constant and correct its value.
Replace the hard-coded '/echo/req' with a constant—e.g.

const ECHO_SENDER_REQ_TAG = '/echo/sender/req';

and use ECHO_SENDER_REQ_TAG in the payload check. The 'closed' event name is already correct.

@AustinKelsay AustinKelsay merged commit bf9df6b into master Oct 22, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant