# @devframes/plugin-data-inspector

> Devframe plugin for inspecting live server objects interactively with jora queries.

Latest version **0.9.18** (published 2026-09-10) · MIT license · 0 weekly downloads

## Install

```sh
npm install @devframes/plugin-data-inspector
pnpm add @devframes/plugin-data-inspector
yarn add @devframes/plugin-data-inspector
bun add @devframes/plugin-data-inspector
```

Provides the command `devframe-data-inspector`.

## Health

**Score 75/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; has provenance; recently updated; high maintenance score; high quality score.

Warnings: low downloads; pre 1.0.

## Facts

| | |
|---|---|
| Version | 0.9.18 |
| Published | 2026-09-10 |
| First published | 2026-07-17 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM |
| Dependencies | 1 |
| Unpacked size | 291.7 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 177 |
| Author | Anthony Fu <anthonyfu117@hotmail.com> |
| Maintainers | antfu |
| Keywords | devframe, devframe-plugin, devtools, jora, data-inspector |

## Links

- npm: https://www.npmjs.com/package/@devframes/plugin-data-inspector
- Repository: https://github.com/devframes/devframe
- Homepage: https://github.com/devframes/devframe#readme
- Issues: https://github.com/devframes/devframe/issues
- npm.io page: https://npm.io/package/@devframes/plugin-data-inspector

## Dependencies (1)

- [cac](https://npm.io/package/cac.md) ^7.0.0

## Alternatives

- [localforage](https://npm.io/package/localforage.md) — 6.2M weekly downloads
- [localforage-observable](https://npm.io/package/localforage-observable.md) — 30.8K weekly downloads
- [@y/y](https://npm.io/package/@y/y.md) — 30.1K weekly downloads
- [@metaobjectsdev/render](https://npm.io/package/@metaobjectsdev/render.md) — 3.5K weekly downloads
- [@ledgerhq/coin-algorand](https://npm.io/package/@ledgerhq/coin-algorand.md) — 1.1K weekly downloads

## Recent versions

- 0.9.18 (latest) — 2026-09-10
- 0.9.17 — 2026-09-09
- 0.9.16 — 2026-09-08
- 0.9.15 — 2026-09-08
- 0.9.12 — 2026-09-04
- 0.9.11 — 2026-09-04
- 0.9.10 — 2026-09-03
- 0.9.9 — 2026-09-03
- 0.9.8 — 2026-09-01
- 0.9.7 — 2026-08-27
- 0.9.6 — 2026-08-27
- 0.9.5 — 2026-08-21
- 0.9.4 — 2026-08-20
- 0.9.3 — 2026-08-19
- 0.9.2 — 2026-08-19
- … 26 more at https://npm.io/package/@devframes/plugin-data-inspector/versions

## README

# @devframes/plugin-data-inspector

Inspect live server-side objects interactively. Other devframes and host frameworks register **data sources**; the workbench composes [jora](https://github.com/discoveryjs/jora) queries against them (executed in the process that owns the objects) and renders normalized results in a [discovery.js](https://github.com/discoveryjs/discovery) struct view with type badges, a shape panel, saved queries, and shareable URL state. Deep graphs expand a level at a time (`load deeper` fetches each subtree on demand), an optional poller re-runs the query every N seconds, and a toolbar offers expand/collapse-all and copy.

## Register a data source

The registry is **process-global**: register from anywhere, before or after the devframe mounts:

```ts
import { registerDataSource } from '@devframes/plugin-data-inspector/registry'

registerDataSource({
  id: 'my-plugin:state',
  title: 'My plugin state',
  description: 'The live state store',
  data: () => store, // value or (async) factory; `static: true` memoizes
  queries: [{ title: 'Active entries', query: 'entries.mapEntries()' }],
})
```

Devframes that prefer zero package dependency consume the same store through the typed context service:

```ts
ctx.services.whenAvailable('devframes:plugin:data-inspector:sources', (sources) => {
  sources.register({ id: 'my-plugin:state', title: 'My state', data: () => store })
})
```

## Writable sources

Sources opt into live edits with `writable: true`: on the root view (`$`), every value grows an edit affordance that opens a side panel where you set a value (string / number / boolean / null / undefined / JSON), add or delete entries, or rename keys; the mutation is applied **in place to the live object** through the `write` RPC. Read-only stays the default; `static: true` sources are memoized snapshots and always stay read-only (declaring both reports `DP_DATA_INSPECTOR_0004`).

`registerDataSource` returns a handle; call `notifyChanged()` whenever the data changes outside the inspector so connected views re-run, or hand the devframe a bridge to the source's own change signal via `subscribe`:

```ts
const handle = registerDataSource({
  id: 'my-plugin:state',
  title: 'My plugin state',
  data: () => store,
  writable: true, // opt-in: the inspector may mutate the live object
  subscribe: (notify) => { // optional: push the source's own change signal
    store.on('change', notify)
    return () => store.off('change', notify)
  },
})

handle.notifyChanged() // or notify imperatively
```

## Mount

```ts
// the default export is the factory; call it for an instance:
import createDataInspectorDevframe from '@devframes/plugin-data-inspector'
// Vite
import { devframeVite } from '@devframes/vite/single'

devframeVite(createDataInspectorDevframe())
```

## Standalone CLI

```sh
pnpx @devframes/plugin-data-inspector stats.json trace.jsonl # inspect local data files
pnpx @devframes/plugin-data-inspector build stats.json       # self-contained static export
pnpx @devframes/plugin-data-inspector attach                 # attach to a process running the inject entry
```

Static exports embed the dataset and run the same query engine client-side, so saved recipes stay portable.

## Attach to another Node process

```ts
import { exposeDataInspector } from '@devframes/plugin-data-inspector/inject'

// pass sources inline, or register them separately beforehand
await exposeDataInspector({
  sources: [{ id: 'app:store', title: 'App store', data: () => store }],
})
```

or with zero code changes:

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

On the zero-code path there's nowhere to call `registerDataSource`, so the inject entry auto-registers a **`globalThis`** source: assign what you want to inspect onto the global object (`globalThis.store = store`) and query it live. Opt out with `DEVFRAME_DATA_INSPECTOR_GLOBAL=0`.

The inject entry binds `127.0.0.1`, requires devframe's trust handshake with a per-run token by default, and advertises its endpoint in `node_modules/.data-inspector/discovery.json`, which `pnpx @devframes/plugin-data-inspector attach` picks up automatically.

> [!WARNING]
> A connected inspector runs eval-grade jora queries against live objects: queries can invoke functions reachable as own properties and fire getters. Treat the inject endpoint like a debugger port: keep it on loopback and keep auth on.

## Saved queries

Recipes (`{ query, title?, description?, ...filters }`) persist id-keyed in two scopes: **workspace** (committable, `getStorageDir('workspace')/data-inspector/queries.json`, shared with the team) and **project** (per-checkout, under `node_modules`).

---
_Source: https://npm.io/package/@devframes/plugin-data-inspector · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
