npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jstverify/tracing

v0.7.0

Published

JstVerify Node.js Tracing SDK — distributed tracing for Node.js backends

Downloads

774

Readme

@jstverify/tracing

Node.js distributed tracing SDK for JstVerify application mapping. Auto-instruments your backend to produce trace spans that connect with the JstVerify JavaScript SDK, giving you a full frontend-to-backend service map.

Zero runtime dependencies. Supports Node.js 18+.

Installation

npm install @jstverify/tracing

Quick Start

1. Initialize (once at startup)

import { init } from "@jstverify/tracing";

init({
  apiKey: "your-sdk-key",
  serviceName: "my-backend",
});

The endpoint defaults to the production ingestion URL (https://sdkapi.jstverify.com/v1/tracing/spans). Override for dev environments:

init({
  apiKey: "your-sdk-key",
  endpoint: "https://sdkapi.dev.jstverify.com/v1/tracing/spans",
  serviceName: "my-backend",
});

2. Add Framework Middleware

Express:

import { tracingMiddleware } from "@jstverify/tracing";

app.use(tracingMiddleware({ gatewayName: "my-api-gateway" }));

Fastify:

import { fastifyTracingPlugin } from "@jstverify/tracing";

fastify.register(fastifyTracingPlugin, { gatewayName: "my-api-gateway" });

Koa:

import { koaTracingMiddleware } from "@jstverify/tracing";

app.use(koaTracingMiddleware({ gatewayName: "my-api-gateway" }));

Hapi:

import { hapiTracingPlugin } from "@jstverify/tracing";

await server.register({ plugin: hapiTracingPlugin, options: { gatewayName: "my-api-gateway" } });

AWS Lambda (API Gateway):

import { JstVerifyTracingMiddleware } from "@jstverify/tracing";

export const handler = JstVerifyTracingMiddleware(async (event, context) => {
  return { statusCode: 200, body: "ok" };
});

For backend event sources (SQS, SNS, EventBridge):

export const handler = JstVerifyTracingMiddleware({ backendTrace: true })(
  async (event, context) => {
    // process SQS messages, SNS notifications, etc.
  },
);

Express / Fastify on AWS Lambda (via @vendia/serverless-express, etc.):

When running a framework app on Lambda, use the framework middleware above for tracing — but you must also call flush() at the end of each request. The background flush timer uses setInterval.unref() which won't fire between Lambda invocations.

import { flush } from "@jstverify/tracing";

app.get("/api/example", async (req, res) => {
  try {
    res.json({ ok: true });
  } finally {
    await flush();
  }
});

Note: The JstVerifyTracingMiddleware Lambda wrapper handles flushing automatically — this manual flush is only needed when using framework middleware on Lambda.

AWS AppSync Lambda Resolver:

import { JstVerifyAppSyncMiddleware } from "@jstverify/tracing";

export const handler = JstVerifyAppSyncMiddleware(async (event, context) => {
  return [{ id: "1", name: "Alice" }];
});

The AppSync middleware extracts trace context from event.request.headers or event.stash (pipeline resolvers) and derives the operation name from event.info.parentTypeName and event.info.fieldName (e.g. Query.listUsers). Only direct transport mode is supported — relay mode is not available for AppSync since GraphQL responses cannot carry custom HTTP headers.

3. Manual Instrumentation (optional)

import { trace, traceSpan, SpanHandle } from "@jstverify/tracing";

// Decorator-style wrapping
const processPayment = trace("process-payment")(async (orderId: string) => {
  // ...
});

// Callback-based spans
async function handleOrder(orderId: string) {
  const result = await traceSpan("validate-order", async (span: SpanHandle) => {
    // ...
    span.setStatus(200);
    return validated;
  });

  await traceSpan("charge-card", async (span: SpanHandle) => {
    // ...
    span.setHttpMetadata({ method: "POST", url: "/payments/charge", statusCode: 201 });
  });
}

4. Custom Attributes

Attach custom key-value metadata to any span. Values are coerced to strings.

Via trace() options:

const processPayment = trace("process-payment", {
  attributes: { orderId: "ORD-123", amount: 49.99, express: true },
})(async (orderId: string) => {
  // ...
});

Via SpanHandle.setAttribute():

await traceSpan("validate-order", async (span: SpanHandle) => {
  span.setAttribute("orderId", orderId);
  span.setAttribute("itemCount", items.length);
  // ...
});

When both options and handle set the same key, the handle value wins.

5. DynamoDB Tracing

Use the traceDynamodb() helper to wrap individual DynamoDB operations:

import { traceDynamodb } from "@jstverify/tracing";

// Wraps any async operation with a DynamoDB-typed span
const result = await traceDynamodb("GetItem", "users-table", async () => {
  return client.send(new GetItemCommand({ TableName: "users-table", Key: { id: { S: "123" } } }));
});

const items = await traceDynamodb("Query", "orders-table", async () => {
  return client.send(new QueryCommand({ TableName: "orders-table", ... }));
});

Each call creates a child span with the operation name (e.g. GetItem users-table) and serviceType: "dynamodb".

6. Auto-Patching

Outgoing HTTP (fetch):

import { patchFetch } from "@jstverify/tracing";

patchFetch();
// All subsequent fetch() calls are automatically traced with headers injected

AWS SDK v3:

import { createAwsSdkTracingMiddleware } from "@jstverify/tracing";
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";

const client = new DynamoDBClient({});
client.middlewareStack.use(createAwsSdkTracingMiddleware());

7. Trace Context Propagation

For SQS and EventBridge, use the propagation helpers to forward trace context:

import { propagation } from "@jstverify/tracing";

// SQS — add as MessageAttributes
const attrs = propagation.sqsMessageAttributes();
await sqs.send(new SendMessageCommand({
  QueueUrl: "...",
  MessageBody: "...",
  MessageAttributes: attrs,
}));

// EventBridge — merge into detail
const traceCtx = propagation.eventbridgeTraceContext();
await events.send(new PutEventsCommand({
  Entries: [{ Source: "my-app", DetailType: "OrderPlaced", Detail: JSON.stringify({ ...payload, ...traceCtx }) }],
}));

8. Shutdown

import { shutdown } from "@jstverify/tracing";

await shutdown();

Shutdown is also registered via process.on('beforeExit') automatically.

Configuration Options

| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | apiKey | string | required | Your JstVerify SDK API key | | endpoint | string | production URL | Span ingestion endpoint URL (defaults to https://sdkapi.jstverify.com/v1/tracing/spans) | | serviceName | string | required | Service name shown in the service map | | serviceType | string | "http" | Service type identifier (auto-detects "lambda" in Lambda environments) | | gatewayName | string | — | If set, framework middleware synthesizes an API Gateway parent span | | transport | string | "direct" | "direct" sends spans via HTTP; "relay" encodes spans into response headers | | flushInterval | number | 5 | Seconds between background flushes | | maxQueueSize | number | 200 | Max buffered spans (circular buffer) | | maxBatchSize | number | 50 | Max spans per API request | | debug | boolean | false | Enable debug logging | | sanitizePii | boolean | true | Scrub PII (SSN, email, phone, credit card) from span data | | piiPatterns | string[] | [] | Additional regex patterns for PII scrubbing | | piiRedaction | string | "[REDACTED]" | Replacement string for redacted PII |

How It Works

Direct Mode (default)

  1. The middleware reads X-JstVerify-Trace-Id and X-JstVerify-Parent-Span-Id headers from incoming requests (injected by the JS SDK).
  2. A root span is created for each request, with nested child spans for trace() wrapped functions and traceSpan() callbacks.
  3. If patchFetch() is called, outgoing fetch calls are automatically instrumented — trace headers are injected so downstream services can continue the trace.
  4. Spans are buffered in a queue and flushed to the JstVerify API in batches by a background setInterval timer (.unref()'d so it doesn't block process exit).

Relay Mode

For backends without outbound internet access (private VPC, strict firewalls), relay mode encodes spans into the X-JstVerify-Spans response header. The JstVerify JS SDK reads this header and relays the spans to the ingestion API on behalf of the backend.

init({
  apiKey: "your-sdk-key",
  serviceName: "my-backend",
  transport: "relay", // No endpoint needed
});

How it works:

  1. Each request collects spans in a per-request buffer (async-safe via AsyncLocalStorage).
  2. When the response is sent, all spans are base64url-encoded into the X-JstVerify-Spans header.
  3. The JS SDK decodes the header and merges the spans into its own flush queue.

Limitations:

  • ~20-30 spans per response max due to the 7500-byte header size limit.
  • Only works for request-response flows — async background jobs have no response to carry spans.
  • Cross-origin requests require the Access-Control-Expose-Headers header (set automatically by the middleware).

License

MIT