DevPul Open DevPul

Event contract

Everything DevPul shows arrives as dart:developer postEvent calls on the VM service Extension stream. Any tool that reads that stream can use the same events, and any code that posts them shows up in DevPul.

Envelope

Kinds are posted as devpul.<kind>. Every event carries:

Field
v Schema version, 1.
session Random per isolate; stable across hot reload, new on hot restart.
seq Increments per isolate. With session, it identifies the event, so replays de-duplicate.
ts Milliseconds since the epoch.
tags Devpul.tags when set, string to string.

The VM adds the isolate and isolate group. The UI groups events into runs by isolate group (by session on the web).

Fields longer than maxValueLength are replaced by a marker:

{"devpul.truncated": {"size": 2400000, "preview": "{\"items\": [..."}}

Kinds

Kind Fields
http.request id, method, url, params, headers, body, curl
http.response id, method, url, status, statusMessage, finalUrl, durationMs, headers, body
http.error id, method, url, status, errorType, message, durationMs, headers, body
app.session free-form
app.actions actions: names, in registration order
error source, type, message, library, context, information, silent, stack
log level, message, name, error, stack
route action (push, pop, replace, remove), route, previous, arguments
anything else custom, shown in Events or a plugin tab

HTTP events pair on session + id. A response may arrive before its request; the UI pairs them either way. finalUrl is present only when a redirect ended somewhere else.

Service extensions

Each isolate that emits registers:

Method Params Returns
ext.devpul.backlog none {"events": [{"kind": "devpul.http.request", "data": {...}}, ...]}: recent events up to backlogSize, plus the latest session and actions.
ext.devpul.action name {"result": ...} from the action, or an extension error with the exception text. Registered with the first Devpul.action.

The UI calls ext.devpul.backlog on connect and whenever an isolate registers it, because DDS keeps only the last 10,000 Extension events, shared with Flutter's per-frame events.

Versioning

New fields and kinds can appear without a version change; readers ignore what they do not know. v changes only when an existing field changes meaning.