Skip to content

Modernize tooling and improve browser/Electron RPC integration - #57

Merged
oe merged 7 commits into
mainfrom
codex/modernize-toolchain-and-rpc
Oct 3, 2026
Merged

oe merged 7 commits into
mainfrom
codex/modernize-toolchain-and-rpc

Conversation

@oe

@oe oe commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

RPC calls could retain timers and unresolved promises after failure/destruction, confuse business progress with heartbeat data, or arrive before a peer's handlers were ready. Calls now clean up deterministically and support optional local cancellation/deadlines; explicit readiness probes prevent startup races without retrying business operations.

Browser/Electron integration:

  • createRpcClient<Api> checks method names/parameters and infers asynchronous results without a proxy layer or new wire protocol.
  • READY_METHOD / waitForPeer provide an explicit ready endpoint with bounded, cancellable probing.
  • Window hubs support opt-in incoming origins, fixed default outgoing origins, and request-origin-pinned replies/progress.
  • Electron sender/frame validation accepts only synchronous true; accidentally async validators fail closed without unhandled rejections.
  • The Electron demo uses context isolation, a sandboxed bundled preload and a fixed contextBridge API.
  • READMEs and npm metadata now explain concrete use cases, runnable setup, transport selection, controls, security boundaries and alternatives.

Tooling pins pnpm 12.8.1, TypeScript 7.0.2, Vite 8.3.2 and Vitest 5.0.3. TypeScript emits declarations directly; Oxlint replaces the obsolete lint stack. Published library JavaScript preserves ES2018 syntax, checked after packing; developers' modern Node requirement does not become a consumer runtime requirement. Node import/require share classes and shared hubs; browser bundlers retain ESM. Legacy filenames, extensionless distribution imports and the UMD global remain available.

Correctness/performance:

  • Deterministic timer/listener/promise cleanup; immediate storage cleanup and repeated progress; correct Worker listener lifetimes; immutable caller options and handler arrays; safe exception/uncloneable-result handling; peer/message validation; recreated destroyed shared hubs.
  • One pending-request record plus peer counts replaces five separate per-request maps.
  • Response/progress dispatch reuses a resolved Promise; accepted Electron messages avoid extra async wrappers. Single handlers avoid multi-handler race machinery, and ordinary calls avoid unnecessary argument/configuration copies and repeated validation.
  • Thenables, multi-handler behavior and throwing subclass hooks retain their tested semantics.
  • 1,000 completed calls leave no heartbeat timers or pending callbacks. A separate clone-transport timer-count probe observed 1,000 outstanding timers in published 2.1.0 versus zero in this build before destruction.

Validation:

  • 266 local tests passed: 81 Node, 56 each in Chromium/Firefox/WebKit, 17 mocked Electron IPC.
  • Lint, strict types, both library/demo builds and packed consumers passed.
  • Packed checks cover ES2018 syntax, CJS/ESM/helper exports, class/singleton identity, NodeNext types with negative calls, extensionless imports, UMD globals and tree shaking.
  • Published 2.1.0 ↔ new production builds passed real Worker calls/progress/errors in both directions; consumer types passed TS 4.1 and 4.4.
  • Real Electron 31.7.7 and 44.5.1 passed locally with renderer sandbox/context isolation enabled.
  • Expanded CI checks Node 22/24 with three browser engines, Electron 31/44 on Linux, and Electron 44 on Windows/macOS. All six current-commit jobs passed.

Performance evidence:

  • In a rotated Chromium 153 Worker benchmark, sequential numerical calls improved 65.35→60.22 µs versus the prior PR, but published 2.1.0 measured 57.52 µs.
  • Isolated continuous 32-lane calls measured 36.84→25.90 µs/call versus 2.1.0; continuous sequential calls measured 64.49→67.69 µs. Concurrent figures are amortized time, not individual latency.
  • Scheduling varies. This reduces known allocation/resource-retention costs and improves some workloads, not every workload. Full production UMD gzip grows approximately 3.8→5.8 KB.
  • A reproducible benchmark and raw samples are included.

Release boundaries:

  • Major changesets record the TypeScript 4.1 declaration minimum (not TS 7), pending-call rejection with UNKNOWN on destroy(), and reserved local signal/requestTimeout fields. Packages remain unbumped/unpublished.
  • Existing emit signatures and the legacy wire protocol remain; heartbeatTimeout: 0 retains its 500ms fallback.
  • Filters are opt-in, deadlines default to unlimited, readiness requires an explicit endpoint. Cancellation/destruction only end local waiting; remote work continues.
  • Runtime transport APIs must exist; readiness/cancellation additionally require AbortController/AbortSignal. Current Playwright engines are covered; older browsers, iOS Safari, embedded WebViews and other Electron versions still need application verification.

Upgrade review and benchmark methodology.

@oe oe changed the title Modernize pnpm, TypeScript and Vite; fix RPC lifecycle leaks Modernize toolchain, fix RPC lifecycle and add cancellable request deadlines Oct 3, 2026
@oe
oe marked this pull request as ready for review October 3, 2026 14:25
@oe oe changed the title Modernize toolchain, fix RPC lifecycle and add cancellable request deadlines Modernize tooling and improve browser/Electron RPC integration Oct 3, 2026
@oe
oe merged commit 11877c4 into main Oct 3, 2026
6 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