{"id":38164093,"url":"https://github.com/forattini-dev/raffel","last_synced_at":"2026-04-02T00:25:57.200Z","repository":{"id":332039347,"uuid":"1130368081","full_name":"forattini-dev/raffel","owner":"forattini-dev","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-01T02:14:08.000Z","size":2232,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-01T02:44:22.973Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://forattini-dev.github.io/raffel/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/forattini-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-08T12:05:52.000Z","updated_at":"2026-04-01T02:14:13.000Z","dependencies_parsed_at":"2026-03-14T23:06:12.064Z","dependency_job_id":null,"html_url":"https://github.com/forattini-dev/raffel","commit_stats":null,"previous_names":["forattini-dev/raffel"],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/forattini-dev/raffel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forattini-dev%2Fraffel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forattini-dev%2Fraffel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forattini-dev%2Fraffel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forattini-dev%2Fraffel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/forattini-dev","download_url":"https://codeload.github.com/forattini-dev/raffel/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forattini-dev%2Fraffel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31293376,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-16T23:19:37.401Z","updated_at":"2026-04-02T00:25:57.191Z","avatar_url":"https://github.com/forattini-dev.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# Raffel\n\n### One server. HTTP, WebSocket, gRPC, TCP, UDP — all at once.\n\n[![npm version](https://img.shields.io/npm/v/raffel.svg?style=flat-square\u0026color=8b5cf6)](https://www.npmjs.com/package/raffel)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-3178C6?style=flat-square\u0026logo=typescript\u0026logoColor=white)](https://www.typescriptlang.org/)\n[![Node.js](https://img.shields.io/badge/Node.js-18+-339933?style=flat-square\u0026logo=node.js\u0026logoColor=white)](https://nodejs.org/)\n[![License](https://img.shields.io/badge/License-MIT-green?style=flat-square)](LICENSE)\n\n[Quick Start](#quick-start) · [Full Documentation](https://forattini-dev.github.io/raffel) · [Examples](./examples) · [Migration Guide](#migrating-an-existing-http-app)\n\n\u003c/div\u003e\n\n---\n\nRaffel is a TypeScript runtime for building APIs, proxies, and traffic-aware infrastructure in one stack.\n\n- Build HTTP, WebSocket, gRPC, JSON-RPC, GraphQL, TCP, and UDP services with one project.\n- Run reverse proxy, explicit proxy, CONNECT MITM, SOCKS5/SOCKS5h, and transparent proxy modes.\n- Export service-mesh style telemetry with `source -\u003e destination -\u003e protocol`, p50/p90/p95, throughput, bytes, and error rates.\n- Add resilience and policy with rate limit, retry, timeout, circuit breaker, validation, auth/session, filters, and proxy middleware.\n\nHeavy edge features stay off by default. Telemetry, graph snapshots, Prometheus exporters, and proxy middleware only run when configured.\n\nNeed the right guide fast? Use the docs or the built-in MCP tools: `raffel_feature_catalog`, `raffel_proxy_capabilities`, `raffel_get_guide`, and `raffel_search`.\n\n- **Protocols:** [HTTP](https://forattini-dev.github.io/raffel/#/protocols/http), [WebSocket](https://forattini-dev.github.io/raffel/#/protocols/websocket), [gRPC](https://forattini-dev.github.io/raffel/#/protocols/grpc), [UDP](https://forattini-dev.github.io/raffel/#/protocols/udp)\n- **Proxies:** [Overview](https://forattini-dev.github.io/raffel/#/proxy), [Modes](https://forattini-dev.github.io/raffel/#/proxy/modes), [Routing](https://forattini-dev.github.io/raffel/#/proxy/routing), [Service Mesh](https://forattini-dev.github.io/raffel/#/proxy/service-mesh)\n- **Observability:** [Flow Metrics](https://forattini-dev.github.io/raffel/#/proxy/flow-metrics), [Observability](https://forattini-dev.github.io/raffel/#/observability), [Tracing](https://forattini-dev.github.io/raffel/#/observability/tracing)\n\n## Start with HTTP\n\n```typescript\nimport { HttpApp, serve } from 'raffel'\n\nconst app = new HttpApp()\n\napp.get('/users', async (c) =\u003e {\n  return c.json(await db.users.findMany())\n})\n\napp.get('/users/:id', async (c) =\u003e {\n  const user = await db.users.findById(c.req.param('id'))\n  if (!user) return c.json({ error: 'Not found' }, 404)\n  return c.json(user)\n})\n\napp.post('/users', async (c) =\u003e {\n  const body = await c.req.json()\n  return c.json(await db.users.create(body), 201)\n})\n\nserve({ fetch: app.fetch, port: 3000 })\n```\n\n`HttpApp` gives Raffel a native Fetch-style HTTP front door. Start with familiar\nroute and middleware concepts, then expand the same contracts across protocols.\n\n---\n\n## Quick Start\n\n```bash\npnpm add raffel\n```\n\n### Hello World\n\n```typescript\nimport { HttpApp, serve } from 'raffel'\n\nconst app = new HttpApp()\n\napp.get('/hello/:name', (c) =\u003e c.text(`Hello, ${c.req.param('name')}!`))\n\nserve({ fetch: app.fetch, port: 3000 })\n```\n\n### CRUD in 30 Seconds\n\n```typescript\nimport { HttpApp, serve } from 'raffel'\n\nconst app = new HttpApp()\nconst users = new Map\u003cstring, unknown\u003e()\n\napp.get('/users', (c) =\u003e c.json([...users.values()]))\n\napp.get('/users/:id', (c) =\u003e {\n  const user = users.get(c.req.param('id'))\n  return user ? c.json(user) : c.json({ error: 'Not found' }, 404)\n})\n\napp.post('/users', async (c) =\u003e {\n  const user = { id: crypto.randomUUID(), ...(await c.req.json()) }\n  users.set(user.id, user)\n  return c.json(user, 201)\n})\n\napp.put('/users/:id', async (c) =\u003e {\n  const id = c.req.param('id')\n  if (!users.has(id)) return c.json({ error: 'Not found' }, 404)\n  const user = { id, ...(await c.req.json()) }\n  users.set(id, user)\n  return c.json(user)\n})\n\napp.delete('/users/:id', (c) =\u003e {\n  const id = c.req.param('id')\n  return users.delete(id)\n    ? c.json({ success: true })\n    : c.json({ error: 'Not found' }, 404)\n})\n\nserve({ fetch: app.fetch, port: 3000 })\n```\n\n### Production-Ready `serve()`\n\n```typescript\nserve({\n  fetch: app.fetch,\n  port: 3000,\n  keepAliveTimeout: 65000,   // slightly above load balancer idle timeout\n  headersTimeout: 66000,\n  onListen: ({ port, hostname }) =\u003e console.log(`Listening on ${hostname}:${port}`),\n})\n```\n\n---\n\n## Developer Experience In 2026\n\nRaffel now ships with an inspection-first workflow for multi-protocol services:\n\n```bash\n# optional, for a global CLI\nnpm i -g raffel\n\nnpx raffel new api my-service\ncd my-service\npnpm install\nnpx raffel inspect src/server.ts\nnpx raffel explain \"users.list\" src/server.ts\nnpx raffel doctor src/server.ts\nnpx raffel playground src/server.ts --port 4301\nnpx raffel contract-tests src/server.ts\npnpm dev\n```\n\nThe same runtime graph powers:\n\n- `server.preview()`\n- `raffel inspect`\n- `raffel explain`\n- `raffel doctor`\n- `raffel playground`\n- `raffel contract-tests`\n- OpenAPI/USD output\n\nThat keeps your docs, runtime bindings, local tooling, and contract checks\naligned.\n\n---\n\n## Wait, There's More\n\nRaffel is not just an HTTP framework. It's a **unified multi-protocol runtime**. Every handler you write is protocol-agnostic — the same business logic runs over HTTP, WebSocket, gRPC, JSON-RPC, GraphQL, TCP, and UDP.\n\n### The Procedure API\n\n```typescript\nimport { createServer } from 'raffel'\nimport { z } from 'zod'\n\nconst server = createServer({\n  port: 3000,\n  websocket: { path: '/ws' },\n  jsonrpc: { path: '/rpc' },\n})\n\nserver\n  .procedure('users.create')\n  .input(z.object({ name: z.string().min(2), email: z.string().email() }))\n  .output(z.object({ id: z.string(), name: z.string(), email: z.string() }))\n  .handler(async (input, ctx) =\u003e {\n    return db.users.create(input)\n  })\n\nawait server.start()\n```\n\n**Same handler. Every protocol. Zero extra code.**\n\n```bash\n# HTTP\ncurl -X POST http://localhost:3000/users \\\n  -d '{\"name\":\"Alice\",\"email\":\"alice@example.com\"}'\n\n# WebSocket\nwscat -c ws://localhost:3000/ws\n\u003e {\"method\":\"users.create\",\"params\":{\"name\":\"Alice\",\"email\":\"alice@example.com\"}}\n\n# JSON-RPC 2.0\ncurl -X POST http://localhost:3000/rpc \\\n  -d '{\"jsonrpc\":\"2.0\",\"method\":\"users.create\",\"params\":{...},\"id\":1}'\n```\n\n### Streaming\n\n```typescript\n// Server → client stream\nserver\n  .stream('logs.tail')\n  .handler(async function* ({ file }) {\n    for await (const line of readLines(file)) {\n      yield { line, timestamp: Date.now() }\n    }\n  })\n\n// Bidirectional stream\nserver\n  .stream('chat.session')\n  .bidi()\n  .handler(async (stream, ctx) =\u003e {\n    for await (const msg of stream) {\n      await stream.write({ echo: msg, from: ctx.auth?.userId })\n    }\n  })\n```\n\n### Events with Delivery Guarantees\n\n```typescript\nserver\n  .event('emails.send')\n  .delivery('at-least-once')\n  .handler(async (payload, ctx, ack) =\u003e {\n    await sendEmail(payload)\n    ack()\n  })\n```\n\n---\n\n## The Full Picture\n\n| Module | What it does |\n|--------|-------------|\n| **HTTP** | Native HTTP front door + `serve()` with production timeouts |\n| **WebSocket** | Real-time adapter + Pusher-like channels (public/private/presence) |\n| **gRPC** | Full gRPC adapter with TLS and streaming |\n| **JSON-RPC 2.0** | Batch + notification + error codes per spec |\n| **GraphQL** | Schema-first adapter with subscriptions |\n| **TCP / UDP** | Raw socket handlers with connection filters |\n| **Single-Port** | Sniff protocol on one port — HTTP, WS, gRPC, gRPC-Web all on `:3000` |\n| **Interceptors** | Rate limit, circuit breaker, retry, timeout, cache, bulkhead, and more |\n| **Session Store** | Memory + Redis drivers with lazy load + auto-save |\n| **Proxy Suite** | HTTP forward, CONNECT tunnel (MITM), SOCKS5, transparent |\n| **Metrics** | Prometheus-style counters, gauges, histograms with exporters |\n| **Tracing** | OpenTelemetry spans with Jaeger / Zipkin exporters |\n| **OpenAPI** | Generate spec from schemas + serve ReDoc / Swagger UI |\n| **Channels** | Pusher-like pub/sub with presence and authorization |\n| **MCP Server** | Model Context Protocol for AI-assisted development |\n| **Testing** | Full mock suite: HTTP, WS, TCP, UDP, DNS, SSE, Proxy |\n| **Validation** | Plug in Zod, Yup, Joi, Ajv, or fastest-validator |\n\n---\n\n## Interceptors\n\nInterceptors are reusable middleware that compose cleanly across any protocol.\n\n```typescript\nimport {\n  createRateLimitInterceptor,\n  createCircuitBreakerInterceptor,\n  createRetryInterceptor,\n  createTimeoutInterceptor,\n  createCacheInterceptor,\n  createLoggingInterceptor,\n  createTracingInterceptor,\n} from 'raffel'\n\nserver\n  .procedure('users.list')\n  .use(createTimeoutInterceptor({ timeout: 5000 }))\n  .use(createRateLimitInterceptor({ limit: 100, window: '1m' }))\n  .use(createCacheInterceptor({ ttl: 60, store: cacheStore }))\n  .use(createLoggingInterceptor())\n  .handler(async () =\u003e db.users.findMany())\n```\n\nApply globally, per-group, or per-procedure:\n\n```typescript\n// Global\nserver.use(createTracingInterceptor({ tracer }))\nserver.use(createLoggingInterceptor())\n\n// Group / module\nconst adminModule = createRouterModule('admin', [requireAdmin])\nadminModule.procedure('users.delete').handler(...)\n\n// Per-procedure\nserver.procedure('payments.charge')\n  .use(createCircuitBreakerInterceptor({ threshold: 5, timeout: 30000 }))\n  .use(createRetryInterceptor({ attempts: 3, backoff: 'exponential' }))\n  .handler(...)\n```\n\n| Interceptor | Purpose |\n|-------------|---------|\n| `createRateLimitInterceptor` | Token bucket / sliding window (memory, Redis, filesystem) |\n| `createCircuitBreakerInterceptor` | Auto-open after failures, half-open probe |\n| `createBulkheadInterceptor` | Concurrency isolation per procedure |\n| `createRetryInterceptor` | Exponential backoff with jitter |\n| `createTimeoutInterceptor` | Per-phase, cascading, deadline propagation |\n| `createCacheInterceptor` | Read-through / write-through (memory, file, Redis) |\n| `createDedupInterceptor` | In-flight request deduplication |\n| `createSizeLimitInterceptor` | Request / response size guard |\n| `createFallbackInterceptor` | Return default on failure |\n| `createRequestIdInterceptor` | Inject/propagate correlation IDs |\n| `createLoggingInterceptor` | Structured request/response logging |\n| `createMetricsInterceptor` | Auto-instrument with Prometheus metrics |\n| `createTracingInterceptor` | OpenTelemetry span creation |\n| `createSessionInterceptor` | Session load/save via memory or Redis |\n| `createValidationInterceptor` | Schema validation on input/output |\n| `createAuthMiddleware` | Bearer token, API key strategies |\n\n---\n\n## Channels (Real-Time Pub/Sub)\n\nPusher-compatible channel model over WebSocket.\n\n```typescript\nimport { createChannelManager } from 'raffel'\n\nconst channels = createChannelManager(\n  {\n    authorize: async (socketId, channel, ctx) =\u003e {\n      // private-* and presence-* channels require auth\n      return { authorized: !!ctx.auth }\n    },\n    presence: {\n      onJoin: (channel, member) =\u003e broadcastPresence(channel),\n      onLeave: (channel, member) =\u003e broadcastPresence(channel),\n    },\n  },\n  (socketId, message) =\u003e ws.sendToClient(socketId, message)\n)\n\n// Subscribe\nawait channels.subscribe(socketId, 'presence-room:42', ctx)\n\n// Broadcast to all subscribers\nchannels.broadcast('presence-room:42', 'new-message', { text: 'Hello!' })\n\n// Get online members\nconst members = channels.getMembers('presence-room:42')\n```\n\nChannel types: `public-*` (anyone), `private-*` (authorized), `presence-*` (auth + member tracking).\n\n---\n\n## Proxy Suite\n\nFull proxy toolkit built into Raffel — no extra dependencies.\n\n### HTTP Forward Proxy\n\n```typescript\nimport { createHttpForwardProxy } from 'raffel'\n\nconst proxy = createHttpForwardProxy({\n  auth: { credentials: { username: 'admin', password: 'secret' } },\n  filter: {\n    allowHosts: ['*.trusted.com', 'api.internal'],\n    denyHosts: ['*.evil.com'],\n  },\n  onRequest: (req) =\u003e { /* log or modify */ return req },\n})\n\nproxy.attachTo(httpServer)\n```\n\n### CONNECT Tunnel (with MITM)\n\n```typescript\nimport { createConnectTunnel } from 'raffel'\n\n// Plain CONNECT tunnel\nconst tunnel = createConnectTunnel({ mode: 'forward' })\n\n// MITM: inspect and modify HTTPS traffic\nconst mitm = createConnectTunnel({\n  mode: 'mitm',\n  onRequest: (req) =\u003e {\n    req.headers['x-intercepted'] = 'true'\n    return req\n  },\n  onResponse: (res) =\u003e {\n    res.headers['x-inspected'] = 'true'\n    return res\n  },\n  onUpstreamCert: (cert) =\u003e trustedCerts.has(cert.fingerprint),  // cert pinning\n})\n```\n\n### Unified Proxy Middleware\n\n```typescript\nimport { createProxySuite } from 'raffel'\n\nconst suite = createProxySuite({\n  explicit: {\n    port: 8080,\n    middleware: [\n      async (ctx, next) =\u003e {\n        if (ctx.kind === 'http-request' || ctx.kind === 'mitm-request') {\n          ctx.request.headers['x-raffel-policy'] = 'edge-a'\n        }\n\n        if (ctx.kind === 'connect' \u0026\u0026 ctx.target.host.endsWith('.blocked.internal')) {\n          ctx.blocked = { statusCode: 403, reason: 'blocked by policy' }\n          return\n        }\n\n        if (ctx.kind === 'upgrade-request' \u0026\u0026 ctx.target.host === 'ws.internal.local') {\n          ctx.target.port = 4102\n        }\n\n        await next()\n      },\n    ],\n    tunnel: { mode: 'mitm' },\n  },\n  socks5: {\n    port: 1080,\n    middleware: [\n      async (ctx, next) =\u003e {\n        if (ctx.kind === 'socks5-connect' \u0026\u0026 ctx.target.host === 'db.internal') {\n          ctx.target.host = 'db-replica.internal'\n        }\n        await next()\n      },\n    ],\n  },\n})\n```\n\nOne middleware model now spans reverse, explicit, MITM, SOCKS5/SOCKS5h, and transparent flows.\nUse it to inspect, block, rewrite destinations, shape headers, and attach policy logic only where configured.\n\n### Explicit Proxy Server\n\n```typescript\nimport { createExplicitProxy } from 'raffel'\n\nconst proxy = createExplicitProxy({\n  port: 8080,\n  auth: { credentials: { username: 'admin', password: 'secret' } },\n  tunnel: { mode: 'forward' },\n  telemetry: {\n    sourceHeader: 'x-service-name',\n    metricsEndpoint: '/metrics',\n    graphEndpoint: '/proxy/graph',\n    defaultLabels: { proxy: 'mesh-edge-a' },\n    percentiles: [0.5, 0.9, 0.95],\n  },\n})\n\nawait proxy.start()\n\n// Prometheus: GET http://127.0.0.1:8080/metrics\n// Graph JSON: GET http://127.0.0.1:8080/proxy/graph\n// Programmatic: proxy.graphSnapshot()\n// Edge latency: snapshot.edges[0].latency.percentiles.p95\n```\n\n### SOCKS5 Proxy\n\n```typescript\nimport { createSocks5Proxy } from 'raffel'\n\nconst socks5 = createSocks5Proxy({\n  port: 1080,\n  auth: { credentials: { username: 'alice', password: 'secret' } },\n  telemetry: {\n    defaultLabels: { proxy: 'mesh-socks' },\n  },\n})\nawait socks5.start()\n\n// Supports CONNECT, BIND, and UDP ASSOCIATE.\n// SOCKS5h is supported by sending hostnames (ATYP 0x03).\n// Telemetry protocols: socks5, socks5h, socks5-bind, socks5h-bind, socks5-udp, socks5h-udp.\n```\n\n### Unified HTTP + HTTPS + SOCKS5h Suite\n\n```typescript\nimport { createProxySuite } from 'raffel'\n\nconst suite = createProxySuite({\n  explicit: {\n    port: 8080,\n    tunnel: { mode: 'forward' }, // HTTPS via CONNECT\n  },\n  socks5: {\n    port: 1080,\n    auth: { credentials: { username: 'svc-billing', password: 'secret' } },\n  },\n  telemetry: {\n    sourceHeader: 'x-service-name',\n    metricsEndpoint: '/metrics',\n    graphEndpoint: '/proxy/graph',\n    percentiles: [0.5, 0.9, 0.95],\n    defaultLabels: { proxy: 'mesh-gateway' },\n  },\n})\n\nawait suite.start()\n\n// Shared graph across HTTP, HTTPS/CONNECT, and SOCKS5 CONNECT/BIND/UDP:\n// GET http://127.0.0.1:8080/proxy/graph\n// Shared Prometheus metrics:\n// GET http://127.0.0.1:8080/metrics\n```\n\n### Transparent Proxy (Linux TPROXY)\n\n```typescript\nimport { createTransparentProxy } from 'raffel'\n\nconst proxy = createTransparentProxy({\n  mode: 'tproxy',\n  port: 8080,\n})\n\nawait proxy.start()\n```\n\n---\n\n## Session Store\n\n```typescript\nimport { createSessionInterceptor, createRedisSessionDriver } from 'raffel'\n\nconst sessions = createSessionInterceptor({\n  driver: createRedisSessionDriver({ client: redis }),\n  cookie: { name: 'sid', httpOnly: true, secure: true, sameSite: 'lax' },\n  ttl: 86400,\n})\n\nserver.use(sessions)\n\nserver.procedure('auth.me').handler(async (_, ctx) =\u003e {\n  // ctx.session is loaded lazily, saved automatically\n  const { userId } = ctx.session.get()\n  return db.users.findById(userId)\n})\n```\n\nDrivers: `createMemorySessionDriver()`, `createRedisSessionDriver({ client })`.\n\n---\n\n## OpenAPI + Docs UI\n\n```typescript\nimport { mountOpenApiDocs } from 'raffel'\n\nserver.enableUSD({\n  info: { title: 'My API', version: '1.0.0' },\n})\n\nconst spec = server.getOpenAPIDocument()\nif (!spec) throw new Error('OpenAPI document is not available')\n\n// Mount /openapi.json + /docs (ReDoc or Swagger UI)\nmountOpenApiDocs(app, {\n  spec,\n  ui: 'redoc',       // or 'swagger'\n  path: '/docs',\n})\n```\n\n---\n\n## Metrics \u0026 Tracing\n\n### Prometheus Metrics\n\n```typescript\nimport { createMetricRegistry, createMetricsInterceptor, exportPrometheus } from 'raffel'\n\nconst metrics = createMetricRegistry()\n\nserver.use(createMetricsInterceptor({ registry: metrics }))\n\n// Expose /metrics endpoint\napp.get('/metrics', (c) =\u003e c.text(exportPrometheus(metrics), 200, {\n  'Content-Type': 'text/plain; version=0.0.4',\n}))\n```\n\n### OpenTelemetry Tracing\n\n```typescript\nimport { createTracer, createTracingInterceptor, createJaegerExporter } from 'raffel'\n\nconst tracer = createTracer({\n  serviceName: 'my-api',\n  exporter: createJaegerExporter({ endpoint: 'http://jaeger:14268/api/traces' }),\n  sampler: createProbabilitySampler(0.1),  // 10% sampling\n})\n\nserver.use(createTracingInterceptor({ tracer }))\n```\n\n---\n\n## Health Checks\n\n```typescript\nimport { createHealthCheckProcedures, CommonProbes } from 'raffel'\n\nconst health = createHealthCheckProcedures({\n  probes: [\n    CommonProbes.memory({ maxHeapMb: 512 }),\n    CommonProbes.uptime(),\n    {\n      name: 'database',\n      check: async () =\u003e {\n        await db.ping()\n        return { status: 'healthy' }\n      },\n    },\n  ],\n})\n\nserver.mount('/', health)\n// Registers: health.live, health.ready, health.startup\n```\n\n---\n\n## Connection Filters\n\nControl who can connect to your TCP, UDP, and WebSocket adapters.\n\n```typescript\nimport { createTcpAdapter } from 'raffel'\n\nconst tcp = createTcpAdapter(router, {\n  connectionFilter: {\n    allowHosts: ['10.0.0.*', 'trusted.internal'],\n    denyHosts: ['*.untrusted.net'],\n    onDenied: (host, port) =\u003e logger.warn(`Blocked connection from ${host}:${port}`),\n  },\n})\n```\n\nWebSocket adds origin filtering:\n\n```typescript\nconst ws = createWebSocketAdapter(router, {\n  connectionFilter: {\n    allowOrigins: ['https://app.example.com'],\n    denyOrigins: ['*'],\n  },\n})\n```\n\n---\n\n## Single-Port Multi-Protocol\n\nRun HTTP, WebSocket, gRPC, and gRPC-Web all on the same port. Raffel sniffs the protocol from the first bytes.\n\n```typescript\nconst server = createServer({\n  port: 3000,\n  singlePort: {\n    http: true,\n    websocket: true,\n    grpc: true,\n    grpcWeb: true,\n  },\n})\n```\n\n---\n\n## File-Based Routing\n\nDrop files into a directory. Raffel discovers and registers them automatically.\n\n```\nroutes/\n  users/\n    index.ts      → GET /users\n    [id].ts       → GET /users/:id\n    [id]/posts.ts → GET /users/:id/posts\n  tcp/\n    echo.ts       → TCP handler \"echo\"\n  udp/\n    ping.ts       → UDP handler \"ping\"\n```\n\n```typescript\nconst server = createServer({\n  port: 3000,\n  discovery: { dir: './routes', watch: true },  // hot-reload in dev\n})\n```\n\n---\n\n## Testing Mocks\n\nA complete mock infrastructure for integration tests — no external services needed.\n\n```typescript\nimport { MockServiceSuite } from 'raffel'\n\nconst suite = new MockServiceSuite()\nawait suite.start()\n\nconst { http, ws, tcp, udp, dns, sse, proxy } = suite\n\n// HTTP mock with request recording\nhttp.onGet('/users', { body: [{ id: '1' }] })\nconst requests = await http.waitForRequests(1)\n\n// WebSocket mock with pattern responses\nws.setResponse(/ping/, 'pong')\nws.dropRate = 0.1  // simulate 10% packet loss\n\n// DNS mock\ndns.addRecord('api.example.com', 'A', '127.0.0.1')\n\n// SSE mock\nsse.emit('data', { event: 'update', data: '{\"count\":42}' })\n\nawait suite.stop()\n```\n\n| Mock | Features |\n|------|---------|\n| `MockHttpServer` | CORS, global delay, streaming, `times`, statistics |\n| `MockWebSocketServer` | Pattern responses, drop rate, max connections, auto-close |\n| `MockTcpServer` | Echo + custom handlers |\n| `MockUdpServer` | UDP responder |\n| `MockDnsServer` | DNS over UDP (RFC 1035), no deps |\n| `MockSSEServer` | Server-Sent Events |\n| `MockProxyServer` | HTTP forward + MITM with hooks |\n\n---\n\n## Spec-Driven Mock Server\n\nYou can also stand up mock endpoints directly from OpenAPI or USD documents:\n\n```typescript\nimport { createMockServer } from 'raffel'\n\nconst openapi = server.getOpenAPIDocument()\nif (!openapi) throw new Error('OpenAPI document is not available')\n\nawait createMockServer({\n  spec: openapi,\n  port: 4100,\n})\n```\n\nThis gives you:\n\n- HTTP routes extracted from documented endpoints\n- example-first responses with schema-generated fallback data\n- request validation from the same contract\n- optional JSON-RPC and WebSocket mocks when the source document is USD\n\nIt is useful for frontend handoff, local integration tests, and spec-first\ndevelopment.\n\n---\n\n## Validation\n\nBring your own validator. Raffel adapts to it.\n\n```typescript\nimport { registerValidator, createZodAdapter } from 'raffel'\nimport { z } from 'zod'\n\nregisterValidator(createZodAdapter(z))\n\nserver\n  .procedure('users.create')\n  .input(z.object({ name: z.string().min(2), email: z.string().email() }))\n  .handler(async (input) =\u003e db.users.create(input))\n```\n\nAdapters available: `createZodAdapter`, `createYupAdapter`, `createJoiAdapter`, `createAjvAdapter`, `createFastestValidatorAdapter`.\n\n---\n\n## MCP Server (AI Integration)\n\nRaffel ships an MCP server for AI-assisted development. It gives tools like Claude direct knowledge of your API.\n\n```bash\n# Add to Claude Code\nclaude mcp add raffel npx raffel-mcp\n\n# Or run directly\nnpx raffel-mcp\n```\n\nProvides: live documentation, code generation prompts (`add_oauth2`, `add_sessions`, etc.), and pattern guidance.\n\n---\n\n## Migrating an Existing HTTP App\n\nRaffel can front an existing HTTP application model, but its goal is bigger than\nHTTP parity. Migrate by mapping routes, middleware, validation, and lifecycle\nconcepts into Raffel's runtime model, then reuse the same contracts across other\ntransports.\n\nSee the [migration guide](./docs/migration/frameworks.md) for concept mapping from\nExpress, Fastify, Fetch-first routers, `ws`, and Socket.IO.\n\n---\n\n## Documentation\n\n| Topic | Description |\n|-------|-------------|\n| [Quick Start](https://forattini-dev.github.io/raffel/#/quickstart) | 5-minute guide |\n| [HTTP Guide](https://forattini-dev.github.io/raffel/#/protocols/http) | REST, middleware, routing, serve() |\n| [Authentication](https://forattini-dev.github.io/raffel/#/auth/overview) | JWT, API Key, OAuth2, OIDC, Sessions |\n| [Interceptors](https://forattini-dev.github.io/raffel/#/interceptors) | Rate limit, circuit breaker, cache, etc. |\n| [WebSocket](https://forattini-dev.github.io/raffel/#/protocols/websocket) | Real-time, channels, presence |\n| [Proxy Suite](https://forattini-dev.github.io/raffel/#/proxy) | Forward, CONNECT, SOCKS5, transparent |\n| [Metrics \u0026 Tracing](https://forattini-dev.github.io/raffel/#/observability) | Prometheus, OpenTelemetry |\n| [Core Model](https://forattini-dev.github.io/raffel/#/core-model) | Envelope, Context, Router, architecture |\n| [File-based Routing](https://forattini-dev.github.io/raffel/#/file-system-discovery) | Zero-config discovery |\n| [Migration Guide](./docs/migration/frameworks.md) | Concept mapping from existing HTTP and realtime stacks |\n\n---\n\n## License\n\nISC\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**[Documentation](https://forattini-dev.github.io/raffel)** · **[GitHub](https://github.com/tetis-io/raffel)** · **[npm](https://www.npmjs.com/package/raffel)**\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforattini-dev%2Fraffel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fforattini-dev%2Fraffel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforattini-dev%2Fraffel/lists"}