Skip to main content
GitHub

JS Context

Trace context propagation in JavaScript/TypeScript.

The JavaScript SDK uses AsyncLocalStorage for automatic context propagation across async operations.

Getting Context

getCurrentContext()

Get the current context state:

import { getCurrentContext } from 'risicare';
 
const context = getCurrentContext();
if (context) {
  console.log('Session:', context.session);
  console.log('Agent:', context.agent);
  console.log('Span:', context.span);
  console.log('Phase:', context.phase);
}

The context object contains nested objects:

interface ContextState {
  session?: { sessionId: string; userId?: string };
  agent?: { name: string; role?: string; agentId?: string };
  span?: Span;
  phase?: SemanticPhase;
}

Individual Getters

import {
  getCurrentTraceId,
  getCurrentSpanId,
  getCurrentAgentId,
  getCurrentSessionId,
} from 'risicare';
 
const traceId = getCurrentTraceId();
const spanId = getCurrentSpanId();
const agentId = getCurrentAgentId();
const sessionId = getCurrentSessionId();

W3C Trace Context

Propagate context across service boundaries using W3C headers:

Inject Context

import { injectTraceContext } from 'risicare';
 
// Inject into HTTP headers
const headers: Record<string, string> = {};
injectTraceContext(headers);
 
// Now headers contains:
// {
//   'traceparent': '00-abc123...-def456...-01',
//   'tracestate': 'risicare=...'
// }
 
await fetch('https://api.example.com', { headers });

Extract Context

import { extractTraceContext, runWithContext } from 'risicare';
 
// In your HTTP handler
app.post('/api/endpoint', async (req, res) => {
  const context = extractTraceContext(req.headers);
 
  if (context) {
    await runWithContext({ span: context }, async () => {
      // All spans created here are linked to the extracted context
      await processRequest(req.body);
    });
  }
 
  res.json({ success: true });
});

Manual Context Management

runWithContext()

Run code within a specific context override:

import { runWithContext } from 'risicare';
 
await runWithContext(
  {
    session: { sessionId: 'sess-123', userId: 'user-456' },
    agent: { name: 'my-agent', role: 'worker' },
  },
  async () => {
    // Code runs with this context
    await doWork();
  }
);

The first parameter is a Partial<ContextState> — you only need to specify the fields you want to override.

Span Registry

Access spans by ID for use in async generators and streaming:

import {
  registerSpan,
  getSpanById,
  unregisterSpan,
} from 'risicare';
 
// Register a span for later lookup by ID
registerSpan(span, 30000); // optional TTL in ms
 
// Get span by its ID
const span = getSpanById('abc123def456');
 
// Clean up when done
unregisterSpan('abc123def456');

When to Use the Span Registry

The span registry is designed for async generators and streaming scenarios where contextvars context may be lost after yield. Store the span ID before yielding, then retrieve it by ID in subsequent iterations.

Cross-Process Propagation

HTTP Client

import { injectTraceContext } from 'risicare';
 
async function fetchWithTracing(url: string, options: RequestInit = {}) {
  const headers = new Headers(options.headers);
 
  // Inject trace context
  const traceHeaders: Record<string, string> = {};
  injectTraceContext(traceHeaders);
 
  Object.entries(traceHeaders).forEach(([key, value]) => {
    headers.set(key, value);
  });
 
  return fetch(url, { ...options, headers });
}

Message Queues

import { injectTraceContext, extractTraceContext, runWithContext } from 'risicare';
 
// Producer
async function publishMessage(queue: Queue, payload: unknown) {
  const headers: Record<string, string> = {};
  injectTraceContext(headers);
 
  await queue.publish({
    payload,
    headers,
  });
}
 
// Consumer
async function handleMessage(message: Message) {
  const context = extractTraceContext(message.headers);
 
  if (context) {
    await runWithContext({ span: context }, async () => {
      await processMessage(message.payload);
    });
  }
}

Next Steps