This specification defines a station client for coordinating same-origin execution contexts around a single logical connection to a Sovereignbase base station.

A station client provides a local-first coordination layer for applications that run in multiple same-origin contexts while sharing one opportunistic connection to a Sovereignbase base station.

This specification is maintained alongside a reference implementation.

To use the reference implementation see:

To test how the tabs sync locally see:

Introduction

The abstract model in this specification is intentionally language-agnostic. It defines relaying, request-response transactions, leadership, and shutdown behavior without requiring a particular local coordination mechanism or transport stack.

The JavaScript reference binding defined below maps that abstract model to a concrete package surface and to a concrete base station wire convention.

This document references Infra [[INFRA]]. Infra-defined terminology, including tuple, is to be interpreted as defined there.

Terminology

base station
An often paid infrastructure service with actor-delegated access-control with which an actor's station client coordinates opaque snapshot persistence, opaque frame relay.
station client
A local agent that coordinates same-origin execution contexts and may maintain an opportunistic transport to a base station.
same-origin context
A browsing context or worker that participates in the same station client coordination group.
leader context
The same-origin context that currently owns the active base station transport for a coordination group.
follower context
A same-origin context that participates in local coordination but does not currently own the active base station transport.
application message
An implementation-defined payload object that represents domain data exchanged through the station client.
coordination group
The set of station client instances that share the same origin and the same configured base station endpoint identifier.

Station Client Model

A station client operates over a coordination group. Each group MAY be configured with a base station endpoint identifier such as a WebSocket URL. When no endpoint identifier is configured, the group operates in local-only mode.

At most one leader context MUST own the active base station transport for a coordination group at a time. Other contexts in the same group MUST behave as follower contexts.

Relay

To relay an application message is to publish that application message to other same-origin contexts in the same coordination group.

A relay operation MUST NOT require a base station transport in order to complete locally.

A leader context SHOULD opportunistically forward a relayed application message to the base station transport, where it gets relayed to peers on a given topic according to logic outside the scope of this specification.

A relay operation MUST NOT synthesize a loopback local delivery back to the calling context unless an implementation explicitly specifies otherwise.

Transact

To transact is to submit an application message as a request to the base station and await a correlated response.

A transact operation MUST resolve with the corresponding application message response when the base station returns one.

A transact operation MAY instead resolve with a transport-unavailable result when the request cannot be issued, for example because no base station endpoint is configured, because the environment is offline, or because no active base station transport is currently available.

A transact operation MAY be aborted by the caller. A caller-supplied abort signal is distinct from any implementation-defined cleanup deadline used to discard stale routing state.

Inbound Messages

When a station client receives an application message from the base station that is not a transact response, it MUST dispatch that application message locally and SHOULD relay it to other same-origin contexts in the same coordination group.

Shutdown

When a station client is closed, it MUST release local coordination resources, cease further transport activity, and reject any pending transact operations that are still owned by that instance.

JavaScript Reference Binding

This section defines the JavaScript package surface exposed by the current reference implementation.

IDL

        typedef object StationClientMessage;
        typedef (StationClientMessage or boolean) StationClientTransactResult;

        dictionary StationClientTransactOptions {
          AbortSignal signal;
          [EnforceRange] unsigned long ttlMs = 30000;
        };

        [Exposed=(Window,Worker)]
        interface StationClient {
          constructor(optional USVString webSocketUrl = "");
          undefined relay(StationClientMessage message);
          Promise<StationClientTransactResult> transact(
            StationClientMessage message,
            optional StationClientTransactOptions options = {}
          );
          undefined close();
          undefined addEventListener(
            DOMString type,
            EventListener? callback,
            optional (AddEventListenerOptions or boolean) options = {}
          );
          undefined removeEventListener(
            DOMString type,
            EventListener? callback,
            optional (EventListenerOptions or boolean) options = {}
          );
        };
        

Construction

Constructing a {{StationClient}} with an empty webSocketUrl places the instance in local-only mode.

Instances constructed with the same origin and the same webSocketUrl participate in the same coordination group.

The relay() Method

The {{StationClient/relay(message)}} method performs a relay operation by publishing |message| to other same-origin contexts in the coordination group.

If the calling instance currently owns the active base station transport, it attempts to forward |message| to the base station.

In the current binding, ordinary relayed upstream messages MAY be buffered while the host reports online status but no open upstream WebSocket is yet available.

Calling {{StationClient/relay(message)}} does not by itself dispatch a local loopback message event to the same instance.

The transact() Method

The {{StationClient/transact(message, options)}} method performs a transact operation by submitting |message| as a request to the base station and returning a promise.

That promise resolves with an application message response when a correlated response is received from the base station.

That promise resolves with false when the binding can determine that the request cannot presently be issued.

In the current binding, {{StationClient/transact(message, options)}} resolves with false without issuing an upstream request when the instance is closed, when no webSocketUrl is configured, when the host reports offline status, or when the calling instance is the leader but no open upstream WebSocket is available.

If options.signal is aborted, the promise rejects with an abort error.

options.ttlMs sets the leader-side stale-routing lifetime for a pending follower request. It is not a general request timeout.

This binding does not guarantee bounded completion time for follower requests that are waiting for leader-side handling. Without a correlated response or caller-supplied abort, such a promise MAY remain pending.

The close() Method

The {{StationClient/close()}} method closes the instance, releases local coordination resources, closes the active base station transport if owned by the instance, and rejects any still-pending transact operations owned by the instance.

After {{StationClient/close()}}, later {{StationClient/relay(message)}} calls have no effect and later {{StationClient/transact(message, options)}} calls resolve with false.

Events

A {{StationClient}} dispatches a message event when it receives an application message from another same-origin context or from the base station.

The JavaScript reference binding exposes {{StationClient/addEventListener()}} and {{StationClient/removeEventListener()}} for observing those events.

The event object MUST be a {{CustomEvent}}, and its {{CustomEvent/detail}} attribute MUST contain the application message.

Transact responses are delivered through the promise returned by {{StationClient/transact(message, options)}} rather than through the message event.

Host Environment Requirements

The JavaScript reference binding requires host support for BroadcastChannel, EventTarget, CustomEvent, MessageEvent, AbortSignal, and crypto.randomUUID().

Upstream transport additionally depends on WebSocket. Leadership and reconnection behavior additionally depend on navigator.locks and navigator.onLine.

In the current binding, upstream connection attempts are only started when a webSocketUrl is configured and the host reports online status. Reconnection attempts cease while the host reports offline status and resume only after online status returns.

Base Station Wire Convention

The JavaScript reference binding uses a WebSocket-based base station transport and serializes transport payloads with MessagePack [[MSGPACK]].

A relayed or inbound application message is transported as the application message value itself.

A transact request is transported as the tuple ["station-client-request", id, message], where id is a binding-generated request identifier.

A transact response is transported as the tuple ["station-client-response", id, message], where id identifies the pending transact operation being fulfilled.