@open-operational-state/probe 0.2.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,74 @@
1
+ # @open-operational-state/probe
2
+
3
+ Probe any operational-state endpoint — fetch, detect, parse, and normalize in a single call.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@open-operational-state/probe)](https://www.npmjs.com/package/@open-operational-state/probe)
6
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](../../LICENSE)
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install @open-operational-state/probe
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```js
17
+ import { probe } from '@open-operational-state/probe';
18
+
19
+ const result = await probe( 'https://api.example.com/health' );
20
+
21
+ console.log( result.snapshot.condition ); // 'operational'
22
+ console.log( result.httpStatus ); // 200
23
+ console.log( result.validation.valid ); // true
24
+ ```
25
+
26
+ ### With discovery
27
+
28
+ ```js
29
+ const result = await probe( 'https://api.example.com', {
30
+ followDiscovery: true,
31
+ } );
32
+
33
+ // Follows Link headers or /.well-known/operational-state
34
+ // before probing the discovered endpoint
35
+ ```
36
+
37
+ ## API
38
+
39
+ ### `probe( url, options? )`
40
+
41
+ Returns a `ProbeResult`:
42
+
43
+ | Field | Type | Description |
44
+ |---|---|---|
45
+ | `url` | `string` | The URL that was probed |
46
+ | `httpStatus` | `number \| null` | HTTP status, or null on connection failure |
47
+ | `contentType` | `string \| null` | Content-Type header |
48
+ | `connectionError` | `boolean` | True if the connection itself failed |
49
+ | `snapshot` | `Snapshot` | Parsed and normalized core model |
50
+ | `validation` | `ValidationResult` | Core model validation result |
51
+ | `discovery` | `DiscoverResult \| null` | Discovery result (if enabled) |
52
+
53
+ ### Options
54
+
55
+ | Option | Type | Default | Description |
56
+ |---|---|---|---|
57
+ | `followDiscovery` | `boolean` | `false` | Follow OOS discovery before probing |
58
+ | `headers` | `Record<string, string>` | — | Custom request headers |
59
+ | `signal` | `AbortSignal` | — | Cancellation signal |
60
+
61
+ ## Architecture
62
+
63
+ `probe` sits above the lower-level packages and orchestrates them:
64
+
65
+ ```
66
+ probe → parser → core → types
67
+ → discovery → types
68
+ ```
69
+
70
+ This package is used by the `oos` CLI and is the recommended programmatic entrypoint for probing endpoints.
71
+
72
+ ## License
73
+
74
+ Licensed under [Apache 2.0](../../LICENSE).
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @open-operational-state/probe
3
+ *
4
+ * Probe any operational-state endpoint — fetch, detect, parse, normalize.
5
+ *
6
+ * Depends on @open-operational-state/types, core, parser, and discovery.
7
+ */
8
+ export { probe } from './probe.js';
9
+ export type { ProbeResult, ProbeOptions } from './probe.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @open-operational-state/probe
3
+ *
4
+ * Probe any operational-state endpoint — fetch, detect, parse, normalize.
5
+ *
6
+ * Depends on @open-operational-state/types, core, parser, and discovery.
7
+ */
8
+ export { probe } from './probe.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Probe — fetch, detect, parse, normalize an operational-state endpoint.
3
+ *
4
+ * This is the programmatic API. The CLI probe command delegates here.
5
+ */
6
+ import type { Snapshot, ValidationResult } from '@open-operational-state/types';
7
+ import type { DiscoverResult } from '@open-operational-state/discovery';
8
+ export interface ProbeOptions {
9
+ /** Follow OOS discovery (Link headers / well-known) before probing. */
10
+ followDiscovery?: boolean;
11
+ /** Custom headers to send with the probe request. */
12
+ headers?: Record<string, string>;
13
+ /** AbortSignal for cancellation. */
14
+ signal?: AbortSignal;
15
+ }
16
+ export interface ProbeResult {
17
+ /** The URL that was probed. */
18
+ url: string;
19
+ /** HTTP status code, or null if connection failed. */
20
+ httpStatus: number | null;
21
+ /** Content-Type header value. */
22
+ contentType: string | null;
23
+ /** True if the connection itself failed (DNS, timeout, etc.). */
24
+ connectionError: boolean;
25
+ /** The parsed and normalized Snapshot. */
26
+ snapshot: Snapshot;
27
+ /** Core-model validation result. */
28
+ validation: ValidationResult;
29
+ /** Discovery result, if followDiscovery was enabled. */
30
+ discovery: DiscoverResult | null;
31
+ }
32
+ /**
33
+ * Probe an operational-state endpoint.
34
+ *
35
+ * Fetches the URL, auto-detects the response format, parses to the canonical
36
+ * core model, normalizes, and validates.
37
+ *
38
+ * @example
39
+ * ```js
40
+ * import { probe } from '@open-operational-state/probe';
41
+ *
42
+ * const result = await probe( 'https://api.example.com/health' );
43
+ * console.log( result.snapshot.condition ); // 'operational'
44
+ * ```
45
+ */
46
+ export declare function probe(url: string, options?: ProbeOptions): Promise<ProbeResult>;
47
+ //# sourceMappingURL=probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../src/probe.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAIhF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAMxE,MAAM,WAAW,YAAY;IACzB,uEAAuE;IACvE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,oCAAoC;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IACxB,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,iCAAiC;IACjC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iEAAiE;IACjE,eAAe,EAAE,OAAO,CAAC;IACzB,0CAA0C;IAC1C,QAAQ,EAAE,QAAQ,CAAC;IACnB,oCAAoC;IACpC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,wDAAwD;IACxD,SAAS,EAAE,cAAc,GAAG,IAAI,CAAC;CACpC;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,KAAK,CAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAI,OAAO,CAAC,WAAW,CAAC,CA+FvF"}
package/dist/probe.js ADDED
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Probe — fetch, detect, parse, normalize an operational-state endpoint.
3
+ *
4
+ * This is the programmatic API. The CLI probe command delegates here.
5
+ */
6
+ import { normalizeSnapshot, validateSnapshot } from '@open-operational-state/core';
7
+ import { parse } from '@open-operational-state/parser';
8
+ import { discover } from '@open-operational-state/discovery';
9
+ // ---------------------------------------------------------------------------
10
+ // Public API
11
+ // ---------------------------------------------------------------------------
12
+ /**
13
+ * Probe an operational-state endpoint.
14
+ *
15
+ * Fetches the URL, auto-detects the response format, parses to the canonical
16
+ * core model, normalizes, and validates.
17
+ *
18
+ * @example
19
+ * ```js
20
+ * import { probe } from '@open-operational-state/probe';
21
+ *
22
+ * const result = await probe( 'https://api.example.com/health' );
23
+ * console.log( result.snapshot.condition ); // 'operational'
24
+ * ```
25
+ */
26
+ export async function probe(url, options) {
27
+ // ── Optional discovery ─────────────────────────────────────────────
28
+ let discoveryResult = null;
29
+ let probeUrl = url;
30
+ if (options?.followDiscovery) {
31
+ discoveryResult = await discover(url, {
32
+ headers: options?.headers,
33
+ });
34
+ // If discovery found links, probe the first one instead
35
+ if (discoveryResult.method === 'link-header' && discoveryResult.links.length > 0) {
36
+ probeUrl = new URL(discoveryResult.links[0].href, url).toString();
37
+ }
38
+ else if (discoveryResult.method === 'well-known' && discoveryResult.document?.resources) {
39
+ const resources = discoveryResult.document.resources;
40
+ // Prefer health profile, fall back to first available
41
+ const resource = resources.find((r) => r.profiles.includes('health')) || resources[0];
42
+ if (resource?.href) {
43
+ probeUrl = new URL(resource.href, url).toString();
44
+ }
45
+ }
46
+ }
47
+ // ── Fetch ──────────────────────────────────────────────────────────
48
+ let response;
49
+ try {
50
+ const fetchOptions = {};
51
+ if (options?.headers) {
52
+ fetchOptions.headers = options.headers;
53
+ }
54
+ if (options?.signal) {
55
+ fetchOptions.signal = options.signal;
56
+ }
57
+ response = await fetch(probeUrl, fetchOptions);
58
+ }
59
+ catch (err) {
60
+ // Re-throw AbortError so callers can distinguish cancellation
61
+ if (err instanceof DOMException && err.name === 'AbortError') {
62
+ throw err;
63
+ }
64
+ // ── Connection failure (DNS, timeout, refused, etc.) ──────────
65
+ const parsed = parse({
66
+ url: probeUrl,
67
+ connectionError: true,
68
+ });
69
+ const snapshot = normalizeSnapshot(parsed);
70
+ const validation = validateSnapshot(snapshot);
71
+ return {
72
+ url: probeUrl,
73
+ httpStatus: null,
74
+ contentType: null,
75
+ connectionError: true,
76
+ snapshot,
77
+ validation,
78
+ discovery: discoveryResult,
79
+ };
80
+ }
81
+ // ── Parse & normalize (outside catch so parse errors propagate) ────
82
+ const contentType = response.headers.get('content-type') || '';
83
+ let body;
84
+ const rawText = await response.text();
85
+ try {
86
+ body = JSON.parse(rawText);
87
+ }
88
+ catch {
89
+ body = rawText;
90
+ }
91
+ const headers = {};
92
+ response.headers.forEach((value, key) => {
93
+ headers[key] = value;
94
+ });
95
+ const parsed = parse({
96
+ contentType,
97
+ body,
98
+ url: probeUrl,
99
+ httpStatus: response.status,
100
+ headers,
101
+ });
102
+ // parse() returns Snapshot, normalizeSnapshot() expects Record<string, unknown>.
103
+ // The cast is safe — Snapshot is a plain object that satisfies Record<string, unknown>.
104
+ const snapshot = normalizeSnapshot(parsed);
105
+ const validation = validateSnapshot(snapshot);
106
+ return {
107
+ url: probeUrl,
108
+ httpStatus: response.status,
109
+ contentType,
110
+ connectionError: false,
111
+ snapshot,
112
+ validation,
113
+ discovery: discoveryResult,
114
+ };
115
+ }
116
+ //# sourceMappingURL=probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.js","sourceRoot":"","sources":["../src/probe.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@open-operational-state/probe",
3
+ "version": "0.2.0",
4
+ "description": "Probe any operational-state endpoint — fetch, detect, parse, normalize",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/open-operational-state/status-tooling-js.git",
24
+ "directory": "packages/probe"
25
+ },
26
+ "scripts": {
27
+ "build": "tsc",
28
+ "clean": "rm -rf dist",
29
+ "typecheck": "tsc --noEmit",
30
+ "test": "bun test"
31
+ },
32
+ "dependencies": {
33
+ "@open-operational-state/types": "^0.2.0",
34
+ "@open-operational-state/core": "^0.2.0",
35
+ "@open-operational-state/parser": "^0.2.0",
36
+ "@open-operational-state/discovery": "^0.2.0"
37
+ },
38
+ "devDependencies": {
39
+ "typescript": "^5.8.0"
40
+ }
41
+ }