Skip to content

API

@ogygia/devtools

The in-page dock.

On this page

This page is generated from the package’s own .d.ts files on every build, so the signatures, descriptions and examples below always match the source.

import { … } from '@ogygia/devtools';

Exports add_sink · clear · configure · emit · ingest · ingest_server_events · install_console_sink · install_devtools_ui · install_postmessage_sink · install_window_sink · snapshot · to_trace · DEVTOOLS · DEVTOOLS_SCHEMA_VERSION · DevtoolsEnvelope · DevtoolsTrace · DevtoolsWindowHook · CompileEventInput · DevtoolsDomain · DevtoolsEvent · DevtoolsEventInput · DevtoolsSink · HubEventInput · NavEventInput · RuntimeEventInput · ServerEventInput · WireEventInput

add_sink

function

Register a sink; returns an unregister fn. A sink sees events from registration onward — to also replay what's buffered, iterate snapshot first.

function add_sink(sink: DevtoolsSink): () => void;

clear

function

Drop every buffered event (the sinks are left registered). Used between e2e scenarios + traces.

function clear(): void;

configure

function

Runtime configuration — pause/resume, resize the ring, set per-name sampling.

function configure(opts: {
  active?: boolean;
  cap?: number;
  sample?: Record<string, number>;
}): void;

emit

function

THE emit entry point. Stamps the envelope (v / seq / t / realm), rings the buffer, fans to sinks. A no-op when the bus is inactive. Guard the CALL with a module-local if (DEVTOOLS) so the event literal compiles out entirely when off — this internal guard only protects direct/dynamic callers.

function emit(input: DevtoolsEventInput): void;

ingest

function

Push ALREADY-STAMPED events into the buffer + sinks WITHOUT re-stamping — the ingest path for the server realm's events, which arrive from the application/ogygia-devtools side-channel carrying their own envelope (v / seq / t / realm:'server'). This is what unifies the server render stream and the client wake stream into ONE window.__ogygia_devtools timeline, correlated by fingerprint.

function ingest(events: DevtoolsEvent[]): void;

ingest_server_events

function

Read the server realm's <script type="application/ogygia-devtools"> side-channel (injected by the handle on a devtools build) and INGEST its events into the unified stream, so a region's server render sits in the same window.__ogygia_devtools timeline as its client wake — correlated by fingerprint. Idempotent per document via a marker attribute; no-op off the browser or when the script is absent. Returns how many server events were ingested.

function ingest_server_events(): number;

install_console_sink

function

Log every event to the console (debugging). filter limits by domain/name substring.

function install_console_sink(filter?: (event: DevtoolsEvent) => boolean): () => void;

install_devtools_ui

function

function install_devtools_ui(opts?: {
  csr_true?: boolean;
}): void;

install_postmessage_sink

function

