Data Inspector
A Vue query workbench for live server-side objects: register data sources, then compose jora queries in the owning process.
Package: @devframes/plugin-data-inspector · Vue + Vite


What it does
- Query workbench — a CodeMirror jora editor with server-computed autocomplete; queries auto-run as you type, state in the URL hash.
- Auto rerun — optional poller (
auto rerun every N seconds). - Result viewer — normalizes to strict JSON (circulars →
$ref; Maps, Sets, class instances, functions, Dates get type badges) plus per-query stats. - Expansion, shape & filters — deep nodes fetch lazily via
load deeper; a shape panel shows a one-level skeleton; filters drop functions and_/$properties. - Saved queries — recipes (
query+ title/description + filters) in workspace (committable) and project (per-checkout) scopes.
A built-in example source registers by default; opt out with exampleSource: false (--no-example; agent DEVFRAME_DATA_INSPECTOR_EXAMPLE=0).
Providing data sources
The registry is process-global — register anywhere, before or after mount.
import { registerDataSource } from '@devframes/plugin-data-inspector/registry'
registerDataSource({
id: 'my-plugin:store', // namespace with your plugin id
title: 'My plugin store',
description: 'The live state store',
icon: 'i-ph:database-duotone',
data: () => store,
queries: [
{ title: 'Active sessions', query: 'sessions.mapEntries().value.[active]' },
{ title: 'Config (data only)', query: 'config', excludeFunctions: true },
],
})data is a plain value or sync/async factory; static: true resolves it once; queries show read-only beside saved ones; registerDataSource returns an unregister callback. Zero-dependency integrations register through the typed context service ctx.services.whenAvailable('devframes:plugin:data-inspector:sources', …).
WARNING
Queries are eval-grade: jora invokes any function reachable as an own property and fires own getters. Register live objects accordingly, and keep endpoints on loopback.
Deep linking
Workbench state lives in the URL hash (#source=<id>&query=<jora>, filters); the handshake token rides the query string (?devframe_auth_token=), scrubbed on read.
In a hub, another dock jumps to a source via dock activation — rpc.call('hub:docks:activate', { dockId: 'devframes:plugin:data-inspector', params: { sourceId } }) (waits for registration).
Standalone
pnpx @devframes/plugin-data-inspector # the example source
pnpx @devframes/plugin-data-inspector stats.json log.jsonl # one static source per data file
pnpx @devframes/plugin-data-inspector build stats.json # self-contained static export
pnpx @devframes/plugin-data-inspector attach # attach to a process running the agent.json parses whole; .jsonl / .ndjson as a record array. build embeds the dataset in a static site.
Mount into a Vite host
For Vite DevTools:
// vite.config.ts
import createDataInspectorDevframe from '@devframes/plugin-data-inspector'
import { createPluginFromDevframe } from '@vitejs/devtools-kit/node'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
createPluginFromDevframe(createDataInspectorDevframe()),
],
})Register sources with registerDataSource, or mount via devframeVite(createDataInspectorDevframe()) from @devframes/vite/single.
Programmatic
import { createDataInspectorDevframe } from '@devframes/plugin-data-inspector'
export default createDataInspectorDevframe({
exampleSource: false,
})Attach to another Node process
The target starts the agent:
import { exposeDataInspector } from '@devframes/plugin-data-inspector/inject'
await exposeDataInspector({
sources: [{ id: 'app:store', title: 'App store', data: () => store }],
})sources pre-registers entries; call it empty to expose whatever's registered. Or code-free:
DEVFRAME_DATA_INSPECTOR=1 node --import @devframes/plugin-data-inspector/inject server.jsThis auto-registers a globalThis source:
// somewhere in the running process
globalThis.store = store
globalThis.cache = cacheIt reads globalThis at query time, so later assignments appear next run (opt out: DEVFRAME_DATA_INSPECTOR_GLOBAL=0).
The agent binds 127.0.0.1, requires the trust handshake with a per-run token, and writes its endpoint to node_modules/.data-inspector/agent.json, which attach reads (or pass ws://… + --token).
RPC surface
All devframes:plugin:data-inspector:*:
| Function | Type | Returns |
|---|---|---|
sources | query | Every registered source (meta, suggested queries). |
query | query | Runs a jora query; normalized result with stats. |
queryPath | query | Depth-limited subtree slice (lazy expansion). |
skeleton | query | A source's type skeleton, honoring filters. |
suggest | query | Autocomplete candidates at the cursor. |
saved:list / saved:save / saved:delete | query / action | Saved-query recipes (workspace, project). |