Liking cljdoc? Tell your friends :D

dev.zeko.stube.conversation

The conversation data model — pure helpers, no I/O.

A conversation is the entire server-side state of a single user's session against one mounted flow. It is a plain map; persistence, history, and concurrency are all handled by working with these values.

────────────────────────────────────────────────────────────────────── Shape ──────────────────────────────────────────────────────────────────────

{:conv/id        "cv-019"
 :conv/instances {"ix-7e2" {…instance map…} …}
 :conv/stack     ["ix-7c1" "ix-7e2"]   ; bottom → top
 :conv/history   [previous-conv …]
 :conv/created   #inst "…"
 :conv/touched   #inst "…"}

An instance is the merged shape of an instantiated component:

{:instance/id        "ix-7e2"
 :instance/type      :auth/login
 :instance/parent    "ix-7c1" | nil
 :instance/resume    :on-login | nil
 :instance/rendered? false        ; toggled on first emitted patch
 …user state from (:component/init cdef)…}

The user-defined state lives at the top level of the instance map (not under a :state key). Handler functions therefore see one merged map and can both read instance metadata (:instance/id) and their own domain fields by simple keyword lookup. Handlers must not clobber the :instance/* keys.

The conversation data model — pure helpers, no I/O.

A *conversation* is the entire server-side state of a single user's
session against one mounted flow.  It is a plain map; persistence,
history, and concurrency are all handled by working with these values.

──────────────────────────────────────────────────────────────────────
Shape
──────────────────────────────────────────────────────────────────────

    {:conv/id        "cv-019"
     :conv/instances {"ix-7e2" {…instance map…} …}
     :conv/stack     ["ix-7c1" "ix-7e2"]   ; bottom → top
     :conv/history   [previous-conv …]
     :conv/created   #inst "…"
     :conv/touched   #inst "…"}

An *instance* is the merged shape of an instantiated component:

    {:instance/id        "ix-7e2"
     :instance/type      :auth/login
     :instance/parent    "ix-7c1" | nil
     :instance/resume    :on-login | nil
     :instance/rendered? false        ; toggled on first emitted patch
     …user state from (:component/init cdef)…}

The user-defined state lives at the top level of the instance map (not
under a `:state` key).  Handler functions therefore see one merged map
and can both read instance metadata (`:instance/id`) and their own
domain fields by simple keyword lookup.  Handlers must not clobber the
`:instance/*` keys.
raw docstring

child-slotclj

(child-slot parent child-iid)

Return the slot key in parent currently pointing at child-iid, or nil.

Return the slot key in `parent` currently pointing at `child-iid`, or nil.
sourceraw docstring

descendant-idsclj

(descendant-ids conv iid)

Return a vector of all instance ids transitively reachable from iid via :instance/children, including iid itself, in pre-order.

Return a vector of all instance ids transitively reachable from `iid`
via `:instance/children`, including `iid` itself, in pre-order.
sourceraw docstring

embedclj

(embed type)
(embed type args)

Return an embed spec for component type initialised with args.

Return an embed spec for component `type` initialised with `args`.
sourceraw docstring

embed?clj

(embed? x)

True if x looks like an embed spec.

True if `x` looks like an embed spec.
sourceraw docstring

instanceclj

(instance conv iid)

The instance map for iid, or nil.

The instance map for `iid`, or nil.
sourceraw docstring

instance-meta-keysclj

Keys the kernel manages on every instance map. Handlers must treat these as read-only; the kernel ignores any user changes to them.

:instance/children is the slot→iid map populated when a component declares :children in its definition. See instantiate-tree.

:instance/slot and :instance/previous are used by the [:call-in-slot …] overlay primitive: the temporary child remembers which parent slot it occupies and which child iid should be restored when it answers.

Keys the kernel manages on every instance map.  Handlers must treat
these as read-only; the kernel ignores any user changes to them.

`:instance/children` is the slot→iid map populated when a component
declares `:children` in its definition.  See [[instantiate-tree]].

`:instance/slot` and `:instance/previous` are used by the
`[:call-in-slot …]` overlay primitive: the temporary child remembers
which parent slot it occupies and which child iid should be restored
when it answers.
sourceraw docstring

instantiateclj

(instantiate cdef {:keys [embed/args]} parent-id resume-key)

Build a fresh instance map from a component definition and an embed spec. parent-id and resume-key may be nil for root instances.

This is the flat constructor: it does not look at :children. Use instantiate-tree when you want the kernel to materialise the whole subtree.

Build a fresh instance map from a component definition and an embed
spec.  `parent-id` and `resume-key` may be nil for root instances.

This is the *flat* constructor: it does not look at `:children`.
Use [[instantiate-tree]] when you want the kernel to materialise the
whole subtree.
sourceraw docstring

instantiate-treeclj

(instantiate-tree cdef embed-spec parent-id resume-key lookup-cdef)

Build a parent instance plus every child eagerly declared by its component definition's :children map.

:children is either a map {slot-key embed-spec} or a function of the freshly-initialised parent state returning such a map. Slot keys are arbitrary keywords the parent can reference from its :render via (s/render-slot self slot-key).

lookup-cdef is a 1-arg function (component-id) → cdef-map. Pass dev.zeko.stube.registry/lookup! from the kernel; the indirection lets this namespace stay registry-agnostic and easy to test in isolation.

Returns [parent-inst descendants] where descendants is a flat seq of every transitively-instantiated child instance, ready to be merged into :conv/instances. The returned parent-inst carries :instance/children populated with {slot-key child-iid}.

Build a parent instance plus every child eagerly declared by its
component definition's `:children` map.

`:children` is either a map `{slot-key embed-spec}` or a function of
the freshly-initialised parent state returning such a map.  Slot keys
are arbitrary keywords the parent can reference from its `:render`
via `(s/render-slot self slot-key)`.

`lookup-cdef` is a 1-arg function `(component-id) → cdef-map`.  Pass
`dev.zeko.stube.registry/lookup!` from the kernel; the indirection lets this
namespace stay registry-agnostic and easy to test in isolation.

Returns `[parent-inst descendants]` where `descendants` is a
flat seq of every transitively-instantiated child instance, ready to
be merged into `:conv/instances`.  The returned `parent-inst` carries
`:instance/children` populated with `{slot-key child-iid}`.
sourceraw docstring

local-signalclj

(local-signal self signal)

Return the per-instance signal key for logical signal on self.

Datastar signals are page-global. Binding two embedded components to the same $answer would therefore make them share client-side state. A local signal keeps the user-facing logical name (:answer) while suffixing the actual wire key with the instance id:

(local-signal {:instance/id "ix-1"} :answer)
;; => :answer-ix-1

merge-kept-signals maps local signal keys back to their logical names when the component lists the logical key in :component/keep.

Return the per-instance signal key for logical `signal` on `self`.

Datastar signals are page-global.  Binding two embedded components to
the same `$answer` would therefore make them share client-side state.
A local signal keeps the user-facing logical name (`:answer`) while
suffixing the actual wire key with the instance id:

    (local-signal {:instance/id "ix-1"} :answer)
    ;; => :answer-ix-1

[[merge-kept-signals]] maps local signal keys back to their logical
names when the component lists the logical key in `:component/keep`.
sourceraw docstring

mark-renderedclj

(mark-rendered conv iid)

Set :instance/rendered? true on iid and every descendant the parent's render placed into the DOM. Called once the kernel has emitted a frame's first patch onto the wire.

Marking the whole subtree at once matches reality: Datastar morphs the parent's HTML into the page in one shot, so children that the parent inlined via s/render-slot are now in the DOM and any future render of that child can use the (cheaper) morph-by-id default instead of re-emitting the shell.

Set `:instance/rendered? true` on `iid` and *every* descendant the
parent's render placed into the DOM.  Called once the kernel has
emitted a frame's first patch onto the wire.

Marking the whole subtree at once matches reality: Datastar morphs
the parent's HTML into the page in one shot, so children that the
parent inlined via `s/render-slot` are now in the DOM and any
*future* render of that child can use the (cheaper) morph-by-id
default instead of re-emitting the shell.
sourceraw docstring

merge-kept-signalsclj

(merge-kept-signals inst signals keep-keys)

Lift the entries of signals whose keys appear in keep-keys onto the instance map. This is the per-event two-way binding step: the user types in the browser, Datastar updates the signal client-side, and on every event the relevant signals land back on self before the handler sees it.

If the browser sends a per-instance key produced by local-signal, that value is lifted onto the logical kept key. Local values win over same-named global values so a component can safely say :keep #{:answer} and render (s/local-bind self :answer).

Lift the entries of `signals` whose keys appear in `keep-keys` onto the
instance map.  This is the per-event two-way binding step: the user
types in the browser, Datastar updates the signal client-side, and on
every event the relevant signals land back on `self` before the handler
sees it.

If the browser sends a per-instance key produced by [[local-signal]],
that value is lifted onto the logical kept key.  Local values win over
same-named global values so a component can safely say `:keep #{:answer}`
and render `(s/local-bind self :answer)`.
sourceraw docstring

merged-selfclj

(merged-self conv iid signals)

Look up iid in conv, find its component definition, and return the instance with kept signals merged in. This is the value passed to :render and :handle.

Look up `iid` in `conv`, find its component definition, and return the
instance with kept signals merged in.  This is the value passed to
`:render` and `:handle`.
sourceraw docstring

new-cidclj

(new-cid)

Mint a fresh conversation id.

Mint a fresh conversation id.
sourceraw docstring

new-conversationclj

(new-conversation)

Build an empty conversation.

Build an empty conversation.
sourceraw docstring

new-instance-idclj

(new-instance-id)

Mint a fresh instance id.

Mint a fresh instance id.
sourceraw docstring

pop-topclj

(pop-top conv)

Pop the top frame and remove its instance — and every embedded descendant — from the conversation. Returns [conv' popped-id].

Pop the top frame and remove its instance — and every embedded
descendant — from the conversation.  Returns `[conv' popped-id]`.
sourceraw docstring

preserve-metaclj

(preserve-meta old-instance new-state)

Merge new-state over old-instance while protecting the :instance/* keys. Used after a handler returns self' so a buggy handler can't break the instance metadata.

Merge `new-state` over `old-instance` while protecting the
`:instance/*` keys.  Used after a handler returns `self'` so a buggy
handler can't break the instance metadata.
sourceraw docstring

push-instanceclj

(push-instance conv inst)

Add inst to :conv/instances and push its id onto the stack.

Add `inst` to `:conv/instances` and push its id onto the stack.
sourceraw docstring

put-instanceclj

(put-instance conv inst)

Replace inst in the instances map without touching the stack.

Replace `inst` in the instances map without touching the stack.
sourceraw docstring

put-manyclj

(put-many conv instances)

Add a flat seq of instances to :conv/instances without touching the stack. Used by the kernel after instantiate-tree to deposit the eagerly-built children alongside their parent.

Add a flat seq of instances to `:conv/instances` without touching
the stack.  Used by the kernel after [[instantiate-tree]] to deposit
the eagerly-built children alongside their parent.
sourceraw docstring

remove-subtreeclj

(remove-subtree conv iid)

Remove iid and every embedded descendant from :conv/instances without touching the call stack.

Remove `iid` and every embedded descendant from `:conv/instances`
without touching the call stack.
sourceraw docstring

set-child-slotclj

(set-child-slot conv parent-id slot child-iid)

Point parent-id's slot at child-iid. If child-iid is nil, remove the slot.

Point `parent-id`'s `slot` at `child-iid`.  If `child-iid` is nil,
remove the slot.
sourceraw docstring

snapshotclj

(snapshot conv)

Append the current value of conv to its own :conv/history so the back button can rewind to it. Persistent maps make this essentially free in space. We strip the previous :conv/history from the snapshot so history doesn't grow quadratically.

Append the current value of `conv` to its own `:conv/history` so the
back button can rewind to it.  Persistent maps make this essentially
free in space.  We strip the previous `:conv/history` from the snapshot
so history doesn't grow quadratically.
sourceraw docstring

top-idclj

(top-id conv)

Id of the topmost frame on the stack, or nil if the stack is empty.

Id of the topmost frame on the stack, or nil if the stack is empty.
sourceraw docstring

top-instanceclj

(top-instance conv)

The instance map at the top of the stack, or nil if empty.

The instance map at the top of the stack, or nil if empty.
sourceraw docstring

touchclj

(touch conv)

Bump the :conv/touched timestamp.

Bump the `:conv/touched` timestamp.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close