Skip to content

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

Data Inspector screenshot
Query workbench with results and data shape panel
Data Inspector screenshot
Query data with advanced Jora syntax

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.

ts
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 ​

sh
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:

ts
// 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 ​

ts
import { createDataInspectorDevframe } from '@devframes/plugin-data-inspector'

export default createDataInspectorDevframe({
  exampleSource: false,
})

Attach to another Node process ​

The target starts the agent:

ts
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:

sh
DEVFRAME_DATA_INSPECTOR=1 node --import @devframes/plugin-data-inspector/inject server.js

This auto-registers a globalThis source:

ts
// somewhere in the running process
globalThis.store = store
globalThis.cache = cache

It 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:*:

FunctionTypeReturns
sourcesqueryEvery registered source (meta, suggested queries).
queryqueryRuns a jora query; normalized result with stats.
queryPathqueryDepth-limited subtree slice (lazy expansion).
skeletonqueryA source's type skeleton, honoring filters.
suggestqueryAutocomplete candidates at the cursor.
saved:list / saved:save / saved:deletequery / actionSaved-query recipes (workspace, project).

Source ​

plugins/data-inspector

Released under the MIT License.