Utilities
Standalone helpers exported from 'comwit' for working with reactive proxies and inspecting state during development.
import { snapshot, isProxy, initDevTools } from 'comwit'
snapshot()
function snapshot<T extends object>(state: T): T
Returns a non-extensible, deep plain-object copy of a comwit reactive proxy. The result is detached from the store — later mutations to the proxy do not affect it, and nested objects are recursively snapshotted and made non-extensible (via Object.preventExtensions, so existing properties stay writable but none can be added or removed).
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'
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'
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'
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'
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.