Block secrets in a NestJS app
Register TailraceModule so OpenAI-compatible routes respect Tailrace policy on Nest + Express.
Use @tailrace/nestjs to enforce data policy on OpenAI-compatible chat routes in NestJS - in-process, with no proxy.
Prerequisites
- Quickstart or equivalent
createTailracesetup - NestJS (
@nestjs/common/@nestjs/core>=10) with the Express adapter (primary CI target) reflect-metadataloaded before Nest bootstraps
Step 1: Install
pnpm add @tailrace/core @tailrace/nestjs @nestjs/common @nestjs/core reflect-metadataStep 2: Import TailraceModule
import { createTailrace } from "@tailrace/core";
import { TailraceModule } from "@tailrace/nestjs";
import { Module } from "@nestjs/common";
@Module({
imports: [
TailraceModule.forRoot({
tailrace: createTailrace(),
forRoutes: ["v1/*path"],
agent: (req) => String(req.headers["x-agent-id"] ?? "default"),
workflowId: (req) => String(req.headers["x-workflow-id"] ?? "default"),
}),
],
})
export class AppModule {}Nest 11 route globs use named splats (v1/*path, not v1*). Prefer scoping forRoutes to your
chat proxy paths instead of the default all-routes matcher.
How it works
TailraceModule.forRoot registers TailraceMiddleware on the routes you
pass. The middleware applies the same openai-compat contract as Hono and Express:
| Location | Tailrace boundary | Direction |
|---|---|---|
| Chat request messages | { kind: "model", provider } (model field as-is) | Outbound to upstream |
| JSON chat completion | same model boundary | Inbound |
SSE text/event-stream | same; carry-buffer across chunks | Inbound |
When policy resolves to block, the middleware returns 422 with
{ error: { type: "policy_violation", entity, rule } } - never the raw value. That maps from
PolicyViolationError.
Only mode: "openai-compatible" is supported. Shared helpers live in @tailrace/http.
Common variations
Nest + Fastify
For Nest's Fastify adapter, register @tailrace/fastify
on the underlying Fastify instance rather than relying on Express-shaped Nest middleware.
Scope agent and workflow ID
Pass agent and workflowId as functions of the Express Request (or a static string for
workflowId). Defaults are "default" when omitted.
Verify with a synthetic key
Send a chat completion body whose messages include sk_test_…FAKE. Expect 422. An
example.com email should tokenize under the default policy.
See also
Block secrets in a Fastify app
Register the OpenAI-compatible Fastify plugin so chat requests and SSE responses respect Tailrace policy before they reach the model.
Block secrets in an Encore service
Add Tailrace middleware to raw OpenAI-compatible Encore endpoints so chat bodies and SSE streams respect policy.