[Web runtime] Add SSE subscribe + CORS to HttpTransport#1537
Open
minggangw wants to merge 4 commits into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
Adds opt-in HTTP subscribe support for the Web Runtime via Server-Sent Events (SSE) and introduces configurable CORS handling so browser/HTTP-only clients can access the HTTP transport cross-origin.
Changes:
- Add
HttpSseConnectionand aGET /capability/subscribe/<name>SSE route toHttpTransport(opt-in viasse/sseKeepAliveMs), plus CORS + OPTIONS preflight support. - Extend the CLI/config system with
--http-sse,--http-sse-keep-alive <ms>, and repeatable--http-cors <origin>flags (and matchingweb.jsonkeys). - Update the web demos/docs to showcase SSE + native browser
EventSource, and add CLI parsing/validation tests.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/test-web-cli.js | Adds unit tests for new CLI flags and config validation/merge behavior (SSE + CORS). |
| lib/runtime/transports/http.js | Implements SSE subscribe connection/route and adds CORS handling + OPTIONS preflight to the HTTP transport. |
| lib/runtime/cli-config.js | Adds defaults, argv parsing, config validation, merge rules, and help text for http.sse, http.sseKeepAliveMs, http.cors. |
| demo/web/typescript/README.md | Documents that HTTP subscribe-over-SSE is opt-in and points to the JS demo for an SSE example. |
| demo/web/javascript/runtime.mjs | Enables SSE + CORS for the JS demo runtime and exposes /topic for pairing with the publisher example. |
| demo/web/javascript/README.md | Documents SSE subscribe usage (curl + browser EventSource) and the required CORS setting. |
| demo/web/javascript/index.html | Adds a native EventSource panel demonstrating SSE subscribe from the browser. |
| bin/rclnodejs-web.js | Wires new config fields into HttpTransport construction and updates the startup banner wording. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+721
to
+736
| function _normaliseCors(value) { | ||
| if (value === undefined || value === null || value === false) return false; | ||
| if (value === true) return true; | ||
| if (typeof value === 'string') return new Set([value]); | ||
| if (Array.isArray(value)) { | ||
| if (!value.every((v) => typeof v === 'string')) { | ||
| throw new TypeError( | ||
| 'HttpTransport: cors array must contain only origin strings' | ||
| ); | ||
| } | ||
| return new Set(value); | ||
| } | ||
| throw new TypeError( | ||
| `HttpTransport: cors must be a boolean, string, or string[], got ${typeof value}` | ||
| ); | ||
| } |
Comment on lines
+469
to
+474
| // Preflight: browsers send OPTIONS before a cross-origin POST with a | ||
| // JSON content-type. Answer it directly (no auth, no body). | ||
| if (req.method === 'OPTIONS' && this.cors) { | ||
| res.writeHead(204).end(); | ||
| return; | ||
| } |
Comment on lines
+389
to
+402
| * @param {boolean} [options.sse=false] | ||
| * Enable `GET /capability/subscribe/<name>` Server-Sent Events | ||
| * streaming. Off by default; `subscribe` returns `unsupported_kind` | ||
| * unless this is set. | ||
| * @param {number} [options.sseKeepAliveMs=15000] | ||
| * Heartbeat comment interval for SSE streams, in milliseconds. Set to | ||
| * `0` to disable heartbeats. | ||
| * @param {boolean|string|string[]} [options.cors=false] | ||
| * Cross-Origin Resource Sharing policy. `false` (default) sends no | ||
| * CORS headers. `true` allows any origin (`Access-Control-Allow-Origin: | ||
| * *`). A string or array of strings allows only those origins (the | ||
| * request's `Origin` is echoed back when it matches). Required for a | ||
| * browser on a different origin to `fetch()` / `EventSource()` this | ||
| * transport. |
Comment on lines
+539
to
+556
| if (kind === 'subscribe') { | ||
| if (!this.sse) { | ||
| return _writeJson(res, 404, { | ||
| ok: false, | ||
| error: | ||
| 'subscribe over HTTP is disabled (enable `sse` or use WebSocket)', | ||
| code: 'unsupported_kind', | ||
| }); | ||
| } | ||
| if (req.method !== 'GET') { | ||
| res.setHeader('allow', 'GET'); | ||
| return _writeJson(res, 405, { | ||
| ok: false, | ||
| error: `method not allowed: ${req.method} (use GET for SSE subscribe)`, | ||
| code: 'method_not_allowed', | ||
| }); | ||
| } | ||
| const conn = new HttpSseConnection(req, res, name, { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Browsers and HTTP-only clients can now
subscribeover HTTP via Server-Sent Events and reach the transport cross-origin via CORS. Both are off by default and configurable in code, the demos, and the CLI.HttpSseConnectionand aGET /capability/subscribe/<name>route (opt-insse,sseKeepAliveMs); addcorsoption with OPTIONS preflight. Headers are deferred until the dispatcher acks, so rejected subscribes still return a normal JSON error.--http-sse,--http-sse-keep-alive <ms>, repeatable--http-cors <origin>flags and matchinghttp.sse/sseKeepAliveMs/corsweb.json keys; banner reflects SSE./topicto pair with the publisher example, add a nativeEventSourcepanel, document it.Fix: #1510