Musubi.Store behaviour (musubi v0.3.0)

Copy Markdown View Source

Compile-time DSL entrypoint, behaviour contract, and runtime facade for Musubi store modules.

Stores use Musubi.Store and implement init/1, render/1, update/2, handle_command/3, handle_async/3, handle_info/2, and terminate/2. Root stores opt in with use Musubi.Store, root: true and may also implement mount/2 to receive client mount params before init/1 runs.

render/1 returns the resolved Elixir-shaped term; wire conversion happens separately via Musubi.Wire.to_wire/1.

Runtime facade

use Musubi.Store blanket-imports this module so every helper below is available bare inside a store's callbacks. Each helper is a defdelegate to the underlying implementation module (Musubi.Socket, Musubi.Stream, Musubi.Lifecycle, Musubi.Child, Musubi.DSL.Render) or a defmacro that lowers to a runtime call (the async lifecycle helpers).

SurfaceHelpers
Socketassign/2,3, assign_new/3, update/3, changed?/2, get_private/2,3, put_private/3
Streamsstream/3,4, stream_configure/3, stream_insert/3,4, stream_delete/3, stream_delete_by_item_key/3
Lifecycleattach_hook/4, detach_hook/3
Asyncassign_async/3,4, start_async/3,4, stream_async/3,4, cancel_async/2,3
Render builderschild/2, stream/1, async_stream/1

The fully-qualified module forms remain available — the facade is purely additive — so Musubi.Socket.assign(...) keeps working alongside the bare assign(...) form preferred inside store modules.

Summary

Callbacks

Handles an async result routed to the current store.

Handles a declared command for the current store.

Handles an in-process message routed to the current store.

Optional. Invoked when a chunk has been received (channel mode) or a client upload_progress message arrived (external mode) for an upload-tracked entry.

Initializes a freshly-created store socket.

Initializes a freshly-mounted store socket.

Mounts a root store with client-supplied params.

Produces the resolved Elixir-shaped render output for the current store.

Handles store teardown after the page runtime begins terminating.

Updates a mounted store socket from new parent-supplied assigns.

Optional. When defined for an upload name, the preflight switches to external mode and forwards the returned meta map to the client uploader. Musubi treats meta opaquely.

Functions

See Musubi.Async.assign_async/3,4.

See Musubi.DSL.Render.async_stream/1. Render-time placeholder.

See Musubi.Async.cancel_async/2,3.

Cancels a single upload entry by ref, emitting {op: cancel}.

Consumes the completed upload entries for name via fun.

See Musubi.Async.start_async/3,4.

See Musubi.DSL.Render.stream/1. Render-time placeholder.

See Musubi.Async.stream_async/3,4.

Returns {completed, in_progress} for the upload named name.

Types

assigns()

@type assigns() :: %{optional(Musubi.Socket.assign_key()) => value()}

async_name()

@type async_name() :: Musubi.Async.name_arg()

async_result()

@type async_result() :: {:ok, value()} | {:exit, value()}

command_name()

@type command_name() :: atom()

command_payload()

@type command_payload() :: %{optional(String.t() | atom()) => value()}

command_reply()

@type command_reply() :: map()

message()

@type message() :: value()

rendered()

@type rendered() ::
  nil
  | boolean()
  | number()
  | String.t()
  | atom()
  | [rendered()]
  | %{optional(String.t() | atom()) => rendered()}

root_params()

@type root_params() :: %{optional(String.t()) => value()}

terminate_reason()

@type terminate_reason() :: :normal | :shutdown | {:shutdown, value()} | value()

value()

@type value() ::
  nil
  | boolean()
  | number()
  | String.t()
  | atom()
  | pid()
  | reference()
  | port()
  | tuple()
  | [value()]
  | %{optional(value()) => value()}

Callbacks

handle_async(name, async_fun_result, socket)

(optional)
@callback handle_async(
  name :: async_name(),
  async_fun_result :: async_result(),
  socket :: Musubi.Socket.t()
) :: {:noreply, Musubi.Socket.t()}

Handles an async result routed to the current store.

handle_command(name, payload, socket)

@callback handle_command(
  name :: command_name(),
  payload :: command_payload(),
  socket :: Musubi.Socket.t()
) ::
  {:noreply, Musubi.Socket.t()} | {:reply, command_reply(), Musubi.Socket.t()}

Handles a declared command for the current store.

handle_info(message, socket)

(optional)
@callback handle_info(message :: message(), socket :: Musubi.Socket.t()) ::
  {:noreply, Musubi.Socket.t()}

Handles an in-process message routed to the current store.

handle_progress(name, entry, socket)

(optional)
@callback handle_progress(
  name :: atom(),
  entry :: Musubi.Upload.Entry.t(),
  socket :: Musubi.Socket.t()
) :: {:noreply, Musubi.Socket.t()}

