https://github.com/stainless-api/xray-emitter-js
X-ray emitter for Node/Typescript
https://github.com/stainless-api/xray-emitter-js
Last synced: 3 months ago
JSON representation
X-ray emitter for Node/Typescript
- Host: GitHub
- URL: https://github.com/stainless-api/xray-emitter-js
- Owner: stainless-api
- Created: 2026-02-12T19:14:15.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-03-12T23:11:28.000Z (3 months ago)
- Last Synced: 2026-03-13T00:05:35.355Z (3 months ago)
- Language: TypeScript
- Size: 170 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Agents: AGENTS.md
Awesome Lists containing this project
README
# X-ray emitter
Node and Typescript SDKs to emit request logs to Stainless X-ray.
## Getting started
```sh
npm add @stainlessdev/xray-emitter
```
Then using it in Express, for example:
```ts
import express from 'express';
import { createEmitter } from '@stainlessdev/xray-emitter/express';
import { getXrayContext } from '@stainlessdev/xray-emitter/node';
const app = express();
const xray = createEmitter({ serviceName: 'my-service' });
app.use(xray);
app.use((req, _res, next) => {
const ctx = getXrayContext(req);
ctx?.setActor('tenant-123', 'user-123');
next();
});
app.get('/', (_req, res) => {
res.send('ok');
});
```
## Supported frameworks
| Framework | Import | Docs | Example |
|-----------|--------|------|---------|
| Express | `@stainlessdev/xray-emitter/express` | [README](src/express/README.md) | [example](examples/express) |
| Fastify | `@stainlessdev/xray-emitter/fastify` | [README](src/fastify/README.md) | [example](examples/fastify) |
| Hono | `@stainlessdev/xray-emitter/hono` | [README](src/hono/README.md) | [example](examples/hono) |
| Next.js | `@stainlessdev/xray-emitter/next` | [README](src/next/README.md) | [example](examples/next-app) |
| Remix | `@stainlessdev/xray-emitter/remix` | [README](src/remix/README.md) | [example](examples/remix-app) |
| Effect | `@stainlessdev/xray-emitter/effect` | [README](src/effect/README.md) | [example](examples/effect) |
Lower-level adapters:
| Adapter | Import | Docs | Example |
|---------|--------|------|---------|
| Node.js (`node:http`) | `@stainlessdev/xray-emitter/node` | [README](src/node/README.md) | [example](examples/node-http) |
| Fetch / Edge | `@stainlessdev/xray-emitter/fetch` | [README](src/fetch/README.md) | [example](examples/edge) |
| Core | `@stainlessdev/xray-emitter` | [README](src/core/README.md) | — |
## Configuration
X-ray does not read standard OTEL environment variables. Configure an endpoint by passing
`endpointUrl` or setting `STAINLESS_XRAY_ENDPOINT_URL`. If both are set, `endpointUrl` wins. An
error is thrown if no endpoint is configured.
The core module (`@stainlessdev/xray-emitter`) is runtime-agnostic; use it only if you supply a
custom exporter instance to `createEmitter`.
### Request IDs
X-ray resolves request IDs from **response headers** when the span is closed. Configure the header name with `requestId.header` (default: `request-id`, emitted as `Request-Id`). Resolution order is: explicit `requestId` on the normalized request → response header lookup → UUIDv7 when missing.
If the configured response header is missing when the response is finalized, X-ray will set it (using the explicit ID when provided, otherwise a generated UUIDv7). Existing response headers are not overwritten.
### Fetch wrappers
`wrapFetch` may replace the request/response objects while capturing bodies. `wrapFetchPreserve` keeps the original request/response whenever possible, but it may replace the response if it needs to inject a missing `Request-Id` header.
## Development
```sh
pnpm install
pnpm build
pnpm test
```