Skip to content
Logo

Changelog

2.0.0

Breaking: Explicit Params

The request() and subscribe() APIs now take params as a single explicit argument instead of rest/spread parameters. This aligns the TypeScript API with the JSON-RPC 2.0 wire format and adds unambiguous support for both positional (array) and named (object) params.

// Before (1.x)
await transport.request('method', param1, param2)
await transport.subscribe('method', param1, (data) => { ... })
 
// After (2.0)
await transport.request('method', [param1, param2])
await transport.subscribe('method', [param1], (data) => { ... })
 
// Named params (new)
await transport.request('daemon.passthrough', { method: 'foo', params: [] })

Migration

  • request(method, ...params)request(method, params?) — wrap positional args in an array. No-arg calls like request('server.ping') are unchanged.
  • subscribe(method, ...params, callback)subscribe(method, params, callback) — params is always the second argument, callback is always the third.
  • SchemaEntry.params — now accepts unknown[] | Record<string, unknown> to support named params.

Other changes

  • Removed the auto-unwrap heuristic in WebSocket and TCP transports that guessed whether a single object argument was named params. The params argument now maps directly to the JSON-RPC params field — no ambiguity.
  • daemon.passthrough — Uses plain object params naturally in ElectrumCashSchema.

1.0.3

Subscription Dispatch Chain

Subscription notification handlers are now serialized via a dispatchChain on each subscription entry, preventing concurrent handler execution and ensuring notifications are processed in order.

  • WebSocket & TCP transports — Notification handlers are dispatched through a promise chain, so each notification waits for the previous one's handlers to complete before firing.
  • Error isolation — A failing handler no longer breaks the dispatch chain for the subscription. Each handler is individually caught.
  • Graceful cleanupunsubscribe() and close() now await in-flight dispatch chains, ensuring all pending handlers complete before teardown.

1.0.2

Batch Auto-Disable

When a server can't handle batch requests (e.g. the batch is too large or the server doesn't support batching), the BatchScheduler now automatically falls back to sending requests individually and temporarily disables batching. After a cooldown period (default: 5 seconds), batching is re-enabled.

  • BatchScheduler — Added sendSingle, isBatchRejection, and disabledCooldown options. Added disabled property.
  • WebSocket & TCP transports — Now provide a sendSingle fallback to BatchScheduler, enabling transparent auto-disable on batch rejection.
  • parse() — Added disabledCooldown query parameter support (e.g. wss://example.com?batchSize=10&disabledCooldown=10000).
  • BatchConfig — Added disabledCooldown option.
  • bump.mjs — Skip package directories without package.json.

Detection

The following errors trigger auto-disable by default:

  • Batch timeout — server couldn't process the batch in time
  • Parse error (JSON-RPC code -32700)
  • Invalid request (JSON-RPC code -32600)

Custom detection can be provided via the isBatchRejection option.

1.0.0

Initial release.

Core

  • Transport interface with request(), subscribe(), connect(), close()
  • Spread-style parameters — request('method', param1, param2) instead of array wrapping
  • Schema-based generics for type-safe method names, parameters, and return types
  • BatchScheduler for automatic request batching with configurable batch size and wait time
  • withRetry() utility with exponential backoff
  • parse() for creating transports from URL strings (supports nested meta-transports and query-string options)
  • createParse() for building custom parse functions with overridden package maps
  • createParseSync() for building synchronous parse functions using pre-imported factory functions
  • ElectrumCashSchema type definitions (protocol v1.5 and v1.6)
  • EthereumSchema type definitions (EIP-1474 standard methods)

Transports

  • WebSocket — Full-duplex communication with subscriptions, keep-alive, reconnection, connection pooling
  • TCP — Newline-delimited JSON-RPC with TLS support, keep-alive, reconnection (Node.js)
  • HTTP — Stateless JSON-RPC over HTTP POST with custom headers, fetch options, and raw mode

All transports support lazy connections — no resources are allocated until the first request(), subscribe(), or connect() call.

Meta-Transports

  • Fallback — Automatic failover across multiple transports with optional health-based ranking
    • Default shouldThrow stops fallback on deterministic JSON-RPC errors (parse error, invalid request, invalid params)
    • eagerConnect prioritizes the fastest-connecting transport
    • onScores listener and scores property for monitoring transport health
    • onResponse hook for observing requests across all transports
  • Cluster — m-of-n quorum consensus with deep-equality response matching
    • onResponse hook for observing individual transport responses
  • Single-element passthrough — fallback([t]) and cluster([t]) return the input transport directly

Electrum Cash Variants

Protocol-specific subpath imports (@rpckit/*/electrum-cash) with pre-configured defaults:

  • server.version handshake with configurable clientName and protocolVersion
  • server.ping keep-alive
  • subscribe/unsubscribe method convention
  • Server-Version HTTP header
  • Fallback variant with server.ping health probing and protocol-aware shouldThrow (retries transient server errors like OOM, warmup, syncing)

Ethereum Variants

Protocol-specific subpath imports (@rpckit/*/ethereum) for Ethereum JSON-RPC:

  • eth_subscription notification routing by subscription ID
  • eth_unsubscribe called automatically on cleanup
  • Subscription ID suppressed from callbacks (handled internally)
  • Custom parse() function for Ethereum transports

Features

  • Automatic request batching with configurable batch size and wait time
  • Subscription support with automatic resubscription on reconnect
  • Handshake re-execution on reconnect (WebSocket and TCP)
  • Connection pooling with ref counting for WebSocket and TCP transports
  • Retry with exponential backoff on all transports
  • Raw mode for HTTP transport (return full JSON-RPC envelopes instead of throwing on error)
  • Request/response hooks on HTTP transport
  • Socket access via getSocket() and getSocketAsync() on WebSocket and TCP transports
  • Subscription sharing — multiple listeners on the same method+params share one server subscription
  • Smart unsubscribe — server unsubscribe only sent when last listener removes
  • Fresh data for new subscribers — new listeners receive most recent notification, not stale initial result
  • Race condition prevention — concurrent subscription calls safely coalesce
  • notificationFilter callback for protocol-specific notification routing
  • transformInitialResult option to normalize or suppress initial subscription results
  • HTTP transport includes response body in error messages for better debugging