Skip to content

feat(cluster-protocol): publish TypeScript cluster client - #843

Merged
tomdps merged 2 commits into
mainfrom
feat/748-typescript-cluster-client
Jul 29, 2026
Merged

feat(cluster-protocol): publish TypeScript cluster client#843
tomdps merged 2 commits into
mainfrom
feat/748-typescript-cluster-client

Conversation

@tomdps

@tomdps tomdps commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Closes #748

Outcome

Publishes @the-open-engine/zeroshot/cluster as a Node 18+ CJS/ESM/TypeScript WebSocket client for the full v1 cluster protocol.

Ownership decisions

  • The connection owns collision-free request IDs, pending entries, exact failed-send cleanup, bounded frame decoding, response routing, and OPEN/CLOSING/CLOSED teardown.
  • Every subscription uses the shared 1024-entry bounded multi-waiter queue; overflow unregisters locally, cancels remotely best-effort, clears retained frames, and returns the protocol slow-consumer close.
  • Durable watch owns one shared reconnect attempt, reconstructs state via coherent get then watch(fromCursor), and suppresses the last ordered physical (runId,cursor) redelivery with constant memory across reconnects.
  • Abort/iterator return detach their exact listeners and cancel exactly once; logs and attach expose terminal closure without a recoverable cursor.
  • Wire types, method/result maps, validators, constants, and the embedded schema are generated deterministically from checked-in Rust/OpenRPC artifacts. There are no hand-maintained DTOs.
  • The package exports preserve the root/deep-import surface while adding the built cluster subpath, optional installed ws runtime, and injectable browser-compatible factory.

The issue's two ownership-design comments were followed directly. The claimed checked-in docs/v2/748-typescript-client-design.md was absent from fresh origin/main, so no replacement design document was fabricated.

Regression coverage

Deterministic tests cover every prior #799-#802 defect class: shared-ID collisions, exact pending cleanup after failed sends, 1024-entry overflow for all stream types, failed/competing reconnect ownership, close at every reconnect boundary, multi-waiter FIFO, close cleanup after cancel failure, post-handshake abort, malformed peer frames and bounded diagnostics, generated response validation, and packed CJS/ESM/TypeScript/default-ws consumers.

External review added and closed two security P1s before merge: durable-watch dedup state is scalar/constant-memory over thousands of unique events, and inbound binary/text byte limits are enforced before decode/encoding-copy allocation. Both review threads include fix and independent probe evidence.

Independent non-authoring verifiers required four rounds. Their final runs reproduced the historical races plus malformed-frame, error-envelope, cancellation, installed-runtime, 5,000-event dedup, UTF-8 boundary, and decoder-allocation probes. No P0/P1/security finding remains.

Verification

  • npm run protocol:check
  • npm run typecheck
  • npm run lint (0 errors; existing warnings remain)
  • npm run test:cluster-client — 38/38
  • npm run test:cluster-package — 4/4
  • npm test — 1953 passing, 18 pending
  • npm pack --dry-run
  • npm run rust:check
  • npm run test:unit — 1953 passing, 18 pending
  • npm run check:agent-cli-provider:ci — 147/147
  • npm run dupcheck
  • opcore check --changed

Non-goals preserved

No Rust dispatcher/server/client behavior, in-process TypeScript transport, hosted authentication, provisioning, or native-daemon behavior changed.

Discovered protocol work

WatchResult uniquely lacks Rust #[serde(deny_unknown_fields)], so its generated schema permits unknown properties while LogsResult and AgentAttachResult are closed. This PR intentionally follows generated authority rather than hand-tightening the TypeScript validator.

@tomdps
tomdps enabled auto-merge July 29, 2026 18:34
Comment thread src/cluster/subscriptions.ts Outdated
Comment thread src/cluster/connection.ts
@greptile-apps

greptile-apps Bot commented Jul 29, 2026

Copy link
Copy Markdown

Greptile Summary

Adds a published Node 18+ TypeScript client for the v1 cluster WebSocket protocol.

  • Provides typed unary calls, bounded subscriptions, cancellation, teardown, and durable watch reconnection.
  • Generates protocol types and validators from checked-in Rust/OpenRPC artifacts.
  • Adds CJS, ESM, declaration, package-export, optional WebSocket runtime, and packaging support.
  • Adds regression coverage for connection races, queue limits, malformed frames, reconnection, and package consumers.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/cluster/connection.ts Implements request ownership, response routing, bounded inbound processing, subscription registration, cancellation, and connection teardown.
src/cluster/subscriptions.ts Implements bounded subscription streams and constant-memory durable-watch reconnection and boundary deduplication.
src/cluster/frames.ts Enforces frame byte limits before binary decoding or string encoding-copy allocation.
src/cluster/client.ts Exposes the typed client API, protocol initialization, subscription construction, and injectable/default WebSocket connection setup.
scripts/generate-cluster-types.js Deterministically emits TypeScript protocol types, constants, method maps, and the embedded schema.
package.json Adds cluster build, validation, packaging, exports, and optional WebSocket runtime configuration.

Sequence Diagram

sequenceDiagram
  participant App
  participant Client as ClusterClient
  participant Conn as Connection
  participant Peer as Cluster Server
  App->>Client: connect(url)
  Client->>Conn: initialize protocol
  Conn->>Peer: JSON-RPC initialize
  Peer-->>Conn: validated response
  App->>Client: unary call or subscription
  Client->>Conn: dispatch request
  Conn->>Peer: bounded WebSocket frame
  Peer-->>Conn: response or notification
  Conn-->>Client: validated result / bounded queue
  Client-->>App: result or async stream item
Loading

Reviews (3): Last reviewed commit: "fix(cluster-protocol): bound peer-contro..." | Re-trigger Greptile

@tomdps
tomdps added this pull request to the merge queue Jul 29, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Jul 29, 2026
@tomdps
tomdps enabled auto-merge July 29, 2026 19:15
@tomdps
tomdps force-pushed the feat/748-typescript-cluster-client branch from e4bf331 to 417df2f Compare July 29, 2026 19:19
@tomdps
tomdps added this pull request to the merge queue Jul 29, 2026
Merged via the queue into main with commit b95fd86 Jul 29, 2026
10 checks passed
@tomdps
tomdps deleted the feat/748-typescript-cluster-client branch July 29, 2026 19:37
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 6.12.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(cluster-protocol): publish the TypeScript cluster client with full v1 parity

1 participant