@caspian-vega/nano-devtools
v0.2.1
Published
Framework-agnostic in-memory logger for nanostores plus a Svelte web-component devtools UI that opens in an independent browser window. Capture store state changes/actions and inspect them (search, filter, timestamps) in a separate window.
Maintainers
Readme
@caspian-vega/nano-devtools
In-memory log buffer for nanostores, plus a separate browser window that renders it.
Part of caspian-vega-astro-libs.
Install
npm install --save-dev @caspian-vega/nano-devtools
# or
pnpm add -D @caspian-vega/nano-devtoolsPeer dependencies: nanostores, @nanostores/logger.
Usage
Capture events:
import { memoryLogger } from '@caspian-vega/nano-devtools/logger';
const unbind = memoryLogger({ MyStore: $store });Open the window:
import appHtml from '@caspian-vega/nano-devtools/devtools.html?raw';
import { configureNanoDevtools } from '@caspian-vega/nano-devtools/host';
configureNanoDevtools({ appHtml });
window.nanoDevtools();Entry points
| Import | Contains |
| ----------------- | -------------------------------------------------------------------------- |
| . | Everything below |
| ./logger | memoryLogger, logStore, clearLogs, MAX_LOG_ENTRIES |
| ./host | configureNanoDevtools, openDevtools, closeDevtools, toggleDevtools |
| ./transport | Transport and the four transport factories |
| ./devtools.html | Self-contained popup document, import with ?raw |
API
memoryLogger(stores, opts?)
Binds stores and appends their events to logStore.
stores(Record<string, AnyStore>, required): stores to bind, keyed by the name shown in the log.opts(object, optional): passed through to@nanostores/logger.- Returns:
() => voidthat unbinds every store passed in.
const unbind = memoryLogger({ Cart: $cart, User: $user });
unbind();logStore
Atom<LogEntry[]> holding captured entries, newest last. Capped at MAX_LOG_ENTRIES.
import { logStore } from '@caspian-vega/nano-devtools/logger';
logStore.subscribe((entries) => console.log(entries.length));clearLogs()
Empties the buffer.
- Returns:
void
MAX_LOG_ENTRIES
number, value 1000. Entries beyond this are dropped from the front.
configureNanoDevtools(options)
Registers the popup document and installs window.nanoDevtools.
options.appHtml(string, required): the self-contained popup document.- Returns:
void
configureNanoDevtools({ appHtml });openDevtools()
Opens the popup window and starts streaming entries to it.
- Returns:
void
Call this from a user gesture or the browser console. Popup blockers stop calls from anywhere else.
closeDevtools()
Closes the popup and stops streaming.
- Returns:
void
toggleDevtools()
Calls closeDevtools() when the popup is open, openDevtools() otherwise. This is what
window.nanoDevtools is bound to.
- Returns:
void
createHostTransport(getPopup)
getPopup(() => Window | null | undefined, required): resolved on every send.- Returns:
Transport<HostToPopup, PopupToHost>
createPopupTransport()
- Returns:
Transport<PopupToHost, HostToPopup>
createPostMessageTransport(getTarget, origin?)
getTarget(() => Window | null | undefined, required): resolved on every send.- Returns:
Transport<TSend, TRecv>
createBroadcastTransport(channelName)
channelName(string, required):BroadcastChannelname. Same origin only.- Returns:
Transport<TSend, TRecv>
Types
LogEntryType
'change' | 'action-start' | 'action-end' | 'action-error' | 'mount' | 'unmount'
LogEntry
id(number): sequence number.timestamp(number): epoch milliseconds.type(LogEntryType)storeName(string): key used at bind time.actionName(string, optional)actionId(number, optional)changed(string, optional): key path, map stores only.oldValue,newValue(unknown, optional)valueMessage(string, optional)args(unknown[], optional): action arguments.error({ message: string; stack?: string }, optional)
Transport
send(msg): sends one message.onMessage(handler): returns an unsubscribe function.close(): releases the underlying channel.
ConfigureOptions
appHtml(string): popup document passed toconfigureNanoDevtools.
Constraints
- Development only. The buffer grows with every event, so guard the wiring with
import.meta.env.DEV. - The popup needs a same-origin
BroadcastChannel, withpostMessageas fallback. - Logged values are held by reference, so large payloads stay alive as long as the buffer does.
Synergies
See SYNERGIES.md.
License
MIT