Optional. Invoked when a chunk has been received (channel mode) or a client upload_progress message arrived (external mode) for an upload-tracked entry.

init(socket)

(optional)
@callback init(socket :: Musubi.Socket.t()) :: {:ok, Musubi.Socket.t()}

Initializes a freshly-created store socket.

mount(socket)

(optional)
@callback mount(socket :: Musubi.Socket.t()) :: {:ok, Musubi.Socket.t()}

Initializes a freshly-mounted store socket.

This callback is kept for compatibility with pre-session stores. Prefer init/1 for child stores and mount/2 for root-only client params.

mount(params, socket)

(optional)
@callback mount(params :: root_params(), socket :: Musubi.Socket.t()) ::
  {:ok, Musubi.Socket.t()}

Mounts a root store with client-supplied params.

Only modules declared with use Musubi.Store, root: true receive this callback. Child stores use init/1.

render(socket)

@callback render(socket :: Musubi.Socket.t()) :: rendered()

Produces the resolved Elixir-shaped render output for the current store.

The returned term is still in Musubi's Elixir form. The runtime converts it to wire form later with Musubi.Wire.to_wire/1.

terminate(reason, socket)

(optional)
@callback terminate(reason :: terminate_reason(), socket :: Musubi.Socket.t()) :: :ok

Handles store teardown after the page runtime begins terminating.

update(assigns, socket)

(optional)
@callback update(assigns :: assigns(), socket :: Musubi.Socket.t()) ::
  {:ok, Musubi.Socket.t()}

Updates a mounted store socket from new parent-supplied assigns.

upload_external(name, entry, socket)

(optional)
@callback upload_external(
  name :: atom(),
  entry :: Musubi.Upload.Entry.t(),
  socket :: Musubi.Socket.t()
) :: {:ok, map(), Musubi.Socket.t()}

Optional. When defined for an upload name, the preflight switches to external mode and forwards the returned meta map to the client uploader. Musubi treats meta opaquely.

Functions

assign(socket, attrs)

See Musubi.Socket.assign/2.

assign(socket, key, value)

See Musubi.Socket.assign/3.

assign_async(socket, key_or_keys, fun)

(macro)

See Musubi.Async.assign_async/3,4.

assign_async(socket, key_or_keys, fun, opts)

(macro)

assign_new(socket, key, fun)

See Musubi.Socket.assign_new/3.

async_stream(name)

(macro)

See Musubi.DSL.Render.async_stream/1. Render-time placeholder.

attach_hook(socket, name, stage, fun)

See Musubi.Lifecycle.attach_hook/4.

cancel_async(socket, target)

See Musubi.Async.cancel_async/2,3.

cancel_async(socket, target, reason)

See Musubi.Async.cancel_async/3.

cancel_upload(socket, name, ref)

Cancels a single upload entry by ref, emitting {op: cancel}.

changed?(socket, key)

See Musubi.Socket.changed?/2.

child(module, opts)

See Musubi.Child.child/2.

consume_uploaded_entries(socket, name, fun)

Consumes the completed upload entries for name via fun.

fun receives (meta, entry) where meta is %{path: path} in channel mode or %{external: meta} in external mode. Returns {:ok, val} to consume the entry (removing it from internal state) or {:postpone, val} to leave it in place.

Returns the updated socket and the list of vals produced.

Must be called from a command handler.

detach_hook(socket, name, stage)

See Musubi.Lifecycle.detach_hook/3.

get_private(socket, key, default \\ nil)

See Musubi.Socket.get_private/3.

put_private(socket, key, value)

See Musubi.Socket.put_private/3.

start_async(socket, name, fun)

(macro)

See Musubi.Async.start_async/3,4.

start_async(socket, name, fun, opts)

(macro)

stream(name)

(macro)

See Musubi.DSL.Render.stream/1. Render-time placeholder.

stream(socket, name, items, opts \\ [])

See Musubi.Stream.stream/4.

stream_async(socket, name, fun)

(macro)

See Musubi.Async.stream_async/3,4.

stream_async(socket, name, fun, opts)

(macro)

stream_configure(socket, name, opts)

See Musubi.Stream.stream_configure/3.

stream_delete(socket, name, item)

See Musubi.Stream.stream_delete/3.

stream_delete_by_item_key(socket, name, item_key)

See Musubi.Stream.stream_delete_by_item_key/3.

stream_insert(socket, name, item, opts \\ [])

See Musubi.Stream.stream_insert/4.

update(socket, key, fun)

See Musubi.Socket.update/3.

uploaded_entries(socket, name)

Returns {completed, in_progress} for the upload named name.

Examples

{completed, _in_progress} = uploaded_entries(socket, :avatar)