Tailrace
Guides

Block secrets in an Encore service

Add Tailrace middleware to raw OpenAI-compatible Encore endpoints so chat bodies and SSE streams respect policy.

Use @tailrace/encore to enforce data policy on OpenAI-compatible proxy endpoints in Encore.ts - in-process, with no proxy.

Prerequisites

Step 1: Install

pnpm add @tailrace/core @tailrace/encore encore.dev

Step 2: Register service middleware

import { createTailrace } from "@tailrace/core";
import { tailraceEncore } from "@tailrace/encore";
import { Service } from "encore.dev/service";

export default new Service("api", {
  middlewares: [
    tailraceEncore(createTailrace(), {
      agent: "api",
      workflowId: "default",
    }),
  ],
});

Step 3: Expose the chat proxy as api.raw

Define the OpenAI-compatible proxy with api.raw so request/response bodies and SSE are available via req.rawRequest / req.rawResponse. Typed Encore APIs that return structured chat payloads still get a check when the body shape matches openai-compat, but raw endpoints are the supported path for streaming proxies.

How it works

LocationTailrace boundaryDirection
Chat request messages{ kind: "model", provider } (model field as-is)Outbound to upstream
JSON chat completionsame model boundaryInbound
SSE text/event-streamsame; carry-buffer across chunksInbound

When policy resolves to block, the middleware returns 422 with { error: { type: "policy_violation", entity, rule } } - never the raw value. That maps from PolicyViolationError.

For SSE, Tailrace cancels the upstream stream, emits one error data: event, and closes (abort-only in v0.1).

Only mode: "openai-compatible" is supported. Shared helpers live in @tailrace/http.

Common variations

Derive agent from the request

tailraceEncore(tailrace, {
  agent: (req) => String(req.data?.agentId ?? "api"),
  workflowId: (req) => String(req.requestMeta?.path ?? "default"),
});

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

On this page