Skip to content

feat(node-message-broker): implement Hub-link client with SSE wakeup - #3

Merged
tada5hi merged 3 commits into
masterfrom
feat/hub-client
Jun 25, 2026
Merged

feat(node-message-broker): implement Hub-link client with SSE wakeup#3
tada5hi merged 3 commits into
masterfrom
feat/hub-client

Conversation

@tada5hi

@tada5hitada5hi commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

What

Replaces the throwing HubClient stub (plan 013 Track B, phase 4) with a real Hub-link adapter.

  • HubClientsend/pull/ack relay to the Hub durable mailbox via the published @privateaim/messenger-http-kit client, authenticated as the node client through the Authup client-credentials hook.
  • SseWakeupSource — consumes the Hub's payload-free messagePending wakeup over GET /messages/stream. EventSource can't carry the node's Authorization header, so the stream is read over fetch behind an IWakeupSource port, with a pure parseSseStream generator, an abort-aware auto-reconnect loop, and ping-heartbeat filtering.
  • ComponentsModule — builds the messenger Client + auth hook and the SSE source (reusing one tokenCreator), skips opening the stream under NODE_ENV=test.

Port correction

IHubClient is aligned to the real messenger contract discovered from messenger-http-kit/messenger-kit:

  • send resolves with the persisted ids (string[]), not Message[].
  • pull takes a MessagePullQuery (limit/wait) — the speculative after cursor is gone (the Hub mailbox is delete-on-ack, no cursor).

Tests

parseSseStream (chunk-boundary splits, multi-line data, comment skipping), SseWakeupSource dispatch (messagePending dispatched, heartbeats ignored, clean stop), and HubClient delegation via colocated fakes. Build (JS + types), lint, and 10/10 tests green.

Not in this slice

The onWakeup → pull → decrypt → deliver loop (gated on the crypto adapter) and the container-facing message endpoints.

Summary by CodeRabbit

  • New Features

    • Message broker now supports real Hub connectivity with authenticated requests and live wakeup notifications.
    • Added support for Server-Sent Events so message availability updates can arrive in real time.
  • Bug Fixes

    • Replaced placeholder Hub behavior with working send, pull, ack, start, and stop actions.
    • Improved handling of connection retries and wakeup event delivery.
  • Tests

    • Added coverage for message broker integration and SSE event parsing.

Replace the throwing HubClient stub with a real adapter over the
published @privateaim/messenger-http-kit client. send/pull/ack relay to
the Hub durable mailbox, authenticated as the node client via the Authup
client-credentials hook.
The Hub's payload-free `messagePending` wakeup is consumed through a new
SseWakeupSource over GET /messages/stream. EventSource can't carry the
node's Authorization header, so the stream is read over fetch behind an
IWakeupSource port, with a pure SSE parser, an abort-aware auto-reconnect
loop, and ping-heartbeat filtering.
The IHubClient port is corrected to the real messenger contract: send
resolves with the persisted ids (string[]), and pull takes a
MessagePullQuery (limit/wait) — the speculative `after` cursor and
Message[] return are gone.
The onWakeup -> pull -> decrypt -> deliver loop and the container-facing
message endpoints remain for follow-up slices (the loop gates on the
crypto adapter).
CopilotAI review requested due to automatic review settings June 24, 2026 10:56

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitaiBot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@tada5hi, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 21 minutes and 2 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 934d82a2-f046-4f14-84e9-b479dfbf76cc

📥 Commits

Reviewing files that changed from the base of the PR and between 2faa9e9 and 699562f.

📒 Files selected for processing (4)
  • apps/node-message-broker/package.json
  • apps/node-message-broker/src/adapters/hub/sse-wakeup-source.ts
  • apps/node-message-broker/src/app/modules/components/module.ts
  • apps/node-message-broker/test/unit/adapters/hub/sse-wakeup-source.spec.ts
📝 Walkthrough

Walkthrough

Replaces the Phase-4 stubbed HubClient with a working hub adapter. New IMessengerClient, IWakeupSource, and updated IHubClient interfaces define the contracts. A new SseWakeupSource implements SSE stream parsing and auto-reconnecting wakeup. ComponentsModule wires authenticated HTTP and SSE clients. Unit tests and test doubles cover all new behavior.

Changes

Hub adapter: REST + SSE wakeup

