@tetrascience-npm/request
v0.2.1
Published
Request tracking middleware for TetraScience services and data apps (client + server).
Downloads
392
Readme
@tetrascience-npm/request
Request middleware for TetraScience services and data apps. End-to-end tracing, auth, validation, and typed OpenAPI client generation — zero-config where possible.
Table of Contents
Installation
yarn add @tetrascience-npm/requestQuick start
Server — reads tracing + auth from headers/cookies, stores in AsyncLocalStorage:
import cookieParser from 'cookie-parser'
import { createRequestMiddleware } from '@tetrascience-npm/request/server'
app.use(cookieParser())
app.use(createRequestMiddleware())Browser — patches fetch(), auto-manages request ID + session cookie:
import { installRequestMiddleware } from '@tetrascience-npm/request/client'
installRequestMiddleware()Using a generated client — auth and tracing auto-resolve:
import { createDataAppsClient } from '@tetrascience/data-apps-client'
// Browser — auth from cookies, tracing from installRequestMiddleware
const client = createDataAppsClient({ auth: 'direct' })
// Server (service-to-service) — reads INTERNAL_API_KEY env var, rest from context
const client = createDataAppsClient({
baseUrl: process.env.TDP_API_URL,
auth: 'internal',
})
// Fully typed
const { data } = await client.GET('/v1/dataapps/kv/{appSlug}', {
params: { path: { appSlug: 'my-app' } },
})Auth
Both auth modes auto-resolve values from RequestContext (server) or cookies (browser) when not explicitly provided.
// Zero-config shorthands
auth: 'direct' // user/browser
auth: 'internal' // service-to-service (reads INTERNAL_API_KEY env var)
// Explicit values
auth: { authToken: jwt, orgSlug: 'my-org' }
auth: { internalApiKey: env.KEY, orgSlug: 'my-org', authToken: 'tok' }Headers injected by each mode:
| Mode | Headers |
|------|---------|
| Direct | ts-auth-token, x-org-slug |
| Internal | ts-internal-api-key, x-org-slug, ts-auth-token |
Middleware pipeline
applyDefaultMiddleware(client, options, schemas) wires the standard pipeline:
| Order | Middleware | Headers / Purpose |
|-------|-----------|-------------------|
| 1 | Tracing | ts-request-id, ts-session-id, ts-initiating-service-name, logging |
| 2 | Auth | ts-internal-api-key / ts-auth-token / x-org-slug |
| 3 | Validation | Zod request body validation |
| 4 | Safe response | Wraps non-JSON success responses |
On Node servers, request ID, session ID, orgSlug, and authToken auto-propagate from createRequestMiddleware context. New middleware added here is picked up by existing clients on dependency update — no regeneration needed.
Client SDK generation
Add to package.json:
"serviceClient": {
"packageName": "@tetrascience/data-apps-client",
"spec": "openapi/dataapps.yaml",
"version": "2.0.0"
}Run generate-service-client — produces a typed client directory. Multi-spec support:
"spec": { "internal": "openapi/internal.yaml", "public": "openapi/public.yaml" }Entrypoints
| Entrypoint | Environment | Purpose |
|-----------|-------------|---------|
| Root | Any | Middleware, types, constants, createClient, applyDefaultMiddleware |
| /server | Node only | createRequestMiddleware, runWithRequestContext, getRequestId |
| /client | Browser only | installRequestMiddleware, createConsoleLogger |
Independent — /server and /client do not re-export the root.
API reference
Root
Middleware:
| Export | Description |
|--------|-------------|
| createClient | Re-exported from openapi-fetch |
| applyDefaultMiddleware(client, options, schemas?) | Standard pipeline with auto-resolve |
| createTracingMiddleware(options?) | ts-request-id, ts-session-id, ts-initiating-service-name, logging |
| createInternalAuthMiddleware(auth) | Service-to-service auth ('internal' or explicit) |
| createDirectAuthMiddleware(auth) | User auth ('direct' or explicit) |
| createRequestValidationMiddleware(opts) | Zod request body validation |
| createSafeResponseMiddleware() | Wraps non-JSON responses |
Types:
| Export | Description |
|--------|-------------|
| ServiceClientOptions | { baseUrl?, auth, headers?, skipValidation? } extends TracingOptions |
| InternalAuth | InternalAuthExplicit \| 'internal' |
| DirectAuth | AuthBase \| 'direct' |
| AuthBase | { authToken?, orgSlug? } — auto-resolves from context/cookies |
| InternalAuthExplicit | AuthBase & { internalApiKey } |
| TracingOptions | { requestId?, sessionId?, serviceName?, logger? } |
| HeaderValue | string \| (() => string \| undefined) |
| RequestContext | { requestId, sessionId, orgSlug?, authToken? } |
Constants: REQUEST_ID_HEADER, SESSION_ID_HEADER, ORG_SLUG_HEADER, AUTH_TOKEN_HEADER, INTERNAL_API_KEY_HEADER, INITIATING_SERVICE_NAME_HEADER
/server
| Export | Description |
|--------|-------------|
| createRequestMiddleware() | Express middleware — reads headers/cookies, sets context + session cookie |
| runWithRequestContext(ctx, fn) | Scoped context via AsyncLocalStorage.run() |
| runWithoutRequestContext(fn) | No context (testing) |
| getRequestContext() | Read current context |
| getRequestId() | Request ID from context or new UUID |
/client
| Export | Description |
|--------|-------------|
| installRequestMiddleware(opts?) | Patches global fetch() — request ID + session cookie |
| createConsoleLogger(opts?) | Console logger with level filtering and prefix |