Forward every event to a postMessage target (the REPL's tab ↔ worker ↔ iframe channel). Pass a Worker / MessagePort / Window; each event is posted as { __ogygia_devtools: event }. Returns the unregister fn.

function install_postmessage_sink(target: {
  postMessage: (message: unknown) => void;
}): () => void;

install_window_sink

function

Publish window.__ogygia_devtools so an out-of-page reader (Playwright, a devtools panel, a REPL host) can pull buffered events, subscribe to new ones, and drain a trace — WITHOUT importing any framework module. Idempotent. No-op off the browser. Returns the hook (or undefined on the server).

This is what lets our e2e assert on the ISLAND LIFECYCLE directly ("interaction island fired its wake, replayed exactly one click") instead of polling the DOM behind a waitForTimeout — the bus pays for itself in our own tests first (the note's proof-of-value).

function install_window_sink(): DevtoolsWindowHook | undefined;

snapshot

function

Buffered events in emission order (oldest → newest). Copies out — safe to hold/serialize.

function snapshot(): DevtoolsEvent[];

to_trace

function

Serialize the current buffer into a DevtoolsTrace.

function to_trace(): DevtoolsTrace;

DEVTOOLS

const

Compile-time gate (Vite define). Exported for the public surface + tests; seam modules declare their OWN local const DEVTOOLS from the same token so DCE never depends on cross-module folding.

const DEVTOOLS: boolean

DEVTOOLS_SCHEMA_VERSION

const

Bump only on a breaking shape change; a trace stamps this so a reader can gate on it.

const DEVTOOLS_SCHEMA_VERSION = 1

DevtoolsEnvelope

interface

Fields the bus stamps on EVERY event — the caller never sets these.

interface DevtoolsEnvelope {/*…*/}

DevtoolsEnvelope.v

Schema version (DEVTOOLS_SCHEMA_VERSION) — copied onto every event for trace gating.

v: number;

DevtoolsEnvelope.seq

Monotonic per-session sequence number (ordering that survives equal timestamps).

seq: number;

DevtoolsEnvelope.t

Timestamp: performance.now() (ms, sub-ms precision) when available, else Date.now().

t: number;

DevtoolsEnvelope.realm

Which realm emitted it — a trace merges client + server streams, so it must be labelled.

realm: "client" | "server";

DevtoolsTrace

interface

A portable trace — a versioned bag of events, attachable to a bug report and replayable in the REPL later (the note's "CPU-profile energy, but for the islands lifecycle").

interface DevtoolsTrace {/*…*/}

DevtoolsTrace.kind

Marker so a consumer knows what it's holding.

kind: "ogygia-devtools-trace";

DevtoolsTrace.version

{@link DEVTOOLS_SCHEMA_VERSION }.

version: number;

DevtoolsTrace.events

Events in emission order.

events: DevtoolsEvent[];

DevtoolsWindowHook

interface

Shape of window.__ogygia_devtools (the e2e / instrument entry point).

interface DevtoolsWindowHook {/*…*/}

DevtoolsWindowHook.version

Schema version, so a reader can gate.

version: number;

DevtoolsWindowHook.events

Every buffered event, oldest → newest (a fresh copy each call).

events(): DevtoolsEvent[];

DevtoolsWindowHook.on

Subscribe to events from now on; returns an unsubscribe fn.

on(cb: (event: DevtoolsEvent) => void): () => void;

DevtoolsWindowHook.clear

Drop the buffer (between e2e scenarios).

clear(): void;

DevtoolsWindowHook.trace

Serialize the buffer to a portable trace.

trace(): DevtoolsTrace;

CompileEventInput

type

type CompileEventInput = {
  domain: "compile";
  name: "compile.island.discovered";
  iid: string;
  entry?: string;
  strategy: string;
  csr: boolean;
} | {
  domain: "compile";
  name: "compile.chunk.emitted";
  entry: string;
  bytes: number;
};

DevtoolsDomain

type

The six event domains (note's Schema-v1 table).

type DevtoolsDomain = "compile" | "server" | "wire" | "runtime" | "hub" | "nav";

DevtoolsEvent

type

A fully-stamped event as it sits in the ring buffer / trace / on a sink.

type DevtoolsEvent = DevtoolsEventInput & DevtoolsEnvelope;

DevtoolsEventInput

type

What a call site passes to emit — the envelope is added by the bus.

type DevtoolsEventInput = CompileEventInput | ServerEventInput | WireEventInput | RuntimeEventInput | HubEventInput | NavEventInput;

DevtoolsSink

type

A sink is any consumer of stamped events. Throwing is contained — one bad sink never starves the others, and never breaks the framework path that emitted the event.

type DevtoolsSink = (event: DevtoolsEvent) => void;

HubEventInput

type

type HubEventInput = {
  domain: "hub";
  name: "hub.mint";
  kind: string;
  id: string;
  tag?: string;
} | {
  domain: "hub";
  name: "hub.resolve";
  kind: string;
  id: string;
  scope: string;
  tag?: string;
  hit: boolean;
} | {
  domain: "hub";
  name: "hub.dispose";
  scope: string;
  count: number;
};

type

RuntimeEventInput

type

type RuntimeEventInput = {
  domain: "runtime";
  name: "runtime.boot";
  features: string[];
} | {
  domain: "runtime";
  name: "region.connected";
  entry?: string;
  fp?: string;
  wake?: string;
  deferred: boolean;
  nested: boolean;
} | {
  domain: "runtime";
  name: "wake.scheduled";
  entry?: string;
  fp?: string;
  when: string;
} | {
  domain: "runtime";
  name: "wake.fired";
  entry?: string;
  fp?: string;
  when: string;
} | {
  domain: "runtime";
  name: "region.prefetch";
  entry?: string;
  fp?: string;
} | {
  domain: "runtime";
  name: "region.hydrate.start";
  entry?: string;
  fp?: string;
} | {
  domain: "runtime";
  name: "region.hydrate.done";
  entry?: string;
  fp?: string;
  ms: number;
} | {
  domain: "runtime";
  name: "region.hydrate.failed";
  entry?: string;
  fp?: string;
  message: string;
} | {
  domain: "runtime";
  name: "region.hydrate.recovered";
  entry?: string;
  fp?: string;
  reason?: string;
} | {
  domain: "runtime";
  name: "region.hydrate.healed";
  entry?: string;
  fp?: string;
  reason?: string;
} | {
  domain: "runtime";
  name: "load.started";
  class: "user" | "visible" | "ahead" | "speculative";
  kind: "code" | "content";
  label?: string;
  waited_ms: number;
} | {
  domain: "runtime";
  name: "load.critical";
  outcome: "arrived" | "input" | "cap" | "none";
  resources: number;
  waited_ms: number;
} | {
  domain: "runtime";
  name: "region.hydrate.conflict";
  entry?: string;
  fp?: string;
  reason?: string;
} | {
  domain: "runtime";
  name: "svelte.hydration.warning";
  code: string;
  message: string;
  file?: string;
  fp?: string;
} | {
  domain: "runtime";
  name: "region.server.applied";
  entry?: string;
  endpoint?: string;
  bytes: number;
  revalidate: boolean;
  wait_ms?: number;
} | {
  domain: "runtime";
  name: "region.batch.sent";
  batch: number;
  kind: "page" | "nav";
  endpoints: string[];
} | {
  domain: "runtime";
  name: "region.batch.part";
  batch: number;
  endpoint: string;
} | {
  domain: "runtime";
  name: "region.batch.done";
  batch: number;
  sent: number;
  delivered: number;
  status: number;
  refused?: "redirected" | "document";
  final_url?: string;
} | {
  domain: "runtime";
  name: "region.server.failed";
  entry?: string;
  endpoint?: string;
  reason: "redirected" | "document" | "forbidden" | "error";
  final_url?: string;
  message?: string;
  attempt: number;
  final: boolean;
} | {
  domain: "runtime";
  name: "entry.fallback";
  entry: string;
  src: string;
  recovered: boolean;
} | {
  domain: "runtime";
  name: "interaction.replay";
  entry?: string;
  fp?: string;
  clicks: number;
  fields: number;
};

ServerEventInput

type

type ServerEventInput = {
  domain: "server";
  name: "server.region.rendered";
  fp: string;
  mode: string;
  entry?: string;
  htmlBytes?: number;
  propsBytes?: number;
  ms?: number;
} | {
  domain: "server";
  name: "server.capability.minted";
  id: string;
  ttl?: number;
} | {
  domain: "server";
  name: "server.delta.skip";
  fp: string;
} | {
  domain: "server";
  name: "server.seed.injected";
  kind: "page" | "remote";
  bytes: number;
} | {
  domain: "server";
  name: "server.postrender";
  op: string;
  url?: string;
  reason?: string;
  bytes?: number;
};

WireEventInput

type

type WireEventInput = {
  domain: "wire";
  name: "wire.props";
  entry?: string;
  bytes: number;
} | {
  domain: "wire";
  name: "wire.context";
  bytes: number;
} | {
  domain: "wire";
  name: "wire.frame.batch";
  count: number;
  bytes?: number;
} | {
  domain: "wire";
  name: "wire.known.sent";
  count: number;
  bytes: number;
};