Utilities
Standalone helpers exported from @comwit/state for working with reactive proxies and inspecting state during development.
import { snapshot, isProxy, initDevTools } from '@comwit/state'
snapshot()
function snapshot<T extends object>(state: T): T
Returns a detached snapshot of a comwit reactive proxy. Later store mutations do not change it. Nested reactive objects are snapshotted recursively; properties are non-writable and objects are non-extensible. Treat the result as read-only and use ordinary actions to change state.
state must be a proxy (a model proxy or a nested proxy slice). Passing a plain object throws Error('Please use proxy object').
import { snapshot } from '@comwit/state'
const plain = snapshot(this.model.filter)
Top-level vs nested slices
The top-level model proxy also exposes a .snapshot() method, so for the whole model you can call it directly:
await savePostAction(this.model.snapshot())
For nested slices (e.g. state.filter, state.list.data), use the standalone snapshot() helper. It is the type-safe path — .snapshot() is only typed on the top-level proxy so that plain assignments like state.user = userFromApi keep working:
import { snapshot } from '@comwit/state'
await fetchCoders({ filter: snapshot(this.model.filter) })
This is the recommended way to convert proxies to plain objects before passing them to server actions or other APIs that require serializable data.
isProxy()
function isProxy(value: unknown): boolean
Returns true if value is a comwit reactive proxy — either a top-level model proxy or a nested proxy slice. Returns false for plain objects, primitives, and snapshots.
Useful for boundary code that must convert proxies to plain objects before serialization (server actions, logging, postMessage):
import { isProxy, snapshot } from '@comwit/state'
function toPlain<T extends object>(value: T): T {
return isProxy(value) ? snapshot(value) : value
}
initDevTools()
function initDevTools(options?: { maxLogSize?: number }): ComwitDevTools | undefined
Initializes the in-memory devtools instance and stores it on globalThis.__COMWIT_DEVTOOLS__. It tracks registered stores, captures state-change and action events, and keeps a rolling action log.
options.maxLogSize— maximum number of action log entries kept (default50). Older entries are dropped once the limit is exceeded.- Returns the existing instance if one was already initialized (idempotent).
- Returns
undefinedand does nothing whenprocess.env.NODE_ENV === 'production'.
import { initDevTools } from '@comwit/state'
if (process.env.NODE_ENV !== 'production') {
initDevTools({ maxLogSize: 100 })
}
The returned ComwitDevTools object exposes:
stores—Mapof model key to{ model, entry, unsubscribe }.getStoreSnapshot(model)—{ state, subscriberCount }for a model, ornullif not registered. Note:subscriberCountcurrently reports the total number of registered stores, not the subscriber count for that specific model.actionLog— array of recent action entries ({ name, args, result?, error?, timestamp }).subscribe(type, handler)— listen for'state-change','action', or'query'events; returns an unsubscribe function.