sercrod

*ws-to

Summary

*ws-to is an optional targeting helper used together with *ws-send. It selects which WebSocket connection a *ws-send action will use by specifying a WebSocket URL. The directive has an alias n-ws-to; in this document, “*ws-to” refers to both *ws-to and n-ws-to.

If a Sercrod host only ever opens one WebSocket connection, *ws-to is not required and can be omitted. When a host has multiple WebSocket connections open (for example primary, notifications, or other channels), *ws-to lets you explicitly choose which URL to send to from markup.

Relationship to *ws-send and *websocket

*ws-to does not open WebSocket connections and does not decide where received messages are stored. Instead:

Basic example: single host with two WebSockets

The following example shows a host that connects to two different WebSocket URLs and uses *ws-to to direct messages to each one.

<serc-rod id="multi"
         data='{
           "apiUrl":   "wss://example.com/api",
           "notifyUrl":"wss://example.com/notify"
         }'
         *websocket="apiUrl">

  <!-- Connect a second WebSocket for notifications -->
  <span *websocket="notifyUrl"></span>

  <!-- Sends to the default connection (apiUrl) -->
  <button *ws-send="{ type: 'ping-api' }">
    Ping API
  </button>

  <!-- Sends specifically to notifyUrl -->
  <button *ws-send="{ type: 'ping-notify' }"
          *ws-to="%notifyUrl%">
    Ping notify
  </button>
</serc-rod>

Behavior:

Behavior

At render time, the *ws-send directive reads the raw *ws-to or n-ws-to attribute value:

On each click, when the handler runs, *ws-send resolves the target URL like this:

Once the target URL string has been calculated, the runtime calls the internal send helper:

The runtime then selects a WebSocket connection based on urlOrEmpty:

In all cases:

Evaluation timing

*ws-to participates in the evaluation lifecycle of *ws-send in a controlled way:

This design lets *ws-to depend on dynamic state (such as a URL stored in data) without forcing re-renders every time the target changes.

Interaction with text expansion

The value of *ws-to or n-ws-to is processed with Sercrod’s generic text expansion helper, so it follows the same rules as other text templates in the system.

Typical patterns:

The exact placeholder syntax and expansion rules are defined by Sercrod’s global configuration and text expansion logic. The important point is that *ws-to is not a full expression binding; it is a text template that is expanded into a plain string URL for _ws_send.

Multiple connections per host

A Sercrod host can maintain multiple WebSocket connections, one per URL, as long as the browser and server allow it.

Internally, each host keeps a map from URL to a holder object that contains:

When *websocket is used with different URLs on the same host, this map grows to include each distinct URL. If *websocket is used multiple times with the same URL:

In this environment:

Relationship to *into and received messages

*ws-to only affects where outgoing messages are sent. It does not influence how incoming messages are stored.

For incoming data:

*ws-to does not touch *into or any of those storage rules:

In other words:

Use with the websocket helper API

Sercrod’s host exposes a websocket helper object that includes a send method. Internally:

From a conceptual point of view:

This symmetry ensures that template-driven and script-driven code share the same rules for selecting WebSocket connections.

Best practices

Additional examples

Dynamic target based on environment:

<serc-rod id="env-ws"
         data='{
           "env": "prod",
           "wsUrls": {
             "dev":  "wss://dev.example.com/ws",
             "prod": "wss://api.example.com/ws"
           }
         }'
         *websocket="wsUrls[env]">

  <button *ws-send="{ type: 'ping', env }">
    Ping current env
  </button>
</serc-rod>

In this scenario:

Explicit URL selection for three channels:

<serc-rod id="multi3"
         data='{
           "chatUrl":   "wss://example.com/chat",
           "notifyUrl": "wss://example.com/notify",
           "metricsUrl":"wss://example.com/metrics"
         }'>
  <span *websocket="chatUrl"></span>
  <span *websocket="notifyUrl"></span>
  <span *websocket="metricsUrl"></span>

  <button *ws-send="{ type: 'chat-ping' }"
          *ws-to="%chatUrl%">
    Ping chat
  </button>

  <button *ws-send="{ type: 'notify-ping' }"
          n-ws-to="%notifyUrl%">
    Ping notify
  </button>

  <button *ws-send="{ type: 'metrics-ping' }"
          *ws-to="%metricsUrl%">
    Ping metrics
  </button>
</serc-rod>

Here, *ws-to and n-ws-to both associate buttons with specific connections, and the behavior is independent of the internal ordering of WebSocket connections on the host.

Notes