{"_id":"@coderatechmw/health-kit","name":"@coderatechmw/health-kit","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@coderatechmw/health-kit","version":"0.1.0","description":"Drop-in /api/health endpoint for Next.js apps. Reports Mongo, auth, storage and env status. Zero runtime dependencies.","keywords":["health-check","healthcheck","monitoring","uptime","observability","nextjs","vercel"],"license":"MIT","author":"coderatechmw","type":"module","sideEffects":false,"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./dependencies":{"types":"./dist/dependencies.d.ts","default":"./dist/dependencies.js"},"./package.json":"./package.json"},"publishConfig":{"access":"public"},"dependencies":{},"devDependencies":{"@types/node":"^24.10.1","typescript":"^6.0.3","vitest":"^4.1.10","@shm/contracts":"0.1.0"},"engines":{"node":">=18"},"scripts":{"build":"tsc -p tsconfig.build.json","typecheck":"tsc -p tsconfig.json --noEmit","test":"vitest run","test:watch":"vitest","clean":"node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\""},"_nodeVersion":"24.15.0","_id":"@coderatechmw/health-kit@0.1.0","dist":{"integrity":"sha512-6M3Cvx4v0kacodegmj2Y8v259UJzNjuBmEaaQer98kVw+9Rakr/fLTpk8oJr0ENRyaK0MI/HzyvLzs4r6S0Fvw==","shasum":"9a3086e5834cbf0de764de38d448c40ee6abfdf4","tarball":"https://registry.npmjs.org/@coderatechmw/health-kit/-/health-kit-0.1.0.tgz","fileCount":43,"unpackedSize":72130,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIC/XAVxnzAREroWJG9FZ8UMHNHahGrodvt4rwi4aLA/RAiEAnHr9PAiIW/GBt3cIDDakgk9mPhzwnoGwhUZW6KYavNA="}]},"_npmUser":{"name":"coderatechmw","email":"coderacorp@gmail.com"},"directories":{},"maintainers":[{"name":"coderatechmw","email":"coderacorp@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/health-kit_0.1.0_1786367303186_0.9294895577318207"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-10T13:08:22.875Z","0.1.0":"2026-08-10T13:08:23.339Z","modified":"2026-08-10T13:08:23.548Z"},"maintainers":[{"name":"coderatechmw","email":"coderacorp@gmail.com"}],"description":"Drop-in /api/health endpoint for Next.js apps. Reports Mongo, auth, storage and env status. Zero runtime dependencies.","keywords":["health-check","healthcheck","monitoring","uptime","observability","nextjs","vercel"],"author":"coderatechmw","license":"MIT","readme":"# @coderatechmw/health-kit\n\nA protected `/api/health` endpoint for your Next.js app, in about ten lines.\n\n**Zero runtime dependencies.** This package installs into every app you own, so it\npulls in nothing — not Zod, not the Mongo driver, not an AWS SDK. It uses only web\nstandards (`Request`, `Response`, `fetch`, `AbortController`, Web Crypto), which\nmeans it runs unchanged on the Node and Edge runtimes.\n\n## Install\n\n```bash\npnpm add @coderatechmw/health-kit\n```\n\n## Use\n\n```ts\n// app/api/health/route.ts\nimport { createHealthHandler, mongoCheck, clerkCheck, r2Check, envCheck } from \"@coderatechmw/health-kit\";\nimport clientPromise from \"@/lib/mongodb\";\n\nexport const GET = createHealthHandler({\n  service: \"my-app\",\n  checks: [\n    mongoCheck(() => clientPromise),\n    clerkCheck(),\n    r2Check(),\n    envCheck([\"MONGODB_URI\", \"CLERK_SECRET_KEY\", \"R2_ACCESS_KEY_ID\"]),\n  ],\n});\n\n// Health must never be served from cache.\nexport const dynamic = \"force-dynamic\";\n```\n\nThen set `HEALTH_TOKEN` in the app's environment to a long random string, and\nregister the same token in the monitor.\n\n```bash\nnode -e \"console.log(require('node:crypto').randomBytes(32).toString('base64url'))\"\n```\n\n## The two-tier response\n\nThe same URL answers differently depending on who is asking.\n\n**Anonymous** — up or not, and nothing else. External uptime probes use this, which\nis why it isn't a 401:\n\n```json\n{ \"schemaVersion\": 1, \"status\": \"healthy\", \"timestamp\": \"2026-08-09T20:00:00.000Z\" }\n```\n\n**With `Authorization: Bearer $HEALTH_TOKEN`** — the full picture:\n\n```json\n{\n  \"schemaVersion\": 1,\n  \"status\": \"degraded\",\n  \"service\": { \"name\": \"my-app\", \"commitSha\": \"a1b2c3d\", \"environment\": \"production\", \"region\": \"iad1\" },\n  \"uptimeSec\": 431.2,\n  \"timestamp\": \"2026-08-09T20:00:00.000Z\",\n  \"durationMs\": 84,\n  \"checks\": [\n    { \"name\": \"mongo\", \"status\": \"healthy\", \"durationMs\": 12, \"meta\": { \"latencyMs\": 11 } },\n    { \"name\": \"r2\", \"status\": \"unhealthy\", \"durationMs\": 3001, \"message\": \"check timed out after 3000ms\" }\n  ]\n}\n```\n\nWithout a token configured, the endpoint **fails closed** — nobody gets detail. A\nforgotten env var must never mean \"publish internals to the world\".\n\n## Status codes\n\n| App status  | HTTP | Why |\n|---|---|---|\n| `healthy`   | 200 | — |\n| `degraded`  | 200 | Still serving. A 503 would have the platform pull it from rotation over something that doesn't warrant it. |\n| `unhealthy` | 503 | Load balancers and external probes react correctly with no extra configuration. |\n\n## Built-in checks\n\n| Check | What it does |\n|---|---|\n| `mongoCheck(getClient)` | Pings the DB and reports latency. Pass your existing client promise so it exercises the **live pool** — a pool that has silently died is invisible to an external probe. |\n| `envCheck([...names])` | Verifies vars are present and non-empty. Reports names only, never values. |\n| `httpCheck({ name, url })` | Probes an outbound dependency from inside the app, so it uses the same egress path and region your real requests do. |\n| `clerkCheck()` · `r2Check()` · `cloudinaryCheck()` | Verify credentials are configured. Pass `probeUrl` to also make a real request. |\n| `customCheck(name, fn)` | Your own logic. Return nothing for healthy, throw for unhealthy. |\n\n### Critical vs. non-critical\n\nChecks are critical by default. Mark the ones your app survives without:\n\n```ts\ncustomCheck(\"analytics\", pingAnalytics, { critical: false })\n```\n\nA non-critical failure reports the app as `degraded` (HTTP 200, no page at 2am)\nwhile its own row still shows `unhealthy`, so the dashboard tells you the truth\nabout what broke.\n\n## Failure isolation\n\nEvery check runs under its own deadline (default 3s, `checkTimeoutMs` to change).\nThe check receives an `AbortSignal` — forward it to any `fetch` you make so the\nrequest is genuinely cancelled — and the result is additionally raced against a\ntimer, so a check that *ignores* the signal, or a driver call that simply never\nsettles, still cannot hold the response open. A hung dependency becomes a timeout\nrow, never a hung endpoint.\n\nErrors are reduced to `error.message`, truncated to 500 chars. Stacks are never\nincluded: they routinely contain absolute filesystem paths, and driver errors can\ncarry a connection string.\n\n## Contributing\n\n`src/conformance.test.ts` is the important file. This package deliberately defines\nits own types rather than importing `@shm/contracts` at runtime, so that test is\nwhat stops the two from drifting — it runs the real handler and validates the\noutput against the actual contract schema, boundary values included.\n\nIf you change the response shape, that test must change with it, and the contract\nneeds a new `schemaVersion` rather than an edit in place.\n","readmeFilename":"","_rev":"1-c8187f8804bd3a2d9a714d3506387b32"}