@docsmyth/capture-proxy
v0.2.0-rc.8
Published
API Contract Platform Capture Proxy - Language-agnostic HTTP sidecar for evidence capture
Readme
@docsmyth/capture-proxy
Language-agnostic HTTP sidecar proxy for evidence capture. Works with any HTTP service behind it and emits evidence events mapped to Contract IR operationIds.
Installation
npm install @docsmyth/capture-proxy
# or
pnpm add @docsmyth/capture-proxyFeatures
- Language-agnostic: Works with any HTTP service (Python, Go, Ruby, Java, etc.)
- Automatic operation mapping: Matches requests to Contract IR operations
- Evidence sanitization: Removes sensitive headers (Authorization, Cookie, etc.)
- Body truncation: Configurable max body size with truncation for large payloads
- Rate limiting: Prevents evidence explosion with configurable rate limits
- Hub integration: Load contracts from the ACP Hub or local files
- Health endpoint: Built-in
/_acp/healthendpoint for monitoring
CLI Usage
The proxy can be started via the ACP CLI:
# Using a local contract file
docsmyth proxy --target http://localhost:3000 --contract ./contract-ir.json --capture
# Using a contract from the Hub
docsmyth proxy --target http://localhost:3000 \
--hub-url http://hub.example.com \
--service my-api \
--version latest \
--capture
# Full options
docsmyth proxy \
--listen 0.0.0.0:8080 \
--target http://localhost:3000 \
--contract ./contract-ir.json \
--capture \
--out ./evidence.ndjson \
--max-body-bytes 65536 \
--event-rate-limit 100 \
--verboseEnvironment Variables
All CLI options can be set via environment variables:
| Variable | CLI Option | Description |
| ---------------------- | -------------------- | ---------------------------------------- |
| ACP_PROXY_LISTEN | --listen | Listen address (default: 0.0.0.0:8080) |
| ACP_PROXY_TARGET_URL | --target | Upstream target URL |
| ACP_HUB_URL | --hub-url | Hub URL for contract loading |
| ACP_HUB_TOKEN | --hub-token | Hub authentication token |
| ACP_SERVICE | --service | Service name for Hub |
| ACP_VERSION | --version | Contract version (default: latest) |
| ACP_CAPTURE | --capture | Enable capture (1 or true) |
| ACP_EVIDENCE_OUT | --out | Evidence output path |
| ACP_MAX_BODY_BYTES | --max-body-bytes | Max body size before truncation |
| ACP_EVENT_RATE_LIMIT | --event-rate-limit | Events per second limit |
Programmatic Usage
import { startProxy, type ProxyConfig } from '@docsmyth/capture-proxy';
const config: ProxyConfig = {
listen: '0.0.0.0:8080',
targetUrl: 'http://localhost:3000',
captureEnabled: true,
contractSource: { type: 'file', path: './contract-ir.json' },
evidenceOutputPath: './evidence.ndjson',
maxBodyBytes: 65536,
eventRateLimit: 100,
logLevel: 'info',
};
const server = await startProxy(config);
console.log(`Proxy listening on ${server.getListenAddress()}`);
// Get health status
const health = server.getHealth();
console.log(`Events captured: ${health.capture.eventsWritten}`);
// Stop the proxy
await server.stop();Health Endpoint
The proxy exposes a health endpoint at /_acp/health that returns:
{
"status": "ok",
"proxy": {
"listening": true,
"listenAddress": "0.0.0.0:8080",
"targetUrl": "http://localhost:3000"
},
"contract": {
"loaded": true,
"serviceName": "orders-api",
"serviceVersion": "1.0.0",
"operationCount": 5
},
"capture": {
"enabled": true,
"eventsWritten": 42,
"eventsDropped": 0
},
"uptime": 3600
}Docker Usage
FROM node:20-alpine
RUN npm install -g @docsmyth/cli
ENV ACP_PROXY_LISTEN=0.0.0.0:8080
ENV ACP_CAPTURE=1
EXPOSE 8080
ENTRYPOINT ["acp", "proxy"]# docker-compose.yml
services:
my-api:
build: .
ports:
- '3000:3000'
capture-proxy:
image: acp-proxy
ports:
- '8080:8080'
environment:
- ACP_PROXY_TARGET_URL=http://my-api:3000
- ACP_HUB_URL=http://hub:3456
- ACP_SERVICE=my-api
- ACP_CAPTURE=1
volumes:
- ./evidence:/app/evidenceEvidence Format
Evidence is emitted as NDJSON (newline-delimited JSON):
{
"evidenceVersion": "0.1",
"operationId": "createOrder",
"protocol": "http",
"timestamp": "2024-01-15T10:30:00.000Z",
"traceId": "acp-abc123",
"request": {
"method": "POST",
"path": "/orders",
"headers": { "content-type": "application/json" },
"body": { "customerId": "cust-1" }
},
"response": {
"status": 201,
"headers": { "content-type": "application/json" },
"body": { "id": "ord-123" }
}
}Comparison with @docsmyth/runtime-node-express
| Feature | @docsmyth/capture-proxy | @docsmyth/runtime-node-express | | --------------------- | -------------------------- | ------------------------- | | Integration | Sidecar (any language) | Express middleware | | Setup | Zero code changes | Requires middleware | | Performance | Slight latency (proxy hop) | In-process (minimal) | | Access to app context | No | Yes (trace IDs, etc.) | | Best for | Legacy apps, polyglot | Express/Node.js apps |
License
MIT
