@somnia-chain/markets-sdk


@somnia-chain/markets-sdk / index / DebugEvent

Type Alias: DebugEvent

DebugEvent = { kind: "log"; level: "debug" | "warn"; scope: string; message: string; data?: Record<string, unknown>; } | { kind: "span"; phase: "start"; id: number; parentId?: number; name: string; data?: Record<string, unknown>; } | { kind: "span"; phase: "annotate"; id: number; name: string; data: Record<string, unknown>; } | { kind: "span"; phase: "end"; id: number; name: string; durationMs: number; error?: unknown; }

Defined in: packages/sdk/src/debug.ts:58

One event on the client's opt-in debug channel — either a structured log line or one phase of a span. Wire a sink with ClientConfig.debug and every event the client produces flows through it.

Details

Events are data, not display strings: data carries raw values (counts, addresses, bigints) and rendering/filtering is entirely the sink's job — see consoleDebugSink for a ready-made renderer and debugCollector for test capture. A span arrives as a start/end pair sharing an id (unique within one client instance), with any number of annotate events in between attaching data to the still-open span.

The shape maps 1:1 onto OpenTelemetry, so a real tracer is just another sink: name ↔ span name, data ↔ attributes, error ↔ span status / recorded exception, annotatesetAttribute, parentId ↔ context link.

Gotchas

Parenting is EXPLICIT — a span event carries parentId only when the call site passed the parent handle — so interleaved events from concurrent operations always attribute correctly; never infer nesting from event order.

Union Members

Type Literal

{ kind: "log"; level: "debug" | "warn"; scope: string; message: string; data?: Record<string, unknown>; }

kind

kind: "log"

level

level: "debug" | "warn"

"warn" for conditions worth surfacing (a failed watch); "debug" for tracing.

scope

scope: string

Emitting module, e.g. "liveTail" — filter on it in the sink.

message

message: string

Stable, human-readable event description, e.g. "applying logs".

data?

optional data?: Record<string, unknown>

Raw values for the sink to render (counts, block numbers, addresses, bigints).


Type Literal

{ kind: "span"; phase: "start"; id: number; parentId?: number; name: string; data?: Record<string, unknown>; }

kind

kind: "span"

phase

phase: "start"

id

id: number

Span id — matches the annotate/end events of the same span. Unique per client.

parentId?

optional parentId?: number

The enclosing span's id; absent on a root span. Only ever set explicitly.

name

name: string

Span name, "<module>.<fn>" — e.g. "trade.execute", "trader.placeOrder".

data?

optional data?: Record<string, unknown>

The operation's input, as raw values (a trader call's params object, …).


Type Literal

{ kind: "span"; phase: "annotate"; id: number; name: string; data: Record<string, unknown>; }

kind

kind: "span"

phase

phase: "annotate"

id

id: number

The still-open span this data belongs to.

name

name: string

The annotated span's name (so sinks need no id → name lookup).

data

data: Record<string, unknown>

Values that only exist mid-span — e.g. the tx hash once broadcast returns.


Type Literal

{ kind: "span"; phase: "end"; id: number; name: string; durationMs: number; error?: unknown; }

kind

kind: "span"

phase

phase: "end"

id

id: number

Matches the span's start event.

name

name: string

Same name as the start event.

durationMs

durationMs: number

Wall-clock start-to-settle: for an async span, until the promise settles.

error?

optional error?: unknown

The thrown value / rejection reason when the span failed; absent on success.

Example

A minimal custom sink — narrow on kind/phase and the union does the rest:

ts
const sink = (e: DebugEvent): void => {
  if (e.kind === "log") console.log(e.scope, e.message, e.data);
  else if (e.phase === "end" && e.error !== undefined) console.error(e.name, e.error);
  else if (e.phase === "end" && e.durationMs > 500) console.log("slow:", e.name, e.durationMs);
};
const exchange = new SomniaMarkets({ ...config, debug: sink });