{"_id":"@boolean-packages/boolean-healthcheck-sdk","name":"@boolean-packages/boolean-healthcheck-sdk","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@boolean-packages/boolean-healthcheck-sdk","version":"0.1.0","description":"Framework-agnostic health-check SDK to expose /health (liveness + readiness) from Node apps","license":"MIT","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"scripts":{"build":"tsup","dev":"tsup --watch","prepare":"tsup","test":"vitest run","test:watch":"vitest","typecheck":"tsc --noEmit"},"peerDependencies":{"pg":"^8.0.0","ioredis":"^5.0.0","amqplib":"^0.10.0"},"peerDependenciesMeta":{"pg":{"optional":true},"ioredis":{"optional":true},"amqplib":{"optional":true}},"devDependencies":{"@types/node":"^20.11.0","msw":"^2.4.0","tsup":"^8.2.0","typescript":"^5.5.0","vitest":"^2.0.0"},"_id":"@boolean-packages/boolean-healthcheck-sdk@0.1.0","gitHead":"c26ef0eb0a1c0c3b2b42fd870cf73092bfa1f0cd","_nodeVersion":"24.4.1","_npmVersion":"11.4.2","dist":{"integrity":"sha512-v9sXvrl8DdoCNQf42IICgbG3KJY+J3tDWdl5xu541jn4CLLV3m3qSuG2PziOQWxEzjNMYD7edOPofQrR1O5ngA==","shasum":"a1d3d6f19482805c8631ae4ce52bd4aa0c9ab964","tarball":"https://registry.npmjs.org/@boolean-packages/boolean-healthcheck-sdk/-/boolean-healthcheck-sdk-0.1.0.tgz","fileCount":9,"unpackedSize":103245,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCmpw1F9y+ghAAcXJIjBEJa+mt+afAUyHe7QIN5AnrZywIhAJZJFAeIOgkYR2IPnCu9bOyG26FMo28stE+2Wtbzt9H2"}]},"_npmUser":{"name":"boolean-packages","email":"packages@boolean.com.ar"},"directories":{},"maintainers":[{"name":"boolean-packages","email":"packages@boolean.com.ar"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/boolean-healthcheck-sdk_0.1.0_1784332206383_0.35063124017089287"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-17T23:50:06.293Z","0.1.0":"2026-07-17T23:50:06.532Z","modified":"2026-07-17T23:50:06.683Z"},"maintainers":[{"name":"boolean-packages","email":"packages@boolean.com.ar"}],"description":"Framework-agnostic health-check SDK to expose /health (liveness + readiness) from Node apps","license":"MIT","readme":"# @boolean-packages/boolean-healthcheck-sdk (TypeScript) — Endpoint `/health` agnóstico\n\nSDK **de lado servidor** para que cualquier app Node (NestJS, Express, Fastify, server HTTP plano) exponga un endpoint `/health` robusto que combine **liveness** (\"estoy vivo\": proceso responde, disco/RAM ok) y **readiness** (\"puedo trabajar\": DB, Redis, RabbitMQ, APIs de terceros).\n\nEs **agnóstico del framework**: provee el motor de checks (`HealthRegistry`) y un handler puro (`createHealthHandler`) que montás donde quieras.\n\n```\nOrquestador (k8s, load balancer, uptime monitor) ──▶ GET /health ──▶ HealthRegistry ──▶ [DB, Redis, RabbitMQ, HTTP, disco, RAM]\n```\n\n## Instalación\n\n```bash\nnpm install @boolean-packages/boolean-healthcheck-sdk\n\n# Drivers opcionales — sólo los que tu app use (peerDependencies):\nnpm install pg        # postgresCheck({ connectionString })\nnpm install ioredis   # redisCheck({ url })\nnpm install amqplib   # rabbitmqCheck({ url })\n```\n\n> Importar el paquete **nunca** importa los drivers opcionales: se cargan con `import()` dinámico sólo cuando un check usa `connectionString`/`url`. Si el driver no está instalado, se lanza `MissingDriverError` con el comando de instalación. Si pasás un cliente/pool ya creado, el driver ni se importa.\n\n## Build, tests y typecheck\n\n```bash\ncd sdks/healthcheck-typescript\nnpm install\nnpm run typecheck\nnpm test\nnpm run build   # genera ESM + CJS + .d.ts en dist/\n```\n\n## Concepto\n\n- **`HealthRegistry`** — registra checks y los corre **en paralelo con timeout** (`Promise.race`, responde rápido y nunca cuelga). Cache TTL opcional para no golpear las dependencias en cada poll.\n- **`HealthCheck`** — `{ name, critical?, run() }`. `run()` devuelve un detalle o lanza/rechaza. Un check `critical` caído → **503 DOWN**; uno no-crítico caído → **200 DEGRADED**.\n- **`createHealthHandler`** — devuelve `(req?) => Promise<{ httpStatus, body }>`. Público devuelve `{ status: \"UP\" }`; el detalle por dependencia sólo se expone con API key / IP autorizada.\n\n## Uso básico\n\n```ts\nimport {\n  HealthRegistry,\n  createHealthHandler,\n  postgresCheck,\n  redisCheck,\n  rabbitmqCheck,\n  httpCheck,\n  diskSpaceCheck,\n} from \"@boolean-packages/boolean-healthcheck-sdk\";\n\nconst registry = new HealthRegistry({ timeoutMs: 2000, cacheTtlMs: 5000, version: \"1.4.0\" })\n  .register(diskSpaceCheck({ path: \"/\", minFreeRatio: 0.1 }))      // liveness\n  .register(postgresCheck({ pool }))                               // SELECT 1\n  .register(redisCheck({ client: redis, critical: false }))        // degrada, no tumba\n  .register(rabbitmqCheck({ connection: amqp }))\n  .register(httpCheck({ url: \"https://pagos.proveedor.com/ping\" })); // tercero crítico\n\nconst handler = createHealthHandler(registry, { detailApiKey: \"super-secreto\" });\n```\n\nLos checks reciben **clientes/pools/conexiones ya existentes** (no gestionan el pool). Como conveniencia también aceptan `connectionString`/`url` para una conexión efímera.\n\n## Montaje por framework (ejemplos, sin acoplamiento)\n\n### Express\n\n```ts\napp.get(\"/health\", async (req, res) => {\n  const { httpStatus, body } = await handler({ headers: req.headers, ip: req.ip });\n  res.status(httpStatus).json(body);\n});\n```\n\n### NestJS (controller)\n\n```ts\n@Controller(\"health\")\nexport class HealthController {\n  @Get()\n  async health(@Req() req: Request, @Res() res: Response) {\n    const { httpStatus, body } = await handler({ headers: req.headers, ip: req.ip });\n    res.status(httpStatus).json(body);\n  }\n}\n```\n\n### Server HTTP plano\n\n```ts\nimport { createServer } from \"node:http\";\n\ncreateServer(async (req, res) => {\n  if (req.url === \"/health\") {\n    const { httpStatus, body } = await handler({\n      headers: req.headers as Record<string, string>,\n      ip: req.socket.remoteAddress,\n    });\n    res.writeHead(httpStatus, { \"content-type\": \"application/json\" });\n    res.end(JSON.stringify(body));\n  }\n}).listen(3000);\n```\n\n## Códigos de estado\n\n| Situación                                     | `status`   | HTTP |\n|-----------------------------------------------|------------|------|\n| Todos los checks OK                           | `UP`        | 200  |\n| Sólo checks **no-críticos** caídos            | `DEGRADED`  | 200  |\n| Al menos un check **crítico** caído / timeout | `DOWN`      | 503  |\n\n## Respuesta\n\n**Pública** (sin autorización):\n\n```json\n{ \"status\": \"UP\" }\n```\n\n**Detallada** (con `x-health-key` válida o IP en `allowedIps`):\n\n```json\n{\n  \"status\": \"DEGRADED\",\n  \"checks\": [\n    { \"name\": \"postgres\", \"status\": \"UP\", \"latencyMs\": 1.4, \"critical\": true },\n    { \"name\": \"redis\", \"status\": \"DEGRADED\", \"latencyMs\": 2000, \"critical\": false,\n      \"detail\": \"Health check 'redis' timed out after 2000ms\" }\n  ],\n  \"version\": \"1.4.0\",\n  \"uptimeSeconds\": 3601.2\n}\n```\n\n## Seguridad del detalle\n\n```ts\nconst handler = createHealthHandler(registry, {\n  detailApiKey: \"super-secreto\",   // comparación en tiempo constante\n  detailHeader: \"x-health-key\",    // default\n  allowedIps: [\"10.0.0.0\", \"127.0.0.1\"],\n});\n```\n\nSin API key correcta ni IP autorizada, el handler devuelve sólo `{ status: ... }` — no revela qué dependencia falló.\n\n## Checks built-in\n\n| Check             | Driver (peer)      | Probe                                   |\n|-------------------|--------------------|-----------------------------------------|\n| `diskSpaceCheck`  | — (`fs.statfs`)    | espacio libre vs umbral                 |\n| `memoryCheck`     | — (`os`)           | `% memoria usada` vs umbral             |\n| `postgresCheck`   | `pg` (sólo con `connectionString`) | `SELECT 1`              |\n| `redisCheck`      | `ioredis` (sólo con `url`) | `PING`                          |\n| `rabbitmqCheck`   | `amqplib` (sólo con `url`) | abre y cierra un channel        |\n| `httpCheck`       | — (`fetch` nativo, Node 18+) | `GET` a URL, status 2xx       |\n\nCheck propio: pasá cualquier objeto `{ name, critical?, run() }` a `registry.register(...)`, o usá `registry.add(\"nombre\", async () => {...}, { critical })`.\n\n## Manejo de errores\n\nTodas las excepciones del SDK extienden `HealthSDKError`:\n\n| Error                | Contexto                                                  |\n|----------------------|-----------------------------------------------------------|\n| `MissingDriverError` | usás un check cuyo driver opcional no está instalado       |\n| `CheckTimeoutError`  | mensaje usado al reportar un check que excedió el timeout   |\n\nLas fallas de las dependencias **no se propagan**: se reflejan en `status`/`httpStatus` del reporte.\n\n## Exports del paquete\n\n```text\n@boolean-packages/boolean-healthcheck-sdk → HealthRegistry, createHealthHandler, checks built-in, tipos, errores\n```\n\n## Notas de despliegue\n\n- Usa `fetch` nativo (Node 18+) para `httpCheck`.\n- Los drivers de DB/cache/broker se cargan en runtime desde el `node_modules` de la app (marcados `external`), nunca se empaquetan en `dist/`.\n","readmeFilename":"README.md","_rev":"1-3cb7d5177425b81675289c5d867831b3"}