Developer inspector

The developer inspector attaches Chrome DevTools to a running DataMind Oda app, so you can debug the app's host process and its connected browser clients from one DevTools window. It is development tooling for a checkout, not part of the everyday app: it joins one run through an overlay file and listens on this computer only.

Turn the inspector on

  1. Build the project first: pnpm run build. The overlay loads the inspector from the build output; Building and shipping Oda covers building and running from source.
  2. Start the web mode with the overlay: oda --profile web --patch ./packages/experimental/inspector/cordis.patch.yml
  3. Open the devtools:// address the app logs once the inspector listens. Chrome DevTools attaches to the run from there.

In a source checkout, pnpm run demo:inspector starts the same web mode and loads the inspector from source instead of the build output.

Nothing is installed into your profile: a run started without the overlay has no inspector, and when the run stops, the inspector goes with it.

What it serves

Once it listens, the inspector serves these addresses on one local port:

AddressWhat it answers
/json, /json/listThe DevTools discovery documents.
/json/versionThe version document for the protocol.
/devtools/page/<id>The target socket DevTools attaches to.
/ingestThe socket a browser client connects to as a source.

What you can inspect

A connected client advertises runtime, console and sources, with its sources read-only; its capability list leaves out the debugger and the heap profiler.

Fields and defaults

The inspector's fields live in its entry in the overlay you run. Set one there when a default does not fit:

FieldDefaultMeaning
host127.0.0.1The bind address; only a loopback address is accepted.
port9230The first port tried; a busy port advances upward, and 0 asks the system for one.
clientOriginsemptyExtra browser origins accepted by the ingest endpoint.
captureFetchonRecord the host's fetch calls.
maxRequestBodyBytes8 MiBRequest-body prefix kept per request.
maxResponseBodyBytes32 MiBResponse-body prefix kept per request.
maxBodyChunkBytes48 KiBRaw bytes carried in one body record.
maxJournalBytes256 MiBTotal body bytes kept.
maxRetainedRequests2000Requests kept.
maxSourceFrameBytes128 KiBLargest encoded source frame.
startupTimeoutMs10 sHow long startup waits for readiness.
stopTimeoutMs5 sThe window for a graceful stop.
clientReconnectBaseMs250 msStarting client reconnect backoff.
clientReconnectMaxMs5 sLargest client reconnect backoff.
clientRuntimeTimeoutMs30 sDeadline for one runtime or sources command sent to a client.
queryTimeoutMs10 sDeadline for one non-DevTools query.

The same entry holds a few further bounds: maxSourceRecordsPerFrame 128, maxQueuedRecords 2048, maxQueuedBytes 16 MiB, maxClientRuntimeObjects 10000, maxClientRuntimeProperties 2000, maxClientSourceBytes 8 MiB, maxCordisNodes 2048 and maxDisconnectedCordisTrees 8.

Keep it safe

Warning

While the inspector runs, anything attached to its DevTools socket can run code in the host and in any connected browser client. Stop the run when you are done.

The worker and the bridge

Messages you may see

Questions, answered

Can I add my own data to the inspector?

Yes. A plugin publishes snapshots with ctx.inspector.publish(topic, payload), and a script can read the detached tree with ctx.inspector.cordis.getTree(). Neither call needs a DevTools window.

How does the inspector see the app's state?

Through snapshots, never through live objects. The app's parts project validated snapshots into the worker, and DevTools works from those snapshots.

Why does client evaluation fail on some pages?

A client page's content security policy can refuse dynamic evaluation, and a client context has no DevTools command-line helpers. What a client offers is its console entries, evaluation and read-only sources.

Does network capture slow the app down?

It can. Full capture copies request and response streams, so a busy run adds memory and I/O pressure, and the retained-byte limit does not cover the buffering inside the stream copy.

Can I turn network capture off?

Yes. Set captureFetch to off in the overlay entry. Capture is on by default.

Are observations lost while a client reconnects?

No. The client keeps its buffered observations across a reconnect and sends them when it joins again, in bounded frames and queues. Its console entries flow only while its connection is open.

Can I debug several browser clients at once?

Yes. Every connected client joins as its own <client> entry, console entries merge from the host and from all of them, and evaluation goes to the client you select. A client keeps its identity across refreshes and reconnects, while a duplicated live tab gets a new one; a browser without Web Locks support cannot tell two live copies apart.

What does [inspector] Client source rejected: <message> mean?

The inspector refused a browser client as a source, and the carried message says why. The client closes that connection and retries with backoff, from 250 ms up to 5 s by default.

How much captured traffic does the inspector keep?

It is bounded: up to maxRetainedRequests requests, 2000 by default, and maxJournalBytes of body bytes, 256 MiB by default, with each body kept as a prefix of its own caps. Raise the fields in the overlay when a run needs more.

What does Inspector Client query socket is not connected mean?

A query reached the client while its socket was between connections, for example during a reconnect. The query is refused rather than queued, so wait for the connection and try again.