LiveView-side helpers for the preferences subsystem.
Emits preference-write push_events from a LiveView and owns the wire event
name that the BackpexPreferences JS hook listens for. The hook receives
the event, POSTs to the preferences controller, and the controller
persists through the configured adapter.
The event name is a browser contract — treat it as a stable wire protocol
and keep it aligned with assets/js/hooks/_preferences.js. The name is
returned from event_name/0.
Summary
Functions
Name of the cookie carrying the browser's unacknowledged preference writes.
Builds the browser routing manifest for the configured preference adapters.
Name of the LiveView push_event used to signal a preference write to the
browser-side BackpexPreferences hook.
Builds the Backpex.Preferences.Context for a LiveView mount.
Pushes a preference-write event to the browser.
Functions
Name of the cookie carrying the browser's unacknowledged preference writes.
A browser contract — keep it aligned with COOKIE_NAME in
assets/js/hooks/_preferences.js.
Builds the browser routing manifest for the configured preference adapters.
Each route carries an opaque token derived from the namespace its adapter actually uses. This allows session-backed values to survive a tenant change while values stored in a tenant-scoped adapter remain isolated. The manifest contains no raw session or application scope values.
Returns nil when the endpoint or Phoenix session cannot provide the secrets
required to sign the route tokens.
Name of the LiveView push_event used to signal a preference write to the
browser-side BackpexPreferences hook.
Exposed for tests that need to assert on the emitted event shape.
Builds the Backpex.Preferences.Context for a LiveView mount.
Combines the session and socket.assigns (what scope resolvers need)
with the preferences the browser is holding, which take precedence over
stored values.
The browser overrides the server exactly when it holds a write the server has not acknowledged. Those writes reach us over the transport that rendered the page, and each transport can only see one carrier:
CONNECTED mount — the
backpex_prefsconnect param. A LiveView reads the session snapshot taken when the websocket connected, so on alive_redirectre-mount it cannot see any preference written since and would render stale column/metric visibility. The browser mirrors those writes insessionStorageand hands them back on every join, before mount renders.DISCONNECTED mount — the
backpex_prefscookie (seeclient_cookie/0). The session cookie a document GET carries can be a full POST round-trip behind the user's last write, so the freshly-read session is not authoritative: it renders the pre-toggle state, which LiveView then patches away — the flash. The browser writes its unacknowledged writes tobackpex_prefssynchronously, so entries that fit its 3072-byte budget ride the very next request. The cookie is skipped when namespace tokens are unavailable; in either degradation case the first paint may be stale until LiveView connects. Entries retire as soon as their POST responds, so the cookie cannot permanently shadow an adapter.Each cookie entry is only honored when its signed adapter namespace token matches the route that owns the key on this request. This is the one place an attacker-plantable (or simply outlived) cookie lands, so the check runs here and does not trust the browser to have discarded it already.
Both carriers feed the same Backpex.Preferences.Context client overlay.
When the pending value is available to both transports, the disconnected and
connected renders derive their state from the same value.
Only valid for calls during mount/3 (including on_mount hooks), where
Phoenix.LiveView.get_connect_params/1 is available.
Pushes a preference-write event to the browser.
The BackpexPreferences JS hook listens for this event and persists the
value via the preferences controller.
This is the transport primitive: it hardcodes the browser round-trip and
never consults an adapter. Prefer Backpex.Preferences.put/4, which asks the
key's adapter first and only falls back here when the adapter cannot write
outside an HTTP request cycle ({:error, :requires_http} — the Session
adapter, and the zero-config default). An adapter that persists server-side
then costs no round-trip at all.
Returns the updated socket so it composes in pipelines.
Options
:mirror- set to:sessionto additionally mirror the value into the browser's sessionStorage. Required for preferences that are read at mount and server-rendered (for example column and metric visibility): the Session adapter reads the websocket-connect session snapshot, which is frozen for the life of the socket, so without the mirror any write after connect silently reverts on the nextlive_redirectre-mount. The browser hands mirrored values back in the connect params of every join, wheremount_context/2picks them up.
Examples
socket
|> Backpex.Preferences.LiveView.push_write(Backpex.Preferences.Keys.theme(), "dark")