@openstatus/health-neon 0.1.4-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # @openstatus/health-neon
2
+
3
+ [Neon](https://neon.com/) serverless Postgres probe for
4
+ [`@openstatus/health`](https://jsr.io/@openstatus/health). Runs `select 1`
5
+ through [`@neondatabase/serverless`](https://github.com/neondatabase/serverless)
6
+ — the HTTP `neon()` driver or the WebSocket `Pool` / `Client` — and fails the
7
+ check when the round trip does.
8
+
9
+ ```sh
10
+ deno add jsr:@openstatus/health jsr:@openstatus/health-neon
11
+ npm install @openstatus/health @openstatus/health-neon
12
+ ```
13
+
14
+ ```ts
15
+ import { neon } from "@neondatabase/serverless";
16
+ import { createHealthHandler } from "@openstatus/health";
17
+ import { neonProbe } from "@openstatus/health-neon";
18
+
19
+ const sql = neon(env.DATABASE_URL);
20
+
21
+ Deno.serve(
22
+ createHealthHandler({ probes: [neonProbe({ client: sql })] }),
23
+ );
24
+ ```
25
+
26
+ The HTTP driver is the best fit for a health endpoint: every probe is one
27
+ stateless `fetch`, nothing stays open between requests, and it runs on edge
28
+ runtimes; the probe's `AbortSignal` is passed as `fetchOptions.signal`, so
29
+ a `timeoutMs` cancels the request in flight. `Pool` and `Client` work the
30
+ same way — the probe calls `client.query("select 1")` on whichever you
31
+ pass — but their `query()` takes no signal, so a timed-out query runs to
32
+ completion on the connection. On a scale-to-zero branch
33
+ the first probe after idle also pays the compute wake-up, so give it a
34
+ `timeoutMs` that allows for it or point the probe at a branch that stays
35
+ warm.
36
+
37
+ ```ts
38
+ neonProbe({
39
+ client: sql,
40
+ // optional overrides from the Probe contract
41
+ name: "primary",
42
+ critical: false,
43
+ timeoutMs: 3000,
44
+ skip: () => env.DATABASE_URL == null,
45
+ });
46
+ ```
47
+
48
+ Critical by default: a Postgres that does not answer usually means requests
49
+ cannot be served, so the report turns `unhealthy` and the instance is taken
50
+ out of rotation. Set `critical: false` for a read replica or a branch that
51
+ only serves reporting.
52
+
53
+ The client is typed structurally as `{ query(text, params?, options?) }`, so
54
+ `@neondatabase/serverless` is an optional peer dependency for its types only
55
+ and the probe adds no runtime import of it. It needs `1.0.0` or newer, where
56
+ `neon()`'s `sql.query()` became a plain function call. The factory throws
57
+ `ProbeConfigError` at construction when the client has no `query()`.
58
+
59
+ ## About openstatus
60
+
61
+ [openstatus](https://www.openstatus.dev/) is the open-source uptime monitoring
62
+ and status page platform. This package is part of
63
+ [`@openstatus/health`](https://github.com/openstatusHQ/health), the `/health`
64
+ endpoints behind openstatus's own services, extracted so any JavaScript server
65
+ can expose one. Point an
66
+ [openstatus monitor](https://www.openstatus.dev/docs/reference/http-monitor)
67
+ at the endpoint and assert on `status` in the body to be alerted on
68
+ `degraded` before it becomes `unhealthy`.
69
+
70
+ Source: [github.com/openstatusHQ/health](https://github.com/openstatusHQ/health).
71
+ Issues and PRs welcome.
72
+
73
+ ## License
74
+
75
+ [MIT](https://github.com/openstatusHQ/health/blob/main/LICENSE)
@@ -0,0 +1,30 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+
25
+ Object.defineProperty(exports, '__toESM', {
26
+ enumerable: true,
27
+ get: function () {
28
+ return __toESM;
29
+ }
30
+ });
package/dist/mod.cjs ADDED
@@ -0,0 +1,35 @@
1
+ const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
+ const __openstatus_health = require_rolldown_runtime.__toESM(require("@openstatus/health"));
3
+
4
+ //#region src/mod.ts
5
+ /** Probe name when `name` is unset. */
6
+ const neonDefaultName = "database";
7
+ /** A probe that runs `select 1`; critical by default. The HTTP driver from `neon()` receives the probe's `AbortSignal` through `fetchOptions`; `Pool` / `Client` take no signal. Throws `ProbeConfigError` without `query()`. */
8
+ function neonProbe(options) {
9
+ const client = options.client;
10
+ if (typeof client?.query !== "function") throw new __openstatus_health.ProbeConfigError("neonProbe", "client", `must expose query(), got ${describe(client)}`);
11
+ const httpDriver = isCallable(client);
12
+ return {
13
+ name: options.name ?? neonDefaultName,
14
+ critical: options.critical ?? true,
15
+ timeoutMs: options.timeoutMs,
16
+ skip: options.skip,
17
+ run: async (signal) => {
18
+ if (httpDriver) await client.query("select 1", [], { fetchOptions: { signal } });
19
+ else await client.query("select 1");
20
+ }
21
+ };
22
+ }
23
+ function isCallable(client) {
24
+ return typeof client === "function";
25
+ }
26
+ function describe(client) {
27
+ if (client == null) return String(client);
28
+ if (typeof client !== "object" && typeof client !== "function") return typeof client;
29
+ const keys = Object.keys(client);
30
+ return keys.length === 0 ? `${typeof client === "function" ? "a function" : "an object"} with no keys` : `an object with keys ${keys.slice(0, 8).join(", ")}`;
31
+ }
32
+
33
+ //#endregion
34
+ exports.neonDefaultName = neonDefaultName;
35
+ exports.neonProbe = neonProbe;
package/dist/mod.d.cts ADDED
@@ -0,0 +1,29 @@
1
+ import { Probe, ProbeOverrides, ProbeResult } from "@openstatus/health";
2
+
3
+ //#region src/mod.d.ts
4
+
5
+ /** Probe name when `name` is unset. */
6
+ declare const neonDefaultName = "database";
7
+ /** What the probe passes to the HTTP driver's `query()` after the statement. */
8
+ interface NeonQueryOptions {
9
+ /** Merged into the `fetch` call; carries the probe's `AbortSignal`. */
10
+ readonly fetchOptions?: {
11
+ readonly signal?: AbortSignal;
12
+ };
13
+ }
14
+ /** The subset of `@neondatabase/serverless` the probe uses: `neon()`'s `sql.query()`, or `Pool` / `Client`. */
15
+ interface NeonLikeClient {
16
+ /** Run one statement; the HTTP driver also receives `params` and `options`. */
17
+ query(text: string, params?: never[], options?: NeonQueryOptions): PromiseLike<ProbeResult>;
18
+ }
19
+ /** Options for `neonProbe()`. */
20
+ interface NeonProbeOptions extends ProbeOverrides {
21
+ /** The `sql` function from `neon()`, or a `Pool` / `Client`. */
22
+ readonly client: NeonLikeClient;
23
+ }
24
+ /** A probe that runs `select 1`; critical by default. The HTTP driver from `neon()` receives the probe's `AbortSignal` through `fetchOptions`; `Pool` / `Client` take no signal. Throws `ProbeConfigError` without `query()`. */
25
+ declare function neonProbe(options: NeonProbeOptions): Probe;
26
+ //# sourceMappingURL=mod.d.ts.map
27
+ //#endregion
28
+ export { NeonLikeClient, NeonProbeOptions, NeonQueryOptions, neonDefaultName, neonProbe };
29
+ //# sourceMappingURL=mod.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.cts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;AAyCwD,cAnB3C,eAAA,GAmB2C,UAAA;AAMxD;AAAyB,UAtBR,gBAAA,CAsBQ;EAAA;EAA0B,SAAG,YAAA,CAAA,EAAA;IAAK,SAAA,MAAA,CAAA,EApBb,WAoBa;;;;UAhB1C,cAAA;;kDAKH,mBACT,YAAY;;;UAIA,gBAAA,SAAyB;;mBAEvB;;;iBAIH,SAAA,UAAmB,mBAAmB"}
package/dist/mod.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ import { Probe, ProbeOverrides, ProbeResult } from "@openstatus/health";
2
+
3
+ //#region src/mod.d.ts
4
+
5
+ /** Probe name when `name` is unset. */
6
+ declare const neonDefaultName = "database";
7
+ /** What the probe passes to the HTTP driver's `query()` after the statement. */
8
+ interface NeonQueryOptions {
9
+ /** Merged into the `fetch` call; carries the probe's `AbortSignal`. */
10
+ readonly fetchOptions?: {
11
+ readonly signal?: AbortSignal;
12
+ };
13
+ }
14
+ /** The subset of `@neondatabase/serverless` the probe uses: `neon()`'s `sql.query()`, or `Pool` / `Client`. */
15
+ interface NeonLikeClient {
16
+ /** Run one statement; the HTTP driver also receives `params` and `options`. */
17
+ query(text: string, params?: never[], options?: NeonQueryOptions): PromiseLike<ProbeResult>;
18
+ }
19
+ /** Options for `neonProbe()`. */
20
+ interface NeonProbeOptions extends ProbeOverrides {
21
+ /** The `sql` function from `neon()`, or a `Pool` / `Client`. */
22
+ readonly client: NeonLikeClient;
23
+ }
24
+ /** A probe that runs `select 1`; critical by default. The HTTP driver from `neon()` receives the probe's `AbortSignal` through `fetchOptions`; `Pool` / `Client` take no signal. Throws `ProbeConfigError` without `query()`. */
25
+ declare function neonProbe(options: NeonProbeOptions): Probe;
26
+ //# sourceMappingURL=mod.d.ts.map
27
+ //#endregion
28
+ export { NeonLikeClient, NeonProbeOptions, NeonQueryOptions, neonDefaultName, neonProbe };
29
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;AAyCwD,cAnB3C,eAAA,GAmB2C,UAAA;AAMxD;AAAyB,UAtBR,gBAAA,CAsBQ;EAAA;EAA0B,SAAG,YAAA,CAAA,EAAA;IAAK,SAAA,MAAA,CAAA,EApBb,WAoBa;;;;UAhB1C,cAAA;;kDAKH,mBACT,YAAY;;;UAIA,gBAAA,SAAyB;;mBAEvB;;;iBAIH,SAAA,UAAmB,mBAAmB"}
package/dist/mod.js ADDED
@@ -0,0 +1,34 @@
1
+ import { ProbeConfigError } from "@openstatus/health";
2
+
3
+ //#region src/mod.ts
4
+ /** Probe name when `name` is unset. */
5
+ const neonDefaultName = "database";
6
+ /** A probe that runs `select 1`; critical by default. The HTTP driver from `neon()` receives the probe's `AbortSignal` through `fetchOptions`; `Pool` / `Client` take no signal. Throws `ProbeConfigError` without `query()`. */
7
+ function neonProbe(options) {
8
+ const client = options.client;
9
+ if (typeof client?.query !== "function") throw new ProbeConfigError("neonProbe", "client", `must expose query(), got ${describe(client)}`);
10
+ const httpDriver = isCallable(client);
11
+ return {
12
+ name: options.name ?? neonDefaultName,
13
+ critical: options.critical ?? true,
14
+ timeoutMs: options.timeoutMs,
15
+ skip: options.skip,
16
+ run: async (signal) => {
17
+ if (httpDriver) await client.query("select 1", [], { fetchOptions: { signal } });
18
+ else await client.query("select 1");
19
+ }
20
+ };
21
+ }
22
+ function isCallable(client) {
23
+ return typeof client === "function";
24
+ }
25
+ function describe(client) {
26
+ if (client == null) return String(client);
27
+ if (typeof client !== "object" && typeof client !== "function") return typeof client;
28
+ const keys = Object.keys(client);
29
+ return keys.length === 0 ? `${typeof client === "function" ? "a function" : "an object"} with no keys` : `an object with keys ${keys.slice(0, 8).join(", ")}`;
30
+ }
31
+
32
+ //#endregion
33
+ export { neonDefaultName, neonProbe };
34
+ //# sourceMappingURL=mod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.js","names":["options: NeonProbeOptions","client: object","client: NeonLikeClient"],"sources":["../src/mod.ts"],"sourcesContent":["/**\n * Neon serverless Postgres probe for `@openstatus/health`: runs `select 1`\n * over the HTTP driver, or a `Pool` / `Client`, from `@neondatabase/serverless`.\n *\n * ```ts\n * import { neon } from \"@neondatabase/serverless\";\n * import { neonProbe } from \"@openstatus/health-neon\";\n *\n * const probe = neonProbe({ client: neon(env.DATABASE_URL) });\n * ```\n *\n * @module\n */\n\nimport {\n type Probe,\n ProbeConfigError,\n type ProbeOverrides,\n type ProbeResult,\n} from \"@openstatus/health\";\n\n/** Probe name when `name` is unset. */\nexport const neonDefaultName = \"database\";\n\n/** What the probe passes to the HTTP driver's `query()` after the statement. */\nexport interface NeonQueryOptions {\n /** Merged into the `fetch` call; carries the probe's `AbortSignal`. */\n readonly fetchOptions?: { readonly signal?: AbortSignal };\n}\n\n/** The subset of `@neondatabase/serverless` the probe uses: `neon()`'s `sql.query()`, or `Pool` / `Client`. */\nexport interface NeonLikeClient {\n /** Run one statement; the HTTP driver also receives `params` and `options`. */\n query(\n text: string,\n params?: never[],\n options?: NeonQueryOptions,\n ): PromiseLike<ProbeResult>;\n}\n\n/** Options for `neonProbe()`. */\nexport interface NeonProbeOptions extends ProbeOverrides {\n /** The `sql` function from `neon()`, or a `Pool` / `Client`. */\n readonly client: NeonLikeClient;\n}\n\n/** A probe that runs `select 1`; critical by default. The HTTP driver from `neon()` receives the probe's `AbortSignal` through `fetchOptions`; `Pool` / `Client` take no signal. Throws `ProbeConfigError` without `query()`. */\nexport function neonProbe(options: NeonProbeOptions): Probe {\n const client = options.client;\n if (typeof client?.query !== \"function\") {\n throw new ProbeConfigError(\n \"neonProbe\",\n \"client\",\n `must expose query(), got ${describe(client)}`,\n );\n }\n const httpDriver = isCallable(client);\n return {\n name: options.name ?? neonDefaultName,\n critical: options.critical ?? true,\n timeoutMs: options.timeoutMs,\n skip: options.skip,\n run: async (signal) => {\n if (httpDriver) {\n await client.query(\"select 1\", [], { fetchOptions: { signal } });\n } else {\n await client.query(\"select 1\");\n }\n },\n };\n}\n\nfunction isCallable(client: object): boolean {\n return typeof client === \"function\";\n}\n\nfunction describe(client: NeonLikeClient): string {\n if (client == null) return String(client);\n if (typeof client !== \"object\" && typeof client !== \"function\") {\n return typeof client;\n }\n const keys = Object.keys(client);\n return keys.length === 0\n ? `${\n typeof client === \"function\" ? \"a function\" : \"an object\"\n } with no keys`\n : `an object with keys ${keys.slice(0, 8).join(\", \")}`;\n}\n"],"mappings":";;;;AAsBA,MAAa,kBAAkB;;AAyB/B,SAAgB,UAAUA,SAAkC;CAC1D,MAAM,SAAS,QAAQ;AACvB,YAAW,QAAQ,UAAU,WAC3B,OAAM,IAAI,iBACR,aACA,WACC,2BAA2B,SAAS,OAAO,CAAC;CAGjD,MAAM,aAAa,WAAW,OAAO;AACrC,QAAO;EACL,MAAM,QAAQ,QAAQ;EACtB,UAAU,QAAQ,YAAY;EAC9B,WAAW,QAAQ;EACnB,MAAM,QAAQ;EACd,KAAK,OAAO,WAAW;AACrB,OAAI,WACF,OAAM,OAAO,MAAM,YAAY,CAAE,GAAE,EAAE,cAAc,EAAE,OAAQ,EAAE,EAAC;OAEhE,OAAM,OAAO,MAAM,WAAW;EAEjC;CACF;AACF;AAED,SAAS,WAAWC,QAAyB;AAC3C,eAAc,WAAW;AAC1B;AAED,SAAS,SAASC,QAAgC;AAChD,KAAI,UAAU,KAAM,QAAO,OAAO,OAAO;AACzC,YAAW,WAAW,mBAAmB,WAAW,WAClD,eAAc;CAEhB,MAAM,OAAO,OAAO,KAAK,OAAO;AAChC,QAAO,KAAK,WAAW,KAClB,SACM,WAAW,aAAa,eAAe,YAC/C,kBACE,sBAAsB,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,CAAC;AACxD"}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@openstatus/health-neon",
3
+ "version": "0.1.4-dev.0",
4
+ "description": "Neon serverless Postgres probe for @openstatus/health",
5
+ "keywords": [
6
+ "openstatus",
7
+ "health",
8
+ "healthcheck",
9
+ "neon",
10
+ "postgres",
11
+ "serverless",
12
+ "database"
13
+ ],
14
+ "license": "MIT",
15
+ "author": {
16
+ "name": "openstatus",
17
+ "url": "https://www.openstatus.dev/"
18
+ },
19
+ "homepage": "https://github.com/openstatusHQ/health",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/openstatusHQ/health.git",
23
+ "directory": "packages/neon/"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/openstatusHQ/health/issues"
27
+ },
28
+ "type": "module",
29
+ "module": "./dist/mod.js",
30
+ "main": "./dist/mod.cjs",
31
+ "types": "./dist/mod.d.ts",
32
+ "exports": {
33
+ ".": {
34
+ "types": {
35
+ "import": "./dist/mod.d.ts",
36
+ "require": "./dist/mod.d.cts"
37
+ },
38
+ "import": "./dist/mod.js",
39
+ "require": "./dist/mod.cjs"
40
+ },
41
+ "./package.json": "./package.json"
42
+ },
43
+ "sideEffects": false,
44
+ "files": [
45
+ "dist/"
46
+ ],
47
+ "engines": {
48
+ "node": ">=22"
49
+ },
50
+ "peerDependencies": {
51
+ "@openstatus/health": "^0.1.4-dev.0",
52
+ "@neondatabase/serverless": ">=1.0.0"
53
+ },
54
+ "peerDependenciesMeta": {
55
+ "@neondatabase/serverless": {
56
+ "optional": true
57
+ }
58
+ },
59
+ "devDependencies": {
60
+ "@neondatabase/serverless": "^1.0.0",
61
+ "tsdown": "^0.12.7",
62
+ "typescript": "^5.8.3"
63
+ },
64
+ "scripts": {
65
+ "build": "tsdown",
66
+ "prepack": "tsdown",
67
+ "test": "node --experimental-transform-types --test"
68
+ }
69
+ }