@open-operational-state/emitter 0.1.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 +72 -0
- package/dist/__tests__/emitter.test.d.ts +7 -0
- package/dist/__tests__/emitter.test.d.ts.map +1 -0
- package/dist/__tests__/emitter.test.js +143 -0
- package/dist/__tests__/emitter.test.js.map +1 -0
- package/dist/__tests__/round-trip.test.d.ts +16 -0
- package/dist/__tests__/round-trip.test.d.ts.map +1 -0
- package/dist/__tests__/round-trip.test.js +242 -0
- package/dist/__tests__/round-trip.test.js.map +1 -0
- package/dist/health-response.d.ts +31 -0
- package/dist/health-response.d.ts.map +1 -0
- package/dist/health-response.js +117 -0
- package/dist/health-response.js.map +1 -0
- package/dist/http.d.ts +17 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +57 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/service-status.d.ts +39 -0
- package/dist/service-status.d.ts.map +1 -0
- package/dist/service-status.js +112 -0
- package/dist/service-status.js.map +1 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# @open-operational-state/emitter
|
|
2
|
+
|
|
3
|
+
Serialization emitters for [Open Operational State](https://github.com/open-operational-state). Convert core model `Snapshot` objects to spec-conformant wire formats.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @open-operational-state/emitter
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
### `emitHealthResponse( snapshot )`
|
|
14
|
+
|
|
15
|
+
Convert a `Snapshot` to an `application/health+json` payload.
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
import { emitHealthResponse } from '@open-operational-state/emitter';
|
|
19
|
+
|
|
20
|
+
const payload = emitHealthResponse( snapshot );
|
|
21
|
+
// Serve as: Content-Type: application/health+json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### `emitServiceStatus( snapshot )`
|
|
25
|
+
|
|
26
|
+
Convert a `Snapshot` to an `application/status+json` payload.
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
import { emitServiceStatus } from '@open-operational-state/emitter';
|
|
30
|
+
|
|
31
|
+
const payload = emitServiceStatus( snapshot );
|
|
32
|
+
// Serve as: Content-Type: application/status+json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### `suggestHttpStatus( condition )`
|
|
36
|
+
|
|
37
|
+
Get the recommended HTTP status code for a condition value.
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
import { suggestHttpStatus } from '@open-operational-state/emitter';
|
|
41
|
+
|
|
42
|
+
suggestHttpStatus( 'operational' ); // 200
|
|
43
|
+
suggestHttpStatus( 'degraded' ); // 200
|
|
44
|
+
suggestHttpStatus( 'down' ); // 503
|
|
45
|
+
suggestHttpStatus( 'maintenance' ); // 503
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### `suggestHeaders( snapshot, serialization )`
|
|
49
|
+
|
|
50
|
+
Get recommended HTTP headers for a response.
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
import { suggestHeaders } from '@open-operational-state/emitter';
|
|
54
|
+
|
|
55
|
+
const headers = suggestHeaders( snapshot, 'application/health+json' );
|
|
56
|
+
// { 'Content-Type': 'application/health+json', 'Cache-Control': 'no-cache, ...' }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Round-Trip Guarantee
|
|
60
|
+
|
|
61
|
+
The emitter maintains the round-trip invariant:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
parse → normalize → emit → parse → normalize
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
No semantic drift, no loss of required data, no illegal state introduced. This is enforced by golden round-trip tests.
|
|
68
|
+
|
|
69
|
+
## Dependencies
|
|
70
|
+
|
|
71
|
+
- `@open-operational-state/types`
|
|
72
|
+
- `@open-operational-state/core`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/emitter.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emitter Tests
|
|
3
|
+
*
|
|
4
|
+
* Round-trip tests: parse → emit → parse, verify structural identity.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect } from 'bun:test';
|
|
7
|
+
import { resolve, join } from 'node:path';
|
|
8
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
9
|
+
import { normalizeSnapshot } from '@open-operational-state/core';
|
|
10
|
+
import { emitHealthResponse } from '../health-response.js';
|
|
11
|
+
import { emitServiceStatus } from '../service-status.js';
|
|
12
|
+
import { suggestHttpStatus, suggestHeaders } from '../http.js';
|
|
13
|
+
const FIXTURE_ROOT = process.env.OOS_FIXTURE_ROOT
|
|
14
|
+
|| resolve(import.meta.dir, '../../../../..', 'status-conformance');
|
|
15
|
+
function loadFixture(relPath) {
|
|
16
|
+
const fullPath = join(FIXTURE_ROOT, relPath);
|
|
17
|
+
if (!existsSync(fullPath)) {
|
|
18
|
+
throw new Error(`Fixture not found: ${fullPath}`);
|
|
19
|
+
}
|
|
20
|
+
return JSON.parse(readFileSync(fullPath, 'utf-8'));
|
|
21
|
+
}
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Health response round-trip
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
describe('emitHealthResponse', () => {
|
|
26
|
+
it('emits a valid health response from a snapshot', () => {
|
|
27
|
+
const snapshot = {
|
|
28
|
+
condition: 'operational',
|
|
29
|
+
profiles: ['health'],
|
|
30
|
+
subject: { id: 'test-service', description: 'Test Service' },
|
|
31
|
+
timing: { observed: '2026-04-02T19:30:00Z' },
|
|
32
|
+
provenance: 'self-reported',
|
|
33
|
+
};
|
|
34
|
+
const payload = emitHealthResponse(snapshot);
|
|
35
|
+
expect(payload.condition).toBe('operational');
|
|
36
|
+
expect(payload.profiles).toEqual(['health']);
|
|
37
|
+
expect(payload.subject.id).toBe('test-service');
|
|
38
|
+
expect(payload.timing?.observed).toBe('2026-04-02T19:30:00Z');
|
|
39
|
+
expect(payload.provenance).toBe('self-reported');
|
|
40
|
+
});
|
|
41
|
+
it('round-trips a health fixture: emit → normalize', () => {
|
|
42
|
+
const fixture = loadFixture('fixtures/profiles/health/positive-degraded-with-components.json');
|
|
43
|
+
const input = fixture.input;
|
|
44
|
+
const snapshot = normalizeSnapshot(input);
|
|
45
|
+
// Emit
|
|
46
|
+
const payload = emitHealthResponse(snapshot);
|
|
47
|
+
// Re-normalize
|
|
48
|
+
const roundTripped = normalizeSnapshot(payload);
|
|
49
|
+
expect(roundTripped.condition).toBe(snapshot.condition);
|
|
50
|
+
expect(roundTripped.subject.id).toBe(snapshot.subject.id);
|
|
51
|
+
expect(roundTripped.provenance).toBe(snapshot.provenance);
|
|
52
|
+
});
|
|
53
|
+
it('includes checks from snapshot', () => {
|
|
54
|
+
const snapshot = {
|
|
55
|
+
condition: 'degraded',
|
|
56
|
+
profiles: ['health'],
|
|
57
|
+
subject: { id: 'test' },
|
|
58
|
+
checks: {
|
|
59
|
+
database: { condition: 'operational', role: 'dependency' },
|
|
60
|
+
cache: { condition: 'down', role: 'component' },
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
const payload = emitHealthResponse(snapshot);
|
|
64
|
+
expect(payload.checks).toBeDefined();
|
|
65
|
+
expect(Object.keys(payload.checks)).toEqual(['database', 'cache']);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Service status round-trip
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
describe('emitServiceStatus', () => {
|
|
72
|
+
it('emits a valid service-status payload', () => {
|
|
73
|
+
const snapshot = {
|
|
74
|
+
condition: 'degraded',
|
|
75
|
+
profiles: ['status'],
|
|
76
|
+
subject: { id: 'payment-platform', description: 'Payment Platform' },
|
|
77
|
+
timing: { observed: '2026-04-02T19:30:00Z' },
|
|
78
|
+
provenance: 'self-reported',
|
|
79
|
+
evidence: { type: 'error-rate', detail: '7.2% errors' },
|
|
80
|
+
components: [
|
|
81
|
+
{ id: 'api', condition: 'operational' },
|
|
82
|
+
{ id: 'cache', condition: 'down' },
|
|
83
|
+
],
|
|
84
|
+
dependencies: [
|
|
85
|
+
{ id: 'database', condition: 'operational' },
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
const payload = emitServiceStatus(snapshot);
|
|
89
|
+
expect(payload.condition).toBe('degraded');
|
|
90
|
+
expect(payload.components?.length).toBe(2);
|
|
91
|
+
expect(payload.dependencies?.length).toBe(1);
|
|
92
|
+
expect(payload.evidence?.type).toBe('error-rate');
|
|
93
|
+
});
|
|
94
|
+
it('converts flat checks to components/dependencies', () => {
|
|
95
|
+
const snapshot = {
|
|
96
|
+
condition: 'operational',
|
|
97
|
+
profiles: ['status'],
|
|
98
|
+
subject: { id: 'test' },
|
|
99
|
+
checks: {
|
|
100
|
+
db: { condition: 'operational', role: 'dependency' },
|
|
101
|
+
worker: { condition: 'operational', role: 'component' },
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
const payload = emitServiceStatus(snapshot);
|
|
105
|
+
expect(payload.components?.length).toBe(1);
|
|
106
|
+
expect(payload.dependencies?.length).toBe(1);
|
|
107
|
+
expect(payload.components[0].id).toBe('worker');
|
|
108
|
+
expect(payload.dependencies[0].id).toBe('db');
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
// HTTP helpers
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
describe('suggestHttpStatus', () => {
|
|
115
|
+
it('returns 200 for operational', () => {
|
|
116
|
+
expect(suggestHttpStatus('operational')).toBe(200);
|
|
117
|
+
});
|
|
118
|
+
it('returns 200 for degraded', () => {
|
|
119
|
+
expect(suggestHttpStatus('degraded')).toBe(200);
|
|
120
|
+
});
|
|
121
|
+
it('returns 503 for down', () => {
|
|
122
|
+
expect(suggestHttpStatus('down')).toBe(503);
|
|
123
|
+
});
|
|
124
|
+
it('returns 503 for maintenance', () => {
|
|
125
|
+
expect(suggestHttpStatus('maintenance')).toBe(503);
|
|
126
|
+
});
|
|
127
|
+
it('returns 200 for alive', () => {
|
|
128
|
+
expect(suggestHttpStatus('alive')).toBe(200);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe('suggestHeaders', () => {
|
|
132
|
+
it('returns correct content type', () => {
|
|
133
|
+
const snapshot = {
|
|
134
|
+
condition: 'operational',
|
|
135
|
+
profiles: ['health'],
|
|
136
|
+
subject: { id: 'test' },
|
|
137
|
+
};
|
|
138
|
+
const headers = suggestHeaders(snapshot, 'application/health+json');
|
|
139
|
+
expect(headers['Content-Type']).toBe('application/health+json');
|
|
140
|
+
expect(headers['Cache-Control']).toContain('no-cache');
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
//# sourceMappingURL=emitter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.test.js","sourceRoot":"","sources":["../../src/__tests__/emitter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Golden Round-Trip Invariant Tests
|
|
3
|
+
*
|
|
4
|
+
* Enforces the fundamental guarantee:
|
|
5
|
+
* parse → normalize → emit → parse → normalize
|
|
6
|
+
*
|
|
7
|
+
* Must guarantee:
|
|
8
|
+
* - No semantic drift
|
|
9
|
+
* - No loss of required data
|
|
10
|
+
* - No illegal state introduced
|
|
11
|
+
*
|
|
12
|
+
* This is the long-term safety net. If these tests break,
|
|
13
|
+
* something fundamental has drifted.
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=round-trip.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"round-trip.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/round-trip.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Golden Round-Trip Invariant Tests
|
|
3
|
+
*
|
|
4
|
+
* Enforces the fundamental guarantee:
|
|
5
|
+
* parse → normalize → emit → parse → normalize
|
|
6
|
+
*
|
|
7
|
+
* Must guarantee:
|
|
8
|
+
* - No semantic drift
|
|
9
|
+
* - No loss of required data
|
|
10
|
+
* - No illegal state introduced
|
|
11
|
+
*
|
|
12
|
+
* This is the long-term safety net. If these tests break,
|
|
13
|
+
* something fundamental has drifted.
|
|
14
|
+
*/
|
|
15
|
+
import { describe, it, expect } from 'bun:test';
|
|
16
|
+
import { resolve, join } from 'node:path';
|
|
17
|
+
import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
|
|
18
|
+
import { normalizeSnapshot, validateSnapshot } from '@open-operational-state/core';
|
|
19
|
+
import { parseHealthCheckDraft } from '@open-operational-state/parser';
|
|
20
|
+
import { emitHealthResponse, emitServiceStatus } from '@open-operational-state/emitter';
|
|
21
|
+
const FIXTURE_ROOT = process.env.OOS_FIXTURE_ROOT
|
|
22
|
+
|| resolve(import.meta.dir, '../../../../..', 'status-conformance');
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Helpers
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
function findFixtures(dirPath) {
|
|
27
|
+
if (!existsSync(dirPath)) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
const files = [];
|
|
31
|
+
for (const entry of readdirSync(dirPath)) {
|
|
32
|
+
const fullPath = join(dirPath, entry);
|
|
33
|
+
const stat = statSync(fullPath);
|
|
34
|
+
if (stat.isDirectory()) {
|
|
35
|
+
files.push(...findFixtures(fullPath));
|
|
36
|
+
}
|
|
37
|
+
else if (entry.endsWith('.json')) {
|
|
38
|
+
files.push(fullPath);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return files;
|
|
42
|
+
}
|
|
43
|
+
function loadJson(path) {
|
|
44
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Assert that two snapshots are semantically equivalent
|
|
48
|
+
* for the purposes of round-trip invariance.
|
|
49
|
+
*
|
|
50
|
+
* Checks required fields and structural shape.
|
|
51
|
+
* Timing is excluded from round-trip checks because emit
|
|
52
|
+
* may add/strip timing fields not present in the original.
|
|
53
|
+
*/
|
|
54
|
+
function assertSemanticEquivalence(original, roundTripped, label) {
|
|
55
|
+
// Condition must be preserved
|
|
56
|
+
expect(roundTripped.condition).toBe(original.condition);
|
|
57
|
+
// Subject identity must be preserved
|
|
58
|
+
expect(roundTripped.subject.id).toBe(original.subject.id);
|
|
59
|
+
// Subject description must be preserved if present
|
|
60
|
+
if (original.subject.description) {
|
|
61
|
+
expect(roundTripped.subject.description).toBe(original.subject.description);
|
|
62
|
+
}
|
|
63
|
+
// Profiles must be preserved
|
|
64
|
+
expect(roundTripped.profiles).toEqual(original.profiles);
|
|
65
|
+
// Provenance must be preserved if present
|
|
66
|
+
if (original.provenance) {
|
|
67
|
+
expect(roundTripped.provenance).toBe(original.provenance);
|
|
68
|
+
}
|
|
69
|
+
// Evidence type must be preserved if present
|
|
70
|
+
if (original.evidence) {
|
|
71
|
+
expect(roundTripped.evidence?.type).toBe(original.evidence.type);
|
|
72
|
+
}
|
|
73
|
+
// Check count must be preserved
|
|
74
|
+
if (original.checks) {
|
|
75
|
+
expect(Object.keys(roundTripped.checks || {}).length)
|
|
76
|
+
.toBe(Object.keys(original.checks).length);
|
|
77
|
+
// Each check's condition must be preserved
|
|
78
|
+
for (const [key, check] of Object.entries(original.checks)) {
|
|
79
|
+
expect(roundTripped.checks?.[key]?.condition).toBe(check.condition);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// The round-tripped snapshot must still be valid
|
|
83
|
+
const validation = validateSnapshot(roundTripped);
|
|
84
|
+
// If original was valid, round-trip must be valid
|
|
85
|
+
const originalValidation = validateSnapshot(original);
|
|
86
|
+
if (originalValidation.valid) {
|
|
87
|
+
expect(validation.valid).toBe(true);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
// Round-trip: health-response (parse → emit → parse)
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
describe('round-trip: health-response', () => {
|
|
94
|
+
// Core positive fixtures through health-response path
|
|
95
|
+
const corePositive = findFixtures(join(FIXTURE_ROOT, 'fixtures', 'core'))
|
|
96
|
+
.filter((f) => f.includes('positive'));
|
|
97
|
+
const profilePositive = findFixtures(join(FIXTURE_ROOT, 'fixtures', 'profiles'))
|
|
98
|
+
.filter((f) => f.includes('positive'));
|
|
99
|
+
const allPositive = [...corePositive, ...profilePositive];
|
|
100
|
+
for (const fixturePath of allPositive) {
|
|
101
|
+
const name = fixturePath.split('/').slice(-2).join('/');
|
|
102
|
+
it(`round-trips: ${name}`, () => {
|
|
103
|
+
const fixture = loadJson(fixturePath);
|
|
104
|
+
const input = fixture.input;
|
|
105
|
+
// Step 1: normalize input → Snapshot
|
|
106
|
+
const original = normalizeSnapshot(input);
|
|
107
|
+
// Step 2: emit health-response
|
|
108
|
+
const emitted = emitHealthResponse(original);
|
|
109
|
+
// Step 3: re-parse the emitted payload
|
|
110
|
+
const roundTripped = normalizeSnapshot(emitted);
|
|
111
|
+
// Step 4: verify semantic equivalence
|
|
112
|
+
assertSemanticEquivalence(original, roundTripped, name);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
// Round-trip: service-status (parse → emit → parse)
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
describe('round-trip: service-status', () => {
|
|
120
|
+
it('round-trips a rich snapshot through service-status format', () => {
|
|
121
|
+
const original = {
|
|
122
|
+
condition: 'degraded',
|
|
123
|
+
profiles: ['status'],
|
|
124
|
+
subject: { id: 'payment-platform', description: 'Payment Platform' },
|
|
125
|
+
timing: { observed: '2026-04-02T19:30:00Z' },
|
|
126
|
+
provenance: 'self-reported',
|
|
127
|
+
evidence: { type: 'error-rate', detail: '7.2% error rate' },
|
|
128
|
+
components: [
|
|
129
|
+
{ id: 'api', condition: 'operational' },
|
|
130
|
+
{ id: 'cache', condition: 'down', evidence: { type: 'connectivity', detail: 'Connection refused' } },
|
|
131
|
+
],
|
|
132
|
+
dependencies: [
|
|
133
|
+
{ id: 'database', condition: 'operational' },
|
|
134
|
+
],
|
|
135
|
+
};
|
|
136
|
+
// Emit
|
|
137
|
+
const emitted = emitServiceStatus(original);
|
|
138
|
+
// Re-parse
|
|
139
|
+
const roundTripped = normalizeSnapshot(emitted);
|
|
140
|
+
// Verify
|
|
141
|
+
expect(roundTripped.condition).toBe('degraded');
|
|
142
|
+
expect(roundTripped.subject.id).toBe('payment-platform');
|
|
143
|
+
expect(roundTripped.provenance).toBe('self-reported');
|
|
144
|
+
expect(roundTripped.profiles).toEqual(['status']);
|
|
145
|
+
});
|
|
146
|
+
it('converts flat checks → components → flat checks without loss', () => {
|
|
147
|
+
const original = {
|
|
148
|
+
condition: 'operational',
|
|
149
|
+
profiles: ['health'],
|
|
150
|
+
subject: { id: 'test' },
|
|
151
|
+
checks: {
|
|
152
|
+
db: { condition: 'operational', role: 'dependency' },
|
|
153
|
+
worker: { condition: 'operational', role: 'component' },
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
// Emit as service-status (converts checks → components/dependencies)
|
|
157
|
+
const emitted = emitServiceStatus(original);
|
|
158
|
+
expect(emitted.components?.length).toBe(1);
|
|
159
|
+
expect(emitted.dependencies?.length).toBe(1);
|
|
160
|
+
// Emit as health-response (keeps checks flat)
|
|
161
|
+
const healthEmitted = emitHealthResponse(original);
|
|
162
|
+
const healthRoundTripped = normalizeSnapshot(healthEmitted);
|
|
163
|
+
expect(Object.keys(healthRoundTripped.checks || {}).length).toBe(2);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// Round-trip: health-check-draft adapter → emit → parse
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
describe('round-trip: adapter → emit → re-parse', () => {
|
|
170
|
+
const adapterFixtures = findFixtures(join(FIXTURE_ROOT, 'adapters', 'health-check-draft')).filter((f) => f.includes('positive'));
|
|
171
|
+
for (const fixturePath of adapterFixtures) {
|
|
172
|
+
const name = fixturePath.split('/').slice(-1)[0];
|
|
173
|
+
it(`adapter round-trip: ${name}`, () => {
|
|
174
|
+
const fixture = loadJson(fixturePath);
|
|
175
|
+
const input = fixture.input;
|
|
176
|
+
// Step 1: parse through adapter
|
|
177
|
+
const adapted = parseHealthCheckDraft(input.body);
|
|
178
|
+
// Step 2: emit as health-response
|
|
179
|
+
const emitted = emitHealthResponse(adapted);
|
|
180
|
+
// Step 3: re-parse the emitted payload
|
|
181
|
+
const roundTripped = normalizeSnapshot(emitted);
|
|
182
|
+
// Step 4: verify the adapter output survived round-trip
|
|
183
|
+
expect(roundTripped.condition).toBe(adapted.condition);
|
|
184
|
+
expect(roundTripped.subject.id).toBe(adapted.subject.id);
|
|
185
|
+
expect(roundTripped.provenance).toBe(adapted.provenance);
|
|
186
|
+
// Must still validate — round-trip must not INTRODUCE new errors
|
|
187
|
+
const adaptedValidation = validateSnapshot(adapted);
|
|
188
|
+
const validation = validateSnapshot(roundTripped);
|
|
189
|
+
if (adaptedValidation.valid) {
|
|
190
|
+
expect(validation.valid).toBe(true);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
expect(validation.errors.length).toBeLessThanOrEqual(adaptedValidation.errors.length);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
// Illegal state detection
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
describe('round-trip: no illegal state introduced', () => {
|
|
202
|
+
it('emitting then re-parsing does not create empty required fields', () => {
|
|
203
|
+
const original = {
|
|
204
|
+
condition: 'operational',
|
|
205
|
+
profiles: ['health'],
|
|
206
|
+
subject: { id: 'svc-1' },
|
|
207
|
+
timing: { observed: '2026-04-02T19:30:00Z' },
|
|
208
|
+
provenance: 'self-reported',
|
|
209
|
+
};
|
|
210
|
+
const emitted = emitHealthResponse(original);
|
|
211
|
+
const roundTripped = normalizeSnapshot(emitted);
|
|
212
|
+
// Required fields must not become empty
|
|
213
|
+
expect(roundTripped.condition).toBeTruthy();
|
|
214
|
+
expect(roundTripped.subject.id).toBeTruthy();
|
|
215
|
+
expect(roundTripped.profiles.length).toBeGreaterThan(0);
|
|
216
|
+
});
|
|
217
|
+
it('does not silently coerce categorical to orderable', () => {
|
|
218
|
+
const original = {
|
|
219
|
+
condition: 'maintenance',
|
|
220
|
+
profiles: ['health'],
|
|
221
|
+
subject: { id: 'svc-1' },
|
|
222
|
+
timing: { observed: '2026-04-02T19:30:00Z' },
|
|
223
|
+
};
|
|
224
|
+
const emitted = emitHealthResponse(original);
|
|
225
|
+
const roundTripped = normalizeSnapshot(emitted);
|
|
226
|
+
// 'maintenance' must remain 'maintenance', not get coerced
|
|
227
|
+
expect(roundTripped.condition).toBe('maintenance');
|
|
228
|
+
});
|
|
229
|
+
it('does not silently coerce extension values', () => {
|
|
230
|
+
const original = {
|
|
231
|
+
condition: 'x-acme-draining',
|
|
232
|
+
profiles: ['health'],
|
|
233
|
+
subject: { id: 'svc-1' },
|
|
234
|
+
timing: { observed: '2026-04-02T19:30:00Z' },
|
|
235
|
+
};
|
|
236
|
+
const emitted = emitHealthResponse(original);
|
|
237
|
+
const roundTripped = normalizeSnapshot(emitted);
|
|
238
|
+
// Extension values must survive untouched
|
|
239
|
+
expect(roundTripped.condition).toBe('x-acme-draining');
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
//# sourceMappingURL=round-trip.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"round-trip.test.js","sourceRoot":"","sources":["../../src/__tests__/round-trip.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Response Emitter
|
|
3
|
+
*
|
|
4
|
+
* Converts a Snapshot → application/health+json wire format.
|
|
5
|
+
*/
|
|
6
|
+
import type { Snapshot } from '@open-operational-state/types';
|
|
7
|
+
export interface HealthResponsePayload {
|
|
8
|
+
condition: string;
|
|
9
|
+
profiles: string[];
|
|
10
|
+
subject: {
|
|
11
|
+
id: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
};
|
|
14
|
+
timing?: {
|
|
15
|
+
observed?: string;
|
|
16
|
+
reported?: string;
|
|
17
|
+
stateChanged?: string;
|
|
18
|
+
};
|
|
19
|
+
provenance?: string;
|
|
20
|
+
evidence?: {
|
|
21
|
+
type: string;
|
|
22
|
+
detail?: string;
|
|
23
|
+
};
|
|
24
|
+
checks?: Record<string, unknown>;
|
|
25
|
+
links?: Record<string, string>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Emit a Snapshot as an application/health+json payload.
|
|
29
|
+
*/
|
|
30
|
+
export declare function emitHealthResponse(snapshot: Snapshot): HealthResponsePayload;
|
|
31
|
+
//# sourceMappingURL=health-response.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-response.d.ts","sourceRoot":"","sources":["../src/health-response.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAgC,MAAM,+BAA+B,CAAC;AAM5F,MAAM,WAAW,qBAAqB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,WAAW,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,MAAM,CAAC,EAAE;QACL,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAOD;;GAEG;AACH,wBAAgB,kBAAkB,CAC9B,QAAQ,EAAE,QAAQ,GACnB,qBAAqB,CAuCvB"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Response Emitter
|
|
3
|
+
*
|
|
4
|
+
* Converts a Snapshot → application/health+json wire format.
|
|
5
|
+
*/
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Public API
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
/**
|
|
10
|
+
* Emit a Snapshot as an application/health+json payload.
|
|
11
|
+
*/
|
|
12
|
+
export function emitHealthResponse(snapshot) {
|
|
13
|
+
const payload = {
|
|
14
|
+
condition: snapshot.condition,
|
|
15
|
+
profiles: [...snapshot.profiles],
|
|
16
|
+
subject: {
|
|
17
|
+
id: snapshot.subject.id,
|
|
18
|
+
...(snapshot.subject.description ? { description: snapshot.subject.description } : {}),
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
// Timing
|
|
22
|
+
if (snapshot.timing) {
|
|
23
|
+
payload.timing = { ...snapshot.timing };
|
|
24
|
+
}
|
|
25
|
+
// Provenance
|
|
26
|
+
if (snapshot.provenance) {
|
|
27
|
+
payload.provenance = snapshot.provenance;
|
|
28
|
+
}
|
|
29
|
+
// Evidence
|
|
30
|
+
if (snapshot.evidence) {
|
|
31
|
+
const evidence = { type: snapshot.evidence.type };
|
|
32
|
+
if (snapshot.evidence.detail) {
|
|
33
|
+
evidence.detail = snapshot.evidence.detail;
|
|
34
|
+
}
|
|
35
|
+
payload.evidence = evidence;
|
|
36
|
+
}
|
|
37
|
+
// Checks — merge from flat checks or convert from nested arrays
|
|
38
|
+
const checks = buildChecks(snapshot);
|
|
39
|
+
if (checks && Object.keys(checks).length > 0) {
|
|
40
|
+
payload.checks = checks;
|
|
41
|
+
}
|
|
42
|
+
// Links
|
|
43
|
+
if (snapshot.links && Object.keys(snapshot.links).length > 0) {
|
|
44
|
+
payload.links = { ...snapshot.links };
|
|
45
|
+
}
|
|
46
|
+
return payload;
|
|
47
|
+
}
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Internal
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
function buildChecks(snapshot) {
|
|
52
|
+
const result = {};
|
|
53
|
+
// Flat checks (native health-response format)
|
|
54
|
+
if (snapshot.checks) {
|
|
55
|
+
for (const [key, check] of Object.entries(snapshot.checks)) {
|
|
56
|
+
result[key] = buildCheckEntry(check);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Nested components → flat checks
|
|
60
|
+
if (snapshot.components) {
|
|
61
|
+
for (const comp of snapshot.components) {
|
|
62
|
+
const entry = {
|
|
63
|
+
condition: comp.condition,
|
|
64
|
+
role: 'component',
|
|
65
|
+
};
|
|
66
|
+
if (comp.timing) {
|
|
67
|
+
entry.timing = comp.timing;
|
|
68
|
+
}
|
|
69
|
+
if (comp.provenance) {
|
|
70
|
+
entry.provenance = comp.provenance;
|
|
71
|
+
}
|
|
72
|
+
if (comp.evidence) {
|
|
73
|
+
entry.evidence = comp.evidence;
|
|
74
|
+
}
|
|
75
|
+
result[comp.id] = entry;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Nested dependencies → flat checks
|
|
79
|
+
if (snapshot.dependencies) {
|
|
80
|
+
for (const dep of snapshot.dependencies) {
|
|
81
|
+
const entry = {
|
|
82
|
+
condition: dep.condition,
|
|
83
|
+
role: 'dependency',
|
|
84
|
+
};
|
|
85
|
+
if (dep.timing) {
|
|
86
|
+
entry.timing = dep.timing;
|
|
87
|
+
}
|
|
88
|
+
if (dep.provenance) {
|
|
89
|
+
entry.provenance = dep.provenance;
|
|
90
|
+
}
|
|
91
|
+
if (dep.evidence) {
|
|
92
|
+
entry.evidence = dep.evidence;
|
|
93
|
+
}
|
|
94
|
+
result[dep.id] = entry;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
98
|
+
}
|
|
99
|
+
function buildCheckEntry(check) {
|
|
100
|
+
const entry = {
|
|
101
|
+
condition: check.condition,
|
|
102
|
+
};
|
|
103
|
+
if (check.role) {
|
|
104
|
+
entry.role = check.role;
|
|
105
|
+
}
|
|
106
|
+
if (check.timing) {
|
|
107
|
+
entry.timing = check.timing;
|
|
108
|
+
}
|
|
109
|
+
if (check.provenance) {
|
|
110
|
+
entry.provenance = check.provenance;
|
|
111
|
+
}
|
|
112
|
+
if (check.evidence) {
|
|
113
|
+
entry.evidence = check.evidence;
|
|
114
|
+
}
|
|
115
|
+
return entry;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=health-response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-response.js","sourceRoot":"","sources":["../src/health-response.ts"],"names":[],"mappings":"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"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Response Helpers
|
|
3
|
+
*
|
|
4
|
+
* Suggest HTTP status codes and headers for operational-state responses
|
|
5
|
+
* per the serialization spec rules.
|
|
6
|
+
*/
|
|
7
|
+
import type { Snapshot } from '@open-operational-state/types';
|
|
8
|
+
/**
|
|
9
|
+
* Returns the recommended HTTP status code for a given condition value,
|
|
10
|
+
* per the serialization spec HTTP Response Requirements.
|
|
11
|
+
*/
|
|
12
|
+
export declare function suggestHttpStatus(condition: string): number;
|
|
13
|
+
/**
|
|
14
|
+
* Returns recommended HTTP headers for an operational-state response.
|
|
15
|
+
*/
|
|
16
|
+
export declare function suggestHeaders(snapshot: Snapshot, serialization: 'application/health+json' | 'application/status+json'): Record<string, string>;
|
|
17
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAM9D;;;GAGG;AACH,wBAAgB,iBAAiB,CAAE,SAAS,EAAE,MAAM,GAAI,MAAM,CA2B7D;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAC1B,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,yBAAyB,GAAG,yBAAyB,GACrE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAaxB"}
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Response Helpers
|
|
3
|
+
*
|
|
4
|
+
* Suggest HTTP status codes and headers for operational-state responses
|
|
5
|
+
* per the serialization spec rules.
|
|
6
|
+
*/
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// HTTP status code suggestion
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
/**
|
|
11
|
+
* Returns the recommended HTTP status code for a given condition value,
|
|
12
|
+
* per the serialization spec HTTP Response Requirements.
|
|
13
|
+
*/
|
|
14
|
+
export function suggestHttpStatus(condition) {
|
|
15
|
+
switch (condition) {
|
|
16
|
+
// Good states → 200
|
|
17
|
+
case 'operational':
|
|
18
|
+
case 'alive':
|
|
19
|
+
case 'ready':
|
|
20
|
+
case 'degraded':
|
|
21
|
+
case 'partial-outage':
|
|
22
|
+
case 'major-outage':
|
|
23
|
+
case 'initializing':
|
|
24
|
+
return 200;
|
|
25
|
+
// Down / unreachable / not-ready → 503
|
|
26
|
+
case 'down':
|
|
27
|
+
case 'unreachable':
|
|
28
|
+
case 'not-ready':
|
|
29
|
+
case 'maintenance':
|
|
30
|
+
return 503;
|
|
31
|
+
// Unknown → 200 (service is responding)
|
|
32
|
+
case 'unknown':
|
|
33
|
+
return 200;
|
|
34
|
+
default:
|
|
35
|
+
// Extension values → 200 (service is responding)
|
|
36
|
+
return 200;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Header suggestion
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
/**
|
|
43
|
+
* Returns recommended HTTP headers for an operational-state response.
|
|
44
|
+
*/
|
|
45
|
+
export function suggestHeaders(snapshot, serialization) {
|
|
46
|
+
const headers = {
|
|
47
|
+
'Content-Type': serialization,
|
|
48
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
49
|
+
};
|
|
50
|
+
// Retry-After for maintenance
|
|
51
|
+
if (snapshot.condition === 'maintenance' && snapshot.timing?.stateChanged) {
|
|
52
|
+
// If we know when maintenance started, suggest checking back in 5 minutes
|
|
53
|
+
headers['Retry-After'] = '300';
|
|
54
|
+
}
|
|
55
|
+
return headers;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,8EAA8E;AAC9E,8BAA8B;AAC9B,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAE,SAAiB;IAChD,QAAS,SAAS,EAAG,CAAC;QAClB,oBAAoB;QACpB,KAAK,aAAa,CAAC;QACnB,KAAK,OAAO,CAAC;QACb,KAAK,OAAO,CAAC;QACb,KAAK,UAAU,CAAC;QAChB,KAAK,gBAAgB,CAAC;QACtB,KAAK,cAAc,CAAC;QACpB,KAAK,cAAc;YACf,OAAO,GAAG,CAAC;QAEf,uCAAuC;QACvC,KAAK,MAAM,CAAC;QACZ,KAAK,aAAa,CAAC;QACnB,KAAK,WAAW,CAAC;QACjB,KAAK,aAAa;YACd,OAAO,GAAG,CAAC;QAEf,wCAAwC;QACxC,KAAK,SAAS;YACV,OAAO,GAAG,CAAC;QAEf;YACI,iDAAiD;YACjD,OAAO,GAAG,CAAC;IACnB,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E;;GAEG;AACH,MAAM,UAAU,cAAc,CAC1B,QAAkB,EAClB,aAAoE;IAEpE,MAAM,OAAO,GAA2B;QACpC,cAAc,EAAE,aAAa;QAC7B,eAAe,EAAE,qCAAqC;KACzD,CAAC;IAEF,8BAA8B;IAC9B,IAAK,QAAQ,CAAC,SAAS,KAAK,aAAa,IAAI,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAG,CAAC;QAC1E,0EAA0E;QAC1E,OAAO,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC;IACnC,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @open-operational-state/emitter
|
|
3
|
+
*
|
|
4
|
+
* Serialization emitters — convert core model Snapshots to wire formats.
|
|
5
|
+
*
|
|
6
|
+
* Depends on @open-operational-state/types and @open-operational-state/core.
|
|
7
|
+
*/
|
|
8
|
+
export { emitHealthResponse } from './health-response.js';
|
|
9
|
+
export type { HealthResponsePayload } from './health-response.js';
|
|
10
|
+
export { emitServiceStatus } from './service-status.js';
|
|
11
|
+
export type { ServiceStatusPayload } from './service-status.js';
|
|
12
|
+
export { suggestHttpStatus, suggestHeaders } from './http.js';
|
|
13
|
+
//# 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,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAElE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEhE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @open-operational-state/emitter
|
|
3
|
+
*
|
|
4
|
+
* Serialization emitters — convert core model Snapshots to wire formats.
|
|
5
|
+
*
|
|
6
|
+
* Depends on @open-operational-state/types and @open-operational-state/core.
|
|
7
|
+
*/
|
|
8
|
+
export { emitHealthResponse } from './health-response.js';
|
|
9
|
+
export { emitServiceStatus } from './service-status.js';
|
|
10
|
+
export { suggestHttpStatus, suggestHeaders } from './http.js';
|
|
11
|
+
//# 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,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAG1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Status Emitter
|
|
3
|
+
*
|
|
4
|
+
* Converts a Snapshot → application/status+json wire format.
|
|
5
|
+
*/
|
|
6
|
+
import type { Snapshot, ComponentEntry, DependencyEntry } from '@open-operational-state/types';
|
|
7
|
+
export interface ServiceStatusPayload {
|
|
8
|
+
condition: string;
|
|
9
|
+
profiles: string[];
|
|
10
|
+
subject: {
|
|
11
|
+
id: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
version?: string;
|
|
14
|
+
contact?: string;
|
|
15
|
+
};
|
|
16
|
+
timing?: {
|
|
17
|
+
observed?: string;
|
|
18
|
+
reported?: string;
|
|
19
|
+
stateChanged?: string;
|
|
20
|
+
};
|
|
21
|
+
provenance?: string;
|
|
22
|
+
evidence?: {
|
|
23
|
+
type: string;
|
|
24
|
+
detail?: string;
|
|
25
|
+
};
|
|
26
|
+
scope?: {
|
|
27
|
+
type: string;
|
|
28
|
+
identifier?: string;
|
|
29
|
+
};
|
|
30
|
+
components?: ComponentEntry[];
|
|
31
|
+
dependencies?: DependencyEntry[];
|
|
32
|
+
incidents?: unknown[];
|
|
33
|
+
links?: Record<string, string>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Emit a Snapshot as an application/status+json payload.
|
|
37
|
+
*/
|
|
38
|
+
export declare function emitServiceStatus(snapshot: Snapshot): ServiceStatusPayload;
|
|
39
|
+
//# sourceMappingURL=service-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-status.d.ts","sourceRoot":"","sources":["../src/service-status.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAM/F,MAAM,WAAW,oBAAoB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,MAAM,CAAC,EAAE;QACL,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,KAAK,CAAC,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,CAAE,QAAQ,EAAE,QAAQ,GAAI,oBAAoB,CA8E5E"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Status Emitter
|
|
3
|
+
*
|
|
4
|
+
* Converts a Snapshot → application/status+json wire format.
|
|
5
|
+
*/
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Public API
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
/**
|
|
10
|
+
* Emit a Snapshot as an application/status+json payload.
|
|
11
|
+
*/
|
|
12
|
+
export function emitServiceStatus(snapshot) {
|
|
13
|
+
const payload = {
|
|
14
|
+
condition: snapshot.condition,
|
|
15
|
+
profiles: [...snapshot.profiles],
|
|
16
|
+
subject: {
|
|
17
|
+
id: snapshot.subject.id,
|
|
18
|
+
...(snapshot.subject.description ? { description: snapshot.subject.description } : {}),
|
|
19
|
+
...(snapshot.subject.version ? { version: snapshot.subject.version } : {}),
|
|
20
|
+
...(snapshot.subject.contact ? { contact: snapshot.subject.contact } : {}),
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
// Timing
|
|
24
|
+
if (snapshot.timing) {
|
|
25
|
+
payload.timing = { ...snapshot.timing };
|
|
26
|
+
}
|
|
27
|
+
// Provenance
|
|
28
|
+
if (snapshot.provenance) {
|
|
29
|
+
payload.provenance = snapshot.provenance;
|
|
30
|
+
}
|
|
31
|
+
// Evidence
|
|
32
|
+
if (snapshot.evidence) {
|
|
33
|
+
payload.evidence = {
|
|
34
|
+
type: snapshot.evidence.type,
|
|
35
|
+
...(snapshot.evidence.detail ? { detail: snapshot.evidence.detail } : {}),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// Scope
|
|
39
|
+
if (snapshot.scope) {
|
|
40
|
+
payload.scope = { ...snapshot.scope };
|
|
41
|
+
}
|
|
42
|
+
// Components — from nested array or convert from flat checks
|
|
43
|
+
if (snapshot.components) {
|
|
44
|
+
payload.components = snapshot.components.map(cloneComponent);
|
|
45
|
+
}
|
|
46
|
+
else if (snapshot.checks) {
|
|
47
|
+
payload.components = [];
|
|
48
|
+
payload.dependencies = [];
|
|
49
|
+
for (const [key, check] of Object.entries(snapshot.checks)) {
|
|
50
|
+
if (check.role === 'dependency') {
|
|
51
|
+
payload.dependencies.push({
|
|
52
|
+
id: key,
|
|
53
|
+
condition: check.condition,
|
|
54
|
+
...(check.timing ? { timing: check.timing } : {}),
|
|
55
|
+
...(check.provenance ? { provenance: check.provenance } : {}),
|
|
56
|
+
...(check.evidence ? { evidence: check.evidence } : {}),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
payload.components.push({
|
|
61
|
+
id: key,
|
|
62
|
+
condition: check.condition,
|
|
63
|
+
...(check.timing ? { timing: check.timing } : {}),
|
|
64
|
+
...(check.provenance ? { provenance: check.provenance } : {}),
|
|
65
|
+
...(check.evidence ? { evidence: check.evidence } : {}),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Dependencies (from nested array)
|
|
71
|
+
if (snapshot.dependencies) {
|
|
72
|
+
payload.dependencies = snapshot.dependencies.map((dep) => ({ ...dep }));
|
|
73
|
+
}
|
|
74
|
+
// Incidents
|
|
75
|
+
if (snapshot.incidents && snapshot.incidents.length > 0) {
|
|
76
|
+
payload.incidents = snapshot.incidents;
|
|
77
|
+
}
|
|
78
|
+
// Links
|
|
79
|
+
if (snapshot.links && Object.keys(snapshot.links).length > 0) {
|
|
80
|
+
payload.links = { ...snapshot.links };
|
|
81
|
+
}
|
|
82
|
+
return payload;
|
|
83
|
+
}
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
// Internal
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
function cloneComponent(comp) {
|
|
88
|
+
const clone = {
|
|
89
|
+
id: comp.id,
|
|
90
|
+
condition: comp.condition,
|
|
91
|
+
};
|
|
92
|
+
if (comp.description) {
|
|
93
|
+
clone.description = comp.description;
|
|
94
|
+
}
|
|
95
|
+
if (comp.criticality) {
|
|
96
|
+
clone.criticality = comp.criticality;
|
|
97
|
+
}
|
|
98
|
+
if (comp.timing) {
|
|
99
|
+
clone.timing = { ...comp.timing };
|
|
100
|
+
}
|
|
101
|
+
if (comp.provenance) {
|
|
102
|
+
clone.provenance = comp.provenance;
|
|
103
|
+
}
|
|
104
|
+
if (comp.evidence) {
|
|
105
|
+
clone.evidence = { ...comp.evidence };
|
|
106
|
+
}
|
|
107
|
+
if (comp.components) {
|
|
108
|
+
clone.components = comp.components.map(cloneComponent);
|
|
109
|
+
}
|
|
110
|
+
return clone;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=service-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-status.js","sourceRoot":"","sources":["../src/service-status.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqCH,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAE,QAAkB;IACjD,MAAM,OAAO,GAAyB;QAClC,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,QAAQ,EAAE,CAAE,GAAG,QAAQ,CAAC,QAAQ,CAAE;QAClC,OAAO,EAAE;YACL,EAAE,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE;YACvB,GAAG,CAAE,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAE;YACxF,GAAG,CAAE,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAE;YAC5E,GAAG,CAAE,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAE;SAC/E;KACJ,CAAC;IAEF,SAAS;IACT,IAAK,QAAQ,CAAC,MAAM,EAAG,CAAC;QACpB,OAAO,CAAC,MAAM,GAAG,EAAE,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;IAC5C,CAAC;IAED,aAAa;IACb,IAAK,QAAQ,CAAC,UAAU,EAAG,CAAC;QACxB,OAAO,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC;IAC7C,CAAC;IAED,WAAW;IACX,IAAK,QAAQ,CAAC,QAAQ,EAAG,CAAC;QACtB,OAAO,CAAC,QAAQ,GAAG;YACf,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI;YAC5B,GAAG,CAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAE;SAC9E,CAAC;IACN,CAAC;IAED,QAAQ;IACR,IAAK,QAAQ,CAAC,KAAK,EAAG,CAAC;QACnB,OAAO,CAAC,KAAK,GAAG,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;IAC1C,CAAC;IAED,6DAA6D;IAC7D,IAAK,QAAQ,CAAC,UAAU,EAAG,CAAC;QACxB,OAAO,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAE,cAAc,CAAE,CAAC;IACnE,CAAC;SAAM,IAAK,QAAQ,CAAC,MAAM,EAAG,CAAC;QAC3B,OAAO,CAAC,UAAU,GAAG,EAAE,CAAC;QACxB,OAAO,CAAC,YAAY,GAAG,EAAE,CAAC;QAC1B,KAAM,MAAM,CAAE,GAAG,EAAE,KAAK,CAAE,IAAI,MAAM,CAAC,OAAO,CAAE,QAAQ,CAAC,MAAM,CAAE,EAAG,CAAC;YAC/D,IAAK,KAAK,CAAC,IAAI,KAAK,YAAY,EAAG,CAAC;gBAChC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAE;oBACvB,EAAE,EAAE,GAAG;oBACP,SAAS,EAAE,KAAK,CAAC,SAAS;oBAC1B,GAAG,CAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAE;oBACnD,GAAG,CAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAE;oBAC/D,GAAG,CAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAE;iBAC5D,CAAE,CAAC;YACR,CAAC;iBAAM,CAAC;gBACJ,OAAO,CAAC,UAAU,CAAC,IAAI,CAAE;oBACrB,EAAE,EAAE,GAAG;oBACP,SAAS,EAAE,KAAK,CAAC,SAAS;oBAC1B,GAAG,CAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAE;oBACnD,GAAG,CAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAE;oBAC/D,GAAG,CAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAE;iBAC5D,CAAE,CAAC;YACR,CAAC;QACL,CAAC;IACL,CAAC;IAED,mCAAmC;IACnC,IAAK,QAAQ,CAAC,YAAY,EAAG,CAAC;QAC1B,OAAO,CAAC,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAE,CAAE,GAAG,EAAG,EAAE,CAAC,CAAE,EAAE,GAAG,GAAG,EAAE,CAAE,CAAE,CAAC;IAClF,CAAC;IAED,YAAY;IACZ,IAAK,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAG,CAAC;QACxD,OAAO,CAAC,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC;IAC3C,CAAC;IAED,QAAQ;IACR,IAAK,QAAQ,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAE,QAAQ,CAAC,KAAK,CAAE,CAAC,MAAM,GAAG,CAAC,EAAG,CAAC;QAC/D,OAAO,CAAC,KAAK,GAAG,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;IAC1C,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAED,8EAA8E;AAC9E,WAAW;AACX,8EAA8E;AAE9E,SAAS,cAAc,CAAE,IAAoB;IACzC,MAAM,KAAK,GAAmB;QAC1B,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,SAAS,EAAE,IAAI,CAAC,SAAS;KAC5B,CAAC;IACF,IAAK,IAAI,CAAC,WAAW,EAAG,CAAC;QAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IAAC,CAAC;IACjE,IAAK,IAAI,CAAC,WAAW,EAAG,CAAC;QAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IAAC,CAAC;IACjE,IAAK,IAAI,CAAC,MAAM,EAAG,CAAC;QAAC,KAAK,CAAC,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;IAAC,CAAC;IACzD,IAAK,IAAI,CAAC,UAAU,EAAG,CAAC;QAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IAAC,CAAC;IAC9D,IAAK,IAAI,CAAC,QAAQ,EAAG,CAAC;QAAC,KAAK,CAAC,QAAQ,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;IAAC,CAAC;IAC/D,IAAK,IAAI,CAAC,UAAU,EAAG,CAAC;QACpB,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAE,cAAc,CAAE,CAAC;IAC7D,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@open-operational-state/emitter",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Serialization emitters for Open Operational State wire formats",
|
|
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.git",
|
|
24
|
+
"directory": "packages/emitter"
|
|
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.1.0",
|
|
34
|
+
"@open-operational-state/core": "^0.1.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@open-operational-state/parser": "^0.1.0",
|
|
38
|
+
"typescript": "^5.8.0"
|
|
39
|
+
}
|
|
40
|
+
}
|