Context Propagation

Request/trace correlation across async boundaries.

Context propagation ensures that all enforcement calls, traces, and spans are correctly correlated within a single request or user session.

Why Context Matters

Without proper context, you lose:

  • Trace continuity: Spans from the same request appear disconnected.
  • Audit correlation: Cannot link enforcement decisions back to the originating request.
  • User attribution: Cannot filter logs by user_id or org_id.

Context Fields

Field Description Example
requestId Unique ID for the current request req_abc123
traceId ID for the distributed trace trace_xyz789
orgId Organization/tenant identifier org_acme
userId End-user identifier user_42
sessionId Browser/client session sess_abc
tags Arbitrary key-value metadata { env: "prod" }

TypeScript (AsyncLocalStorage)

The SDK uses Node.js AsyncLocalStorage to propagate context across async boundaries.

njira.runWithContext(
  { 
    requestId: "req_123", 
    traceId: "trace_abc", 
    orgId: "org_1", 
    userId: "u_9",
    tags: { environment: "production" }
  },
  async () => {
    // All calls inside this function use the same context
    await njira.enforcePre({ input: "hello" });
    njira.trace.event("custom", { ok: true });
    
    // Nested async calls also inherit context
    await processSubTask();
  }
);

Python (contextvars)

The Python SDK uses contextvars for async-safe context propagation.

ctx = {
    "request_id": "req_123", 
    "trace_id": "trace_abc", 
    "org_id": "org_1", 
    "user_id": "u_9",
    "tags": {"environment": "production"}
}

async def handler():
    # Context is available via njira.get_context()
    await njira.enforce_pre(input_data="hello")
    return njira.get_context()

await njira.run_with_context(ctx, handler)

Middleware Integration

For web applications, use the provided middleware wrappers. They automatically:

  1. Generate a unique requestId if not present.
  2. Extract traceId from incoming x-njira-trace-id header.
  3. Set context for the request lifecycle.
  4. Attach x-njira-trace-id to the response.
  5. Flush traces after the request completes.

Express

import { njiraMiddleware } from "@njiraai/sdk/express";
app.use(njiraMiddleware(njira));

FastAPI

from njiraai.fastapi import NjiraMiddleware
app.add_middleware(NjiraMiddleware, njira=njira)

Next.js

// middleware.ts
export { njiraMiddleware as middleware } from "@njiraai/sdk/next";

Debugging Context Issues

If traces appear disconnected or context is missing:

  1. Check middleware order: Njira middleware should run early.
  2. Verify async boundaries: Ensure runWithContext wraps all async work.
  3. Log context: Use njira.getContext() to inspect current values.
  4. Check for context loss: Some libraries (e.g., pg callbacks) may lose context.