Layer / File(s)Summary
Core hub type contracts
apps/node-message-broker/src/core/hub/types.ts, apps/node-message-broker/package.json
Adds IMessengerMessageApi, IMessengerClient, and IWakeupSource interfaces; updates IHubClient so send returns string[], pull accepts MessagePullQuery, and stop() is added. Adds @privateaim/messenger-http-kit dependency.
SseWakeupSource implementation
apps/node-message-broker/src/adapters/hub/sse-wakeup-source.ts, apps/node-message-broker/src/adapters/hub/index.ts
Adds parseSseStream/parseSseBlock SSE stream parser, isMessagePendingEvent type guard, readableToAsyncIterable adapter, and the full SseWakeupSource class with subscriber registry, start/stop lifecycle, reconnect loop with abort-aware backoff, per-connection authenticated fetch, and safe dispatch(). Re-exported from the adapter index.
HubClient adapter implementation
apps/node-message-broker/src/adapters/hub/client.ts
Replaces the NOT_IMPLEMENTED stub with a HubClientContext-injected class that delegates send/pull/ack to IMessengerClient.message.*, wires onWakeup to the wakeup source's subscribe forwarding event.recipient, and delegates start/stop to the wakeup source.
ComponentsModule wiring
apps/node-message-broker/src/app/modules/components/module.ts
Reworks setup() to construct an authup-backed HTTP Client, instantiate SseWakeupSource with a dynamic Bearer token callback, build and register HubClient in DI, and skip start() in TEST environments.
Test doubles and unit tests
apps/node-message-broker/test/unit/adapters/hub/...
Adds FakeMessengerClient and FakeWakeupSource test doubles; unit tests for HubClient covering send, pull, ack, onWakeup unsubscribe, and lifecycle delegation; unit tests for parseSseStream and SseWakeupSource covering event dispatch, heartbeat filtering, chunk boundaries, and stop-before-connect.

Sequence Diagram(s)

sequenceDiagram
participant ComponentsModule
participant SseWakeupSource
participant HubClient
participant MessengerHTTPClient
participant HubMessengerAPI
ComponentsModule->>MessengerHTTPClient: new Client(hubURL) + auth hook
ComponentsModule->>SseWakeupSource: new SseWakeupSource({ authorization, url })
ComponentsModule->>HubClient: new HubClient({ client, wakeup })
ComponentsModule->>HubClient: start()
HubClient->>SseWakeupSource: wakeup.start()
SseWakeupSource->>HubMessengerAPI: GET /messages/stream (Bearer token)
HubMessengerAPI-->>SseWakeupSource: SSE stream
SseWakeupSource-->>HubClient: onWakeup listener(recipient)
rect rgba(100, 149, 237, 0.5)
Note over HubClient, HubMessengerAPI: Message send/pull/ack
HubClient->>MessengerHTTPClient: client.message.send(request)
MessengerHTTPClient->>HubMessengerAPI: POST /messages
HubMessengerAPI-->>MessengerHTTPClient: string[]
MessengerHTTPClient-->>HubClient: string[]
end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐇 Hoppity-hop through the event stream,
No more stubs throwing NOT_IMPLEMENTED screams!
SSE bytes parsed with a careful paw,
Auth tokens fetched without a flaw.
The wakeup source reconnects and loops,
A real hub client now leaps through its hoops! 🌟

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/hub-client

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.

@tada5hi

Copy link
Copy Markdown
ContributorAuthor

@coderabbitai review

@coderabbitai

coderabbitaiBot commented Jun 25, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Stability and robustness fixes for the SSE wakeup source and its wiring:
- add an idle watchdog (resets on every event incl. heartbeats) so a
silently half-open stream is dropped and reconnected instead of hanging
- split lifecycle vs per-connection AbortControllers so stop() can always
cancel the reconnect backoff, even after an error-triggered abort
- normalise CR/CRLF line endings in the SSE parser, handling a CRLF split
across chunk boundaries
- tighten messagePending validation to require recipient type and id
- cache the node-client grant for the SSE Authorization header so reconnects
reuse the token instead of minting a fresh one each time
- normalise HUB_URL trailing slash before building the stream URL
- clear the auth hook's refresh timer on teardown to avoid a dangling timer
- cover reconnect, idle drop, clean stop, malformed payloads and CRLF in tests
@tada5hi
tada5hi merged commit a70591d into masterJun 25, 2026
7 checks passed
Sign up for freeto 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.

2 participants

@tada5hi