Skip to content

feat: host-declared controller URL for rooms - #14

Merged
tim4724 merged 1 commit into
mainfrom
feat/controller-url
Jul 1, 2026
Merged

feat: host-declared controller URL for rooms#14
tim4724 merged 1 commit into
mainfrom
feat/controller-url

Conversation

@tim4724

@tim4724 tim4724 commented Jul 1, 2026

Copy link
Copy Markdown
Owner

What

Adds an optional url template to create so a host can tell a generic controller what to load for a room:

{ "type": "create", "clientId": "...", "maxClients": 4,
  "url": "https://play.example.com/{room}?instance={instance}" }

The relay resolves {room} (the code) and {instance} (the holding machine) once at create time and returns the finished URL in created, every joined, and GET /room/:code. A native controller that only has the room code can then discover which page to load and where to connect.

Why

Enables a general controller app: the user types a room code, and the room itself carries the URL to render, so the app needs no per-game hard-coding. The code and instance aren't known until create, so the host ships a template and the relay fills the values it owns.

Validation

Templates are checked on create and rejected otherwise:

  • absolute https: only (no javascript:/file:/custom schemes)
  • at most 512 bytes (UTF-8)
  • no spaces or control characters (closes a NUL/tab pass-through: the WHATWG URL parser silently strips these, so they'd otherwise survive into the emitted URL)
  • balanced braces, only the {room}/{instance} placeholders

Substituted values are percent-encoded. Rooms without a url are unchanged (the field is simply absent, so existing clients and the /room/:code shape are unaffected).

Tests

+9 tests: fill, static URL, omitted, non-https, unknown placeholder, control chars, unclosed brace, UTF-8 byte cap, and the reclaim/reconnect join path. bun test: 91 pass / 8 skip / 0 fail.

Follow-up (not in this PR)

  • ALLOWED_CONTROLLER_ORIGINS allowlist: a shared relay currently accepts any https: origin, which a generic native shell would then load. Gating loadable origins server-side is a policy decision left open; https:-only + validation are the baseline.

Also fixes a pre-existing mermaid render error in the README: two sequence-diagram Notes contained ;, which mermaid treats as a statement separator.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Bm9uqStLTmcFSMSJStqPU3

A host can pass a `url` template on `create`, e.g.
"https://play.example.com/{room}?instance={instance}". The relay resolves
{room} (the code) and {instance} (the holding machine) once at create time
and returns the URL in `created`, every `joined`, and `GET /room/:code`, so a
generic controller that only has the room code can discover which page to load
and where to connect.

Templates are validated on create: https-only, at most 512 bytes, no spaces or
control characters, balanced braces, and only the {room}/{instance}
placeholders. Substituted values are percent-encoded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bm9uqStLTmcFSMSJStqPU3
@tim4724
tim4724 merged commit 326aced into main Jul 1, 2026
2 checks passed
@tim4724
tim4724 deleted the feat/controller-url branch July 1, 2026 17:29
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