Most applications should use the server adapter. Reach for JevRecorder when implementing your own transport or viewer integration.
JevRecorder#
import { TypeSafeClient } from "@typesafe-ai/sdk";
import { JevRecorder } from "jev-devtools/server";
export const recorder = new JevRecorder({ limit: 50 });
export const client = recorder.instrument(
new TypeSafeClient({
apiKey: process.env.TYPESAFE_API_KEY,
fetch: recorder.transport(globalThis.fetch),
}),
{ session: "local", label: "My request", source: "live" },
);
export const unsubscribe = recorder.subscribe((sessions) => {
if (sessions.has("local")) {
console.log(recorder.snapshot("local"));
}
});
// Call unsubscribe() when the subscriber is no longer needed.Create a lower-level in-memory request recorder for a custom integration.
new JevRecorder(options?)- limit
- Maximum retained request traces across sessions. Defaults to 50; clamped to 1–200.
- redact
- Transform the captured copy before storage or streaming. Does not change SDK inputs or application values.
Maximum retained request traces across sessions. Defaults to 50; clamped to 1–200.
limitWrap a TypeSafe client to record its systemOne calls. Pair with recorder.transport() to capture request transport details.
recorder.instrument(client, metadata)- session
- The recording scope for this request.
- label
- A human-readable request label.
- source
- Label the capture as sample or live; does not change the underlying transport.
Wrap a fetch implementation to observe request transport details. Pass the wrapper to the SDK client's fetch option.
recorder.transport(fetcher)The recording scope for this request.
sessionA human-readable request label.
labelLabel the capture as sample or live; does not change the underlying transport.
sourceListen for changed session IDs. Returns an unsubscribe function; call it when the listener is no longer needed.
recorder.subscribe(listener)Read a cloned snapshot of retained traces for one session, newest first. Changing the snapshot does not change recorder history.
recorder.snapshot(session)API reference: JevRecorder · recorder.instrument() · recorder.transport() · recorder.subscribe() · recorder.snapshot()
Example walkthrough: the recorder retains up to 50 traces. transport() observes HTTP attempts, while instrument() observes logical systemOne calls and assigns their session and label. The subscriber filters notifications to the local session, then reads a detached snapshot. Call unsubscribe() during cleanup.
instrument observes logical calls; transport observes HTTP attempts. Pair them to preserve both views. The instrumented proxy preserves the original SDK promise and response helpers. This example needs a real key when you call client.systemOne().
Recorder methods#
| Method | Return type | Purpose |
|---|---|---|
new JevRecorder(options?) |
JevRecorder |
Create bounded history with limit and redact. |
transport(fetcher) |
Fetch |
Wrap a compatible fetch implementation to capture attempts. |
instrument(client, metadata) |
T (the original client type) |
Return an instrumented client. Metadata is { session, label, source } or a factory returning that object. |
snapshot(session) |
Trace[] |
Return detached traces, newest first, for one session. |
changes(session, after?) |
{ revision: number; order: string[]; upserts: Trace[] } |
Return { revision, order, upserts } for incremental viewers. Omit the cursor for a full initial view. |
subscribe(listener) |
() => void |
Receive affected session sets; returns an unsubscribe function. |
clear(session) |
void |
Remove retained traces for that session. |
withFlow(link, onTrace, callback) |
T (the callback result) |
Link a request to { runId, stepId, executionId } while calling through. Normally used by the adapter's flow observer. |
The retention limit is global to the recorder, not a per-session allocation. Snapshots are captured inspection copies, not complete original SDK objects.
Custom flow observers#
FlowObserver is exported from jev-devtools/flow. Its startFlow(definition, run) can return { update(run), request(link, onTrace, callback) } or undefined. Recording is optional; the flow runner owns execution results.
The request hook should call through synchronously to preserve request linkage. Avoid using observer callbacks for application actions. In the working tree, observer snapshots are detached from execution state and failures are contained; see the changelog for these unreleased robustness changes.
Public type map#
| Import | Types |
|---|---|
jev-devtools |
JevDevtoolsProps, Trace, Snapshot, StreamSnapshot, TraceDelta, Json, AnswerView, QuestionView |
jev-devtools/server |
JevDevtoolsServerOptions, CaptureOptions, ClientMetadata |
jev-devtools/flow |
FlowBuilder, FlowExpression, FlowOutcome, FlowRunOptions, FlowTask, FlowRequestFactory, TaskContext, Resolved, FlowObserver, FlowDisplay, FlowDefinition, FlowRun, FlowStep |
Use import type for data-only contracts. /server and /flow runtime imports belong on Node. Root protocol types are browser-safe.
Version-matched declarations#
The installed package's lib/src/index.d.ts, lib/server/index.d.ts, and lib/flow/index.d.ts are the precise contracts for that version. The API glossary includes exact public declarations and their supporting shapes. Additional stream semantics are documented in the stream protocol and installed declarations.
Replay types (unreleased)#
FlowFixture and BuiltFlowFixture are also exported from the root and /flow entries. The browser-safe flowFixture() helper builds an export from captured data; Node-only replayClient() uses it to supply stored answers to a flow. See replay reference.