Skip to content

Migrate from Node.js/Express to Cloudflare Workers - #8

Merged
InventivetalentDev merged 1 commit into
masterfrom
claude/vigilant-hopper-kca5oz
Sep 10, 2026
Merged

InventivetalentDev merged 1 commit into
masterfrom
claude/vigilant-hopper-kca5oz

Conversation

@InventivetalentDev

Copy link
Copy Markdown
Member

Summary

This PR migrates the Remote Slide signalling server from a Node.js/Express application to Cloudflare Workers, leveraging Durable Objects for session management and WebSocket support.

Key Changes

  • Replaced Express server with Cloudflare Workers: Removed the legacy index.js (404 lines of Node.js/Express code) and replaced it with a modern TypeScript-based Workers implementation (src/index.ts)

  • Implemented Durable Objects for session management: Created src/session-room.ts (408 lines) to handle per-session state, WebSocket connections, and client lifecycle management using Cloudflare's Durable Objects API

  • Formalized wire protocol: Added src/protocol.ts with shared protocol definitions and PROTOCOL.md documentation for the JSON-based WebSocket communication between website, injected controller, and server

  • Added comprehensive test suite: Created test/session.test.ts (300 lines) and test/helpers.ts with test utilities for validating session creation, WebSocket communication, and client lifecycle

  • Updated build configuration:

    • Added wrangler.jsonc for Cloudflare Workers configuration
    • Added tsconfig.json and vitest.config.ts for TypeScript and testing setup
    • Updated package.json to version 2.0.0 with Workers-specific dependencies
  • Added CI/CD workflows: Created GitHub Actions workflows for automated testing (ci.yml) and deployment (deploy.yml)

  • Updated client-side code: Modified Angular controllers to work with the new WebSocket-based connection model instead of Socket.IO

Notable Implementation Details

  • Session persistence: Uses Durable Objects' built-in storage for session metadata and client state, with configurable TTL (SESSION_TTL_MS)
  • Liveness detection: Implements heartbeat mechanism with configurable timeouts (LIVENESS_CHECK_MS, LIVENESS_TIMEOUT_MS) to detect and clean up stale connections
  • Message validation: Enforces size limits (MAX_MESSAGE_BYTES = 1MB) and validates message structure against the wire protocol
  • CORS support: Maintains cross-origin support with appropriate headers for the web-based controller
  • QR code generation: Added src/qr.ts for SVG-based QR code generation suitable for Workers environment

https://claude.ai/code/session_01GfhNPpQzAKM2dMhYp66gLk

The Express/Socket.IO server (index.js, node-persist, rotating logs)
is replaced by a Worker with one Durable Object per session:

- src/index.ts routes /api/session (create or resume via the
  rs-session-id cookie, SVG QR code), /ws/:session (WebSocket join)
  and everything else to the static assets in static/, with CORS on
  all of it and a www -> apex redirect.
- src/session-room.ts is the SessionRoom Durable Object. It holds the
  host, remotes and observer as hibernatable WebSockets, relays
  control and application events between them, remembers each
  remote's settings for the connection info, replaces an older host
  or observer when a newer one connects, drops sockets that stop
  sending heartbeats (alarm every 15 s while connected) and deletes
  the session an hour after the last activity. Heartbeats are
  answered by the runtime through setWebSocketAutoResponse, so an
  idle session costs nothing.
- The wire format is plain JSON over WebSocket instead of Socket.IO;
  PROTOCOL.md describes it. The socket client lives in the
  RemoteSlide-Controller submodule (rs-socket.js) so the website, the
  bookmarklet and the Chrome extension share it.

Website changes: index.html moves from views/ into static/ as the
SPA fallback, the controllers join the session through
RemoteSlideSocket once they know the session id (the "init start"
round trip is gone), "_forward"/"_get" become plain events, and the
latency display uses the socket's own heartbeat. The bookmarklet
loader no longer juggles window.io; it loads attrchange from this
site (the rawgit CDN it used has been dead since 2019), then
rs-socket.js and the page controller. The inline
chrome.webstore.install call is removed (Chrome dropped inline
installs in 2018), the _gaq calls are guarded (no analytics script
is loaded, so settings.save() threw), and the bookmarklet's jQuery
is bumped to 3.7.1.

Tests run inside workerd via @cloudflare/vitest-pool-workers and
cover the session API, routing, presence, relaying, host replacement,
heartbeats and expiry. CI runs them on every push and PR; the deploy
workflow publishes master with wrangler (needs the
CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID secrets).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GfhNPpQzAKM2dMhYp66gLk
@InventivetalentDev
InventivetalentDev merged commit 99b2751 into master Sep 10, 2026
1 check passed
@InventivetalentDev
InventivetalentDev deleted the claude/vigilant-hopper-kca5oz branch September 10, 2026 07:34
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.

2 participants