model.md 8.7 KB

Statum Model

Statum Frames

A statum frame consists of a JSON object with three keys:

  • content: a string containing the literal content of the frame.
  • signer: a string containing a signer ID.
  • signature: a base64 encoded signature verifying the content authored by the signer.

Statum Slot

  • key: a server issued ID for the slot.
  • scope: a string value that can be one of:
    • "device": persists between browser sessions.
    • "session": persists within the browser session (e.g. between tabs).
    • "flow": persists only within the current tab, while the tab remains on the site (e.g. persits on between navigation)
    • "page": persists only while the current page is loaded (e.g. clears on navigate).
    • "transient": does not persist, will never get sent back to the server - random or null key each time.
  • type: an application defined type name.

Statum Snapshot

A statum snapshot captures an aspect of the application state at a particular point-in-time. It is usually wrapped in a frame, which must be retained if it is to be sent back to the server after the transmit_after time. It contains:

  • as_at: an ISO 8601 string representing the time the snapshot was authored.
  • slot: a slot object (above)
  • transmit_after: an ISO 8601 string representing the time the slot will no longer be cached by the server and the application will need to send the snapshot. undefined if this is a unidirectional snapshot that never needs to be sent to the server. If it equals as_at, then the snapshot must always be sent.
  • invalid_after: an IOS 8601 string representing the time this snapshot should be considered invalid and not used.
  • private: a base64 encoded string of data only readable by the application server.
  • public: a JSON object with application-defines key/values.

Statum Action

  • uri: The URI to request.
  • method: The HTTP verb to use.
  • private: A base64 encoded string of data only readable by the application server (can be undefined)

Statum Directive

  • type: One of
    • "navigate": Used to redirect the frontend to a new URI.
    • "post": Used to cause the frontend to POST some data to a URI.
    • "set": Used to set a slot to a new snapshot.
    • "clear": Used to clear a slot.

Depending on the type, it will have other properties.

Navigate Directive

  • uri: The URI to navigate to.

Post Directive

  • uri: The URI to perform a form post to.
  • data: Key/value pairs for form data.

Set Directive

  • snapshot_frame: A frame containing a snapshot.

Clear Directive

  • slot_id: The ID of the slot to clear.

Statum HTTP API

Entrypoint Endpoint

GET /_statum/entrypoint: Get initial diretives based on the URL. has query param uri set to the browsers current window.location. Returns a JSON array of Statum Directives.

Slot Post Endpoint

POST /_statum/slots: Send a saved state snapshots frame to the server once it has reached its transmit_after time window. Sent as a JSON array of Statum Frames. Returns a JSON array of Statum Directives.

Action Endpoints

The URLs of action endpoints are entirely defined by the action iteself (in the uri property). An additional X-Statum-Private header should contain the private data of the action if present. Returns a JSON array of Statum Directives.

Request Headers

All HTTP API requests must have a X-Statum-Slot header for each relevant slot snapshot in scope.

There are two variations of this header:

  • For slots that have a snapshot that are within the transmit_after time window, an as_at timestamp is sent, e.g. X-Statum-Slot: key=d3cceb88-c211-41ee-a0b1-6a93f3b6331b; as_at=2026-07-06T07:33:02.332Z.
  • For slots that have a snapshot which has a transmit_after timestamp equal to its as_at timestamp, the frame is sent in base64, e.g. X-Statum-Slot: eyAiY29udGVudCI6ICIuLi4uIiwgInNpZ25lciI6ICJzMSIsICJzaWduYXR1cmUiOiAiZXlBaVkyOXVkR1Z1ZENJNklDSXVMaTR1SWl3Z0luTnBaMjVsY2lJNklDSnpNU0lzSUNKemFXZHVZWFIxY21VaU9pQWlJbjA9In0=

Before an HTTP request is sent, if one or more slot snapshots's transmit_after timestamp is in the past, and it is not equal to its as_at timestamp, a pre-flight request should be made to the slot post endpoint, which will in turn provide updated snapshots and a new as_at timestamp.

Javascript API

The Javascript API provides access to the state and actions via the global statum object. It automatically handles pre-flight requests, headers, and executing directives from the server.

Managing State

State snapshots can be cleaned up via statum.clear("typeName"). All snapshots can be cleared via statum.clear().

Reading State

State can be read via statum.read("typeName") which returns the snapshot object currently associated with the type "typeName".

To get the current frame of a type, use statum.getFrame("typeName") which will return the frame object that encapsulates the snapshot.

A full state object can be generated via statum.state() which returns a javascript object containing properties named after each type name that currently has a state, thier values being the current snapshot object, e.g. { "typeName": {"as_at": "....

Performing an Action

To perform an action, use statum.act(action) where action is a Statum action. Use statum.act(action, data) to send parameters along with the request. This is encoded as query params when action.method == GET, or encoded as form encoded otherwise. statum.act returns a promise which resolves when the request has completed and all directives have been run.

The act function can also be used with a string referring to an action name

Reacting to State

Callbacks can be attached to statum using statum.addStateListener("typeName", callback) which calls callback with an object containing:

  • type: the type name
  • frame: the frame (can be null if state has been cleared)
  • snapshot: the snapshot object (can be null if state has been cleared).

It is fired whenever a state of the specified type is set or cleared.

HTML API

The Javascript library also has some functionality inspired by HTMX using attributes prefixed with stm-. Ususally their values refer to something along the JSON object path of the current statum.state().

The following attributes are supported:

Text binding

The attribute stm-text binds the element's innerText to the specified state value, e.g. <span stm-text="typeName.label">.

HTML binding

The attribute stm-html binds the element's innerHTML to the specified state value.

Conditional display

The attribute stm-if adds or removes the element from the DOM depending on the expression inside the statement, e.g. <div stm-if="typeName.visable"> or <div stm-if="typeName.level > 5">

The attribute stm-else-if can only exist as the next sibling of an element with either stm-if or stm-else-if and has the same type of value as stm-if.

The attribute stm-else can exist only as the next sibling of an element with stm-if or stm-else-if.

Conditional classes

The attribute stm-class.x where x is any class name can be used to toggle classes on or off with a predicate, e.g. <div stm-class.alert="typeName.waterLevel > 50">.

Actions

The attribute stm-action binds the elements primary action (e.g. onclick for buttons, or onsubmit for forms), overriding their default behaviour to instead perform the statum action referenced (via state path). For example <button stm-action="typeName.deleteItem">Delete</button>.

It can be used with stm-data to also provide additional data to the action, e.g. <button stm-action="typeName.deleteItem" stm-data="{'confirm': true}">Delete</button>.

The attribute will also disable the element (and any children) while the action is being processed, and restore the original state once completed (or on error). In addition to this, the attribute stm-busy-class can be used to specify one or more css classes to apply during this time.

When used on a form, any form inputs are sent in the JSON or query string of the action, bound by their name, as they would for a regular native form submission.

Loops

the attribute stm-for-x-in= attribute (where x can be anything) repeats the current element multuple times for each item in the referenced array, and makes available the specified variable name in all stm- attributes in its children, and for all other stm- attributes on itself. For example:

<div class="list">
    <div class="item" stm-for-product-in="typeName.availableProducts" stm-class.featured="product.featured">
        <h3 stm-text="product.name"></h3>
        <p stm-text="product.description"></p>
        <span stm-text="product.price"></span>
        <button stm-action="product.addToCartAction">Add to cart</button>
    </div>
</div>