Transport-agnostic protocol constants + pure helpers for the remote-control receiver: the http-gate, the session-socket URL builder, reconnect backoff, and the client KeepAlive frame. No socket, no node, no m.global — fully unit-testable.
Members
(static, constant) CONTRACT_VERSION
The long-poll wire-contract version this client implements. The plugin advertises its own contractVersion in the /info probe body; JellyRock refuses a mismatch and stays dark rather than risk acting on a command shape it might misread. See remote-control-longpoll-contract.md (Versioning).
- Default Value
- 1
(static, constant) PLUGIN_ROUTE
--- HTTPS long-poll transport (#667) --- The plugin route prefix. JellyRock consumes the long-poll over TLS (roUrlTransfer) because Roku can't wss://. Unlike buildSocketUrl, these carry NO token in the URL — the caller attaches the standard Authorization header (baseRequest.buildAuthHeader), which already binds the session by DeviceId. See docs/architecture/remote-control-longpoll-contract.md.
- Default Value
- /JellyRock/RemoteControl
Methods
(static) buildLongPollUrl(serverUrl, waitMs) → {string}
Build the plugin's long-poll command-channel URL for a server base URL. Returns "" for a blank server URL. waitMs is JellyRock's requested hold ceiling; the client-side transfer timeout is set longer so a 204 (empty hold) always arrives before the transfer itself times out. https://host -> https://host/JellyRock/RemoteControl/poll?waitMs=
| Name | Type | Description |
|---|---|---|
serverUrl | dynamic | |
waitMs | integer |
- Type:
- string
(static) buildProbeUrl(serverUrl) → {string}
Build the plugin presence/version probe URL (200 = plugin present, 404 = absent). Returns "" for a blank server URL. No token in the URL (auth is header-based). https://host -> https://host/JellyRock/RemoteControl/info
| Name | Type | Description |
|---|---|---|
serverUrl | dynamic |
- Type:
- string
(static) buildSocketUrl(serverUrl, authToken, deviceId) → {string}
Build the Jellyfin session-socket URL from the server URL + session credentials. Returns "" when the server isn't http:// (never downgrades an https:// token onto ws://) or when a credential is missing. The deviceId MUST match the DeviceId in baseRequest's auth header so the socket binds the SAME session the REST API uses. http://host:port -> ws://host:port/socket?api_key=
| Name | Type | Description |
|---|---|---|
serverUrl | dynamic | |
authToken | dynamic | |
deviceId | dynamic |
- Type:
- string
(static) isHttpServer(serverUrl) → {boolean}
The http-gate. JellyRock can only open a ws:// socket to an http:// server — Roku can't do wss:// (no socket TLS), so an https:// session stays uncontrolled (the future plugin long-poll path). Both the advertised capability (deviceCapabilities) and the receiver gate on this, so they never disagree.
| Name | Type | Description |
|---|---|---|
serverUrl | dynamic |
- Type:
- boolean
(static) keepAliveFrame() → {string}
The client->server KeepAlive frame. Jellyfin's ForceKeepAlive asks the client to send these on the requested interval so the session isn't reaped by the inactivity timeout.
- Type:
- string
(static) nextBackoffMs(attempt) → {integer}
Exponential reconnect backoff, 0-based attempt: 1s, 2s, 4s, 8s, 16s, then capped at 30s.
| Name | Type | Description |
|---|---|---|
attempt | integer |
- Type:
- integer
(static) parseContractVersion(body) → {integer}
Extract the contractVersion from a /info probe body. Returns 0 for a blank/unparseable body, a non-object body, a missing key, or a non-numeric value — callers treat anything <> CONTRACT_VERSION as "no usable plugin". NEVER throws on a hostile/garbled body (it's network-controlled input): a string/object/bool contractVersion is rejected before any coercion that could raise at runtime.
| Name | Type | Description |
|---|---|---|
body | dynamic |
- Type:
- integer
(static) pluginBaseUrl(serverUrl) → {string}
Shared plugin route-prefix builder. Trims a single trailing slash on the server URL so we never emit "//". Returns "" for a missing/blank server URL.
| Name | Type | Description |
|---|---|---|
serverUrl | dynamic |
- Type:
- string