@open-operational-state/core 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 ADDED
@@ -0,0 +1,60 @@
1
+ # @open-operational-state/core
2
+
3
+ Core model logic for [Open Operational State](https://github.com/open-operational-state). Depends only on `@open-operational-state/types`.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add @open-operational-state/core
9
+ ```
10
+
11
+ ## API
12
+
13
+ ### `normalizeSnapshot( raw )`
14
+
15
+ Coerce a raw JSON object into a typed `Snapshot` with spec defaults applied.
16
+
17
+ ```js
18
+ import { normalizeSnapshot } from '@open-operational-state/core';
19
+
20
+ const snapshot = normalizeSnapshot({
21
+ condition: 'operational',
22
+ profiles: ['health'],
23
+ subject: { id: 'my-service' },
24
+ });
25
+ ```
26
+
27
+ ### `validateSnapshot( snapshot )`
28
+
29
+ Validate a `Snapshot` against required fields, vocabulary rules, and profile constraints. Returns `{ valid, errors, warnings }`.
30
+
31
+ ```js
32
+ import { validateSnapshot } from '@open-operational-state/core';
33
+
34
+ const result = validateSnapshot( snapshot );
35
+ if ( !result.valid ) {
36
+ console.error( result.errors );
37
+ }
38
+ ```
39
+
40
+ ### `worstOf( conditions )`
41
+
42
+ Return the worst (highest severity) condition from an array, using the orderable severity ranking.
43
+
44
+ ```js
45
+ import { worstOf } from '@open-operational-state/core';
46
+
47
+ worstOf([ 'operational', 'degraded', 'down' ]); // 'down'
48
+ ```
49
+
50
+ ### `deriveParentConditionFromChecks( checks )`
51
+
52
+ Derive a parent condition from flat check entries using worst-of aggregation.
53
+
54
+ ### `deriveParentConditionFromComponents( components )`
55
+
56
+ Derive a parent condition from nested component entries using worst-of aggregation.
57
+
58
+ ## Dependencies
59
+
60
+ - `@open-operational-state/types`
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Core Package Tests — Aggregation
3
+ *
4
+ * Direct unit tests for worstOf and condition derivation helpers.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=aggregate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregate.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/aggregate.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Core Package Tests — Aggregation
3
+ *
4
+ * Direct unit tests for worstOf and condition derivation helpers.
5
+ */
6
+ import { describe, it, expect } from 'bun:test';
7
+ import { worstOf, deriveParentConditionFromChecks, deriveParentConditionFromComponents } from '../aggregate.js';
8
+ describe('worstOf', () => {
9
+ it('returns the worst condition from an array', () => {
10
+ expect(worstOf(['operational', 'degraded', 'down'])).toBe('down');
11
+ });
12
+ it('returns operational when all are operational', () => {
13
+ expect(worstOf(['operational', 'operational'])).toBe('operational');
14
+ });
15
+ it('returns degraded when worst is degraded', () => {
16
+ expect(worstOf(['operational', 'degraded'])).toBe('degraded');
17
+ });
18
+ it('handles single-element arrays', () => {
19
+ expect(worstOf(['down'])).toBe('down');
20
+ });
21
+ it('returns unknown for empty arrays', () => {
22
+ expect(worstOf([])).toBe('unknown');
23
+ });
24
+ it('orders partial-outage between degraded and major-outage', () => {
25
+ expect(worstOf(['degraded', 'partial-outage'])).toBe('partial-outage');
26
+ expect(worstOf(['partial-outage', 'major-outage'])).toBe('major-outage');
27
+ });
28
+ it('skips non-orderable values and returns best orderable', () => {
29
+ expect(worstOf(['operational', 'x-custom'])).toBe('operational');
30
+ });
31
+ it('handles liveness conditions', () => {
32
+ expect(worstOf(['alive', 'unreachable'])).toBe('unreachable');
33
+ });
34
+ it('handles readiness conditions', () => {
35
+ expect(worstOf(['ready', 'not-ready'])).toBe('not-ready');
36
+ expect(worstOf(['ready', 'initializing'])).toBe('initializing');
37
+ });
38
+ });
39
+ describe('deriveParentConditionFromChecks', () => {
40
+ it('derives from flat checks', () => {
41
+ const result = deriveParentConditionFromChecks({
42
+ db: { condition: 'operational', role: 'dependency' },
43
+ cache: { condition: 'down', role: 'component' },
44
+ });
45
+ expect(result).toBe('down');
46
+ });
47
+ it('returns operational when all checks are operational', () => {
48
+ const result = deriveParentConditionFromChecks({
49
+ db: { condition: 'operational', role: 'dependency' },
50
+ api: { condition: 'operational', role: 'component' },
51
+ });
52
+ expect(result).toBe('operational');
53
+ });
54
+ it('returns unknown for empty checks', () => {
55
+ expect(deriveParentConditionFromChecks({})).toBe('unknown');
56
+ });
57
+ });
58
+ describe('deriveParentConditionFromComponents', () => {
59
+ it('derives from nested components', () => {
60
+ const result = deriveParentConditionFromComponents([
61
+ { id: 'api', condition: 'operational' },
62
+ { id: 'cache', condition: 'degraded' },
63
+ ]);
64
+ expect(result).toBe('degraded');
65
+ });
66
+ it('returns unknown for empty array', () => {
67
+ expect(deriveParentConditionFromComponents([])).toBe('unknown');
68
+ });
69
+ });
70
+ //# sourceMappingURL=aggregate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregate.test.js","sourceRoot":"","sources":["../../src/__tests__/aggregate.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Core Package Tests — Normalization
3
+ *
4
+ * Direct unit tests for normalizeSnapshot.
5
+ * These must not rely on parser/validator/emitter to exercise core logic.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=normalize.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/normalize.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Core Package Tests — Normalization
3
+ *
4
+ * Direct unit tests for normalizeSnapshot.
5
+ * These must not rely on parser/validator/emitter to exercise core logic.
6
+ */
7
+ import { describe, it, expect } from 'bun:test';
8
+ import { normalizeSnapshot } from '../normalize.js';
9
+ describe('normalizeSnapshot', () => {
10
+ it('normalizes a minimal valid input', () => {
11
+ const result = normalizeSnapshot({
12
+ condition: 'operational',
13
+ profiles: ['health'],
14
+ subject: { id: 'svc-1' },
15
+ });
16
+ expect(result.condition).toBe('operational');
17
+ expect(result.profiles).toEqual(['health']);
18
+ expect(result.subject.id).toBe('svc-1');
19
+ });
20
+ it('defaults profiles to empty array if missing', () => {
21
+ const result = normalizeSnapshot({
22
+ condition: 'operational',
23
+ subject: { id: 'svc-1' },
24
+ });
25
+ expect(result.profiles).toEqual([]);
26
+ });
27
+ it('defaults subject to empty id if missing', () => {
28
+ const result = normalizeSnapshot({
29
+ condition: 'operational',
30
+ profiles: ['health'],
31
+ });
32
+ expect(result.subject.id).toBe('');
33
+ });
34
+ it('defaults condition to empty string if missing', () => {
35
+ const result = normalizeSnapshot({
36
+ profiles: ['health'],
37
+ subject: { id: 'svc-1' },
38
+ });
39
+ expect(result.condition).toBe('');
40
+ });
41
+ it('preserves timing fields', () => {
42
+ const result = normalizeSnapshot({
43
+ condition: 'operational',
44
+ profiles: ['health'],
45
+ subject: { id: 'svc-1' },
46
+ timing: {
47
+ observed: '2026-04-02T19:30:00Z',
48
+ reported: '2026-04-02T19:30:01Z',
49
+ stateChanged: '2026-04-02T19:00:00Z',
50
+ },
51
+ });
52
+ expect(result.timing?.observed).toBe('2026-04-02T19:30:00Z');
53
+ expect(result.timing?.reported).toBe('2026-04-02T19:30:01Z');
54
+ expect(result.timing?.stateChanged).toBe('2026-04-02T19:00:00Z');
55
+ });
56
+ it('preserves provenance', () => {
57
+ const result = normalizeSnapshot({
58
+ condition: 'alive',
59
+ profiles: ['liveness'],
60
+ subject: { id: 'svc-1' },
61
+ provenance: 'externally-observed',
62
+ });
63
+ expect(result.provenance).toBe('externally-observed');
64
+ });
65
+ it('preserves evidence', () => {
66
+ const result = normalizeSnapshot({
67
+ condition: 'degraded',
68
+ profiles: ['health'],
69
+ subject: { id: 'svc-1' },
70
+ evidence: { type: 'error-rate', detail: '7.2%' },
71
+ });
72
+ expect(result.evidence?.type).toBe('error-rate');
73
+ expect(result.evidence?.detail).toBe('7.2%');
74
+ });
75
+ it('preserves flat checks', () => {
76
+ const result = normalizeSnapshot({
77
+ condition: 'degraded',
78
+ profiles: ['health'],
79
+ subject: { id: 'svc-1' },
80
+ checks: {
81
+ db: { condition: 'operational', role: 'dependency' },
82
+ cache: { condition: 'down', role: 'component' },
83
+ },
84
+ });
85
+ expect(result.checks).toBeDefined();
86
+ expect(result.checks['db'].condition).toBe('operational');
87
+ expect(result.checks['db'].role).toBe('dependency');
88
+ expect(result.checks['cache'].condition).toBe('down');
89
+ });
90
+ it('preserves nested components', () => {
91
+ const result = normalizeSnapshot({
92
+ condition: 'degraded',
93
+ profiles: ['status'],
94
+ subject: { id: 'svc-1' },
95
+ components: [
96
+ { id: 'api', condition: 'operational' },
97
+ { id: 'cache', condition: 'down' },
98
+ ],
99
+ });
100
+ expect(result.components?.length).toBe(2);
101
+ expect(result.components[0].id).toBe('api');
102
+ expect(result.components[1].condition).toBe('down');
103
+ });
104
+ it('preserves nested dependencies', () => {
105
+ const result = normalizeSnapshot({
106
+ condition: 'operational',
107
+ profiles: ['status'],
108
+ subject: { id: 'svc-1' },
109
+ dependencies: [
110
+ { id: 'pg', condition: 'operational' },
111
+ ],
112
+ });
113
+ expect(result.dependencies?.length).toBe(1);
114
+ expect(result.dependencies[0].id).toBe('pg');
115
+ });
116
+ it('preserves scope', () => {
117
+ const result = normalizeSnapshot({
118
+ condition: 'operational',
119
+ profiles: ['status'],
120
+ subject: { id: 'svc-1' },
121
+ scope: { type: 'region', identifier: 'us-east-1' },
122
+ });
123
+ expect(result.scope?.type).toBe('region');
124
+ expect(result.scope?.identifier).toBe('us-east-1');
125
+ });
126
+ it('preserves links', () => {
127
+ const result = normalizeSnapshot({
128
+ condition: 'operational',
129
+ profiles: ['health'],
130
+ subject: { id: 'svc-1' },
131
+ links: { self: 'https://example.com/health' },
132
+ });
133
+ expect(result.links?.self).toBe('https://example.com/health');
134
+ });
135
+ it('preserves extension condition values', () => {
136
+ const result = normalizeSnapshot({
137
+ condition: 'x-acme-draining',
138
+ profiles: ['health'],
139
+ subject: { id: 'svc-1' },
140
+ });
141
+ expect(result.condition).toBe('x-acme-draining');
142
+ });
143
+ it('handles empty object input', () => {
144
+ const result = normalizeSnapshot({});
145
+ expect(result.condition).toBe('');
146
+ expect(result.profiles).toEqual([]);
147
+ expect(result.subject.id).toBe('');
148
+ });
149
+ });
150
+ //# sourceMappingURL=normalize.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.test.js","sourceRoot":"","sources":["../../src/__tests__/normalize.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Core Package Tests — Validation
3
+ *
4
+ * Direct unit tests for validateSnapshot.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=validate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/validate.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Core Package Tests — Validation
3
+ *
4
+ * Direct unit tests for validateSnapshot.
5
+ */
6
+ import { describe, it, expect } from 'bun:test';
7
+ import { validateSnapshot } from '../validate-model.js';
8
+ import { normalizeSnapshot } from '../normalize.js';
9
+ // Helper: normalize then validate
10
+ function validate(raw) {
11
+ return validateSnapshot(normalizeSnapshot(raw));
12
+ }
13
+ describe('validateSnapshot', () => {
14
+ // ── Required fields ────────────────────────────────────────────────
15
+ it('accepts a valid minimal snapshot', () => {
16
+ const result = validate({
17
+ condition: 'operational',
18
+ profiles: ['health'],
19
+ subject: { id: 'svc-1' },
20
+ timing: { observed: '2026-04-02T19:30:00Z' },
21
+ });
22
+ expect(result.valid).toBe(true);
23
+ expect(result.errors.length).toBe(0);
24
+ });
25
+ it('rejects missing condition', () => {
26
+ const result = validate({
27
+ profiles: ['health'],
28
+ subject: { id: 'svc-1' },
29
+ });
30
+ expect(result.valid).toBe(false);
31
+ expect(result.errors.some((e) => e.code === 'MISSING_CONDITION')).toBe(true);
32
+ });
33
+ it('rejects missing subject.id', () => {
34
+ const result = validate({
35
+ condition: 'operational',
36
+ profiles: ['health'],
37
+ });
38
+ expect(result.valid).toBe(false);
39
+ expect(result.errors.some((e) => e.code === 'MISSING_SUBJECT_ID')).toBe(true);
40
+ });
41
+ it('rejects missing profiles', () => {
42
+ const result = validate({
43
+ condition: 'operational',
44
+ subject: { id: 'svc-1' },
45
+ });
46
+ expect(result.valid).toBe(false);
47
+ expect(result.errors.some((e) => e.code === 'MISSING_PROFILES')).toBe(true);
48
+ });
49
+ // ── Vocabulary validation ──────────────────────────────────────────
50
+ it('rejects invalid condition value for declared profile', () => {
51
+ const result = validate({
52
+ condition: 'invalid-value',
53
+ profiles: ['liveness'],
54
+ subject: { id: 'svc-1' },
55
+ });
56
+ expect(result.valid).toBe(false);
57
+ expect(result.errors.some((e) => e.code === 'INVALID_CONDITION')).toBe(true);
58
+ });
59
+ it('accepts valid liveness conditions', () => {
60
+ for (const condition of ['alive', 'unreachable']) {
61
+ const result = validate({
62
+ condition,
63
+ profiles: ['liveness'],
64
+ subject: { id: 'svc-1' },
65
+ });
66
+ expect(result.valid).toBe(true);
67
+ }
68
+ });
69
+ it('accepts valid readiness conditions', () => {
70
+ for (const condition of ['ready', 'initializing', 'not-ready']) {
71
+ const result = validate({
72
+ condition,
73
+ profiles: ['readiness'],
74
+ subject: { id: 'svc-1' },
75
+ });
76
+ expect(result.valid).toBe(true);
77
+ }
78
+ });
79
+ it('accepts valid health conditions', () => {
80
+ for (const condition of ['operational', 'degraded', 'partial-outage', 'major-outage', 'down']) {
81
+ const result = validate({
82
+ condition,
83
+ profiles: ['health'],
84
+ subject: { id: 'svc-1' },
85
+ timing: { observed: '2026-04-02T19:30:00Z' },
86
+ });
87
+ expect(result.valid).toBe(true);
88
+ }
89
+ });
90
+ it('accepts categorical conditions', () => {
91
+ for (const condition of ['maintenance', 'unknown']) {
92
+ const result = validate({
93
+ condition,
94
+ profiles: ['health'],
95
+ subject: { id: 'svc-1' },
96
+ timing: { observed: '2026-04-02T19:30:00Z' },
97
+ });
98
+ expect(result.valid).toBe(true);
99
+ }
100
+ });
101
+ it('accepts extension condition values', () => {
102
+ const result = validate({
103
+ condition: 'x-acme-draining',
104
+ profiles: ['health'],
105
+ subject: { id: 'svc-1' },
106
+ timing: { observed: '2026-04-02T19:30:00Z' },
107
+ });
108
+ expect(result.valid).toBe(true);
109
+ });
110
+ // ── Timing validation ──────────────────────────────────────────────
111
+ it('accepts valid RFC 3339 timestamps', () => {
112
+ const result = validate({
113
+ condition: 'operational',
114
+ profiles: ['health'],
115
+ subject: { id: 'svc-1' },
116
+ timing: { observed: '2026-04-02T19:30:00Z' },
117
+ });
118
+ expect(result.valid).toBe(true);
119
+ });
120
+ it('warns on invalid timestamp format', () => {
121
+ const result = validate({
122
+ condition: 'operational',
123
+ profiles: ['health'],
124
+ subject: { id: 'svc-1' },
125
+ timing: { observed: 'not-a-date' },
126
+ });
127
+ // May produce warnings or errors depending on strictness
128
+ expect(result.warnings.length + result.errors.length).toBeGreaterThan(0);
129
+ });
130
+ // ── Profile requirement enforcement ────────────────────────────────
131
+ it('enforces timing requirement for standard conformance', () => {
132
+ const result = validate({
133
+ condition: 'operational',
134
+ profiles: ['health'],
135
+ subject: { id: 'svc-1' },
136
+ timing: { observed: '2026-04-02T19:30:00Z' },
137
+ provenance: 'self-reported',
138
+ });
139
+ // With timing + provenance, should be valid
140
+ expect(result.valid).toBe(true);
141
+ });
142
+ // ── Check entry validation ─────────────────────────────────────────
143
+ it('validates check entry conditions', () => {
144
+ const result = validate({
145
+ condition: 'degraded',
146
+ profiles: ['health'],
147
+ subject: { id: 'svc-1' },
148
+ timing: { observed: '2026-04-02T19:30:00Z' },
149
+ checks: {
150
+ db: { condition: 'operational', role: 'dependency' },
151
+ },
152
+ });
153
+ expect(result.valid).toBe(true);
154
+ });
155
+ // ── Provenance validation ──────────────────────────────────────────
156
+ it('accepts valid provenance values', () => {
157
+ for (const provenance of ['self-reported', 'externally-observed', 'synthetic']) {
158
+ const result = validate({
159
+ condition: 'operational',
160
+ profiles: ['health'],
161
+ subject: { id: 'svc-1' },
162
+ timing: { observed: '2026-04-02T19:30:00Z' },
163
+ provenance,
164
+ });
165
+ expect(result.valid).toBe(true);
166
+ }
167
+ });
168
+ });
169
+ //# sourceMappingURL=validate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.test.js","sourceRoot":"","sources":["../../src/__tests__/validate.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Condition Aggregation
3
+ *
4
+ * Worst-of and derived-parent logic per the core model and profiles spec.
5
+ */
6
+ import type { CheckEntry, ComponentEntry } from '@open-operational-state/types';
7
+ /**
8
+ * Returns the worst (highest severity) orderable condition from a list.
9
+ *
10
+ * Non-orderable values (categorical and extension) are skipped — they
11
+ * do not participate in worst-of calculations per the spec.
12
+ *
13
+ * Returns `'unknown'` if no orderable values are present (including
14
+ * empty arrays).
15
+ */
16
+ export declare function worstOf(conditions: string[]): string;
17
+ /**
18
+ * Derive a parent condition from flat check entries (health-response style).
19
+ *
20
+ * Uses worst-of aggregation across orderable condition values.
21
+ * Categorical values are reported but do not participate.
22
+ */
23
+ export declare function deriveParentConditionFromChecks(checks: Record<string, CheckEntry>): string;
24
+ /**
25
+ * Derive a parent condition from nested component entries (service-status style).
26
+ *
27
+ * Uses worst-of aggregation across orderable condition values.
28
+ */
29
+ export declare function deriveParentConditionFromComponents(components: ComponentEntry[]): string;
30
+ //# sourceMappingURL=aggregate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregate.d.ts","sourceRoot":"","sources":["../src/aggregate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAkBhF;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAE,UAAU,EAAE,MAAM,EAAE,GAAI,MAAM,CActD;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC3C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GACnC,MAAM,CAGR;AAED;;;;GAIG;AACH,wBAAgB,mCAAmC,CAC/C,UAAU,EAAE,cAAc,EAAE,GAC7B,MAAM,CAGR"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Condition Aggregation
3
+ *
4
+ * Worst-of and derived-parent logic per the core model and profiles spec.
5
+ */
6
+ import { conditionSeverity, isOrderableCondition, HEALTH_ORDERABLE_CONDITIONS, } from '@open-operational-state/types';
7
+ // ---------------------------------------------------------------------------
8
+ // Reverse-lookup: severity number → condition string
9
+ // ---------------------------------------------------------------------------
10
+ const SEVERITY_TO_CONDITION = {};
11
+ for (const c of HEALTH_ORDERABLE_CONDITIONS) {
12
+ const sev = conditionSeverity(c);
13
+ if (sev !== undefined) {
14
+ SEVERITY_TO_CONDITION[sev] = c;
15
+ }
16
+ }
17
+ // ---------------------------------------------------------------------------
18
+ // Public API
19
+ // ---------------------------------------------------------------------------
20
+ /**
21
+ * Returns the worst (highest severity) orderable condition from a list.
22
+ *
23
+ * Non-orderable values (categorical and extension) are skipped — they
24
+ * do not participate in worst-of calculations per the spec.
25
+ *
26
+ * Returns `'unknown'` if no orderable values are present (including
27
+ * empty arrays).
28
+ */
29
+ export function worstOf(conditions) {
30
+ let worstSeverity = -1;
31
+ let worstCondition;
32
+ for (const c of conditions) {
33
+ if (!isOrderableCondition(c)) {
34
+ continue;
35
+ }
36
+ const sev = conditionSeverity(c);
37
+ if (sev > worstSeverity) {
38
+ worstSeverity = sev;
39
+ worstCondition = c;
40
+ }
41
+ }
42
+ return worstCondition ?? 'unknown';
43
+ }
44
+ /**
45
+ * Derive a parent condition from flat check entries (health-response style).
46
+ *
47
+ * Uses worst-of aggregation across orderable condition values.
48
+ * Categorical values are reported but do not participate.
49
+ */
50
+ export function deriveParentConditionFromChecks(checks) {
51
+ const conditions = Object.values(checks).map((c) => c.condition);
52
+ return worstOf(conditions);
53
+ }
54
+ /**
55
+ * Derive a parent condition from nested component entries (service-status style).
56
+ *
57
+ * Uses worst-of aggregation across orderable condition values.
58
+ */
59
+ export function deriveParentConditionFromComponents(components) {
60
+ const conditions = components.map((c) => c.condition);
61
+ return worstOf(conditions);
62
+ }
63
+ //# sourceMappingURL=aggregate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregate.js","sourceRoot":"","sources":["../src/aggregate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACH,iBAAiB,EACjB,oBAAoB,EACpB,2BAA2B,GAC9B,MAAM,+BAA+B,CAAC;AAGvC,8EAA8E;AAC9E,qDAAqD;AACrD,8EAA8E;AAE9E,MAAM,qBAAqB,GAA2B,EAAE,CAAC;AACzD,KAAM,MAAM,CAAC,IAAI,2BAA2B,EAAG,CAAC;IAC5C,MAAM,GAAG,GAAG,iBAAiB,CAAE,CAAC,CAAE,CAAC;IACnC,IAAK,GAAG,KAAK,SAAS,EAAG,CAAC;QACtB,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,MAAM,UAAU,OAAO,CAAE,UAAoB;IACzC,IAAI,aAAa,GAAG,CAAC,CAAC,CAAC;IACvB,IAAI,cAAkC,CAAC;IAEvC,KAAM,MAAM,CAAC,IAAI,UAAU,EAAG,CAAC;QAC3B,IAAK,CAAC,oBAAoB,CAAE,CAAC,CAAE,EAAG,CAAC;YAAC,SAAS;QAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,iBAAiB,CAAE,CAAC,CAAG,CAAC;QACpC,IAAK,GAAG,GAAG,aAAa,EAAG,CAAC;YACxB,aAAa,GAAG,GAAG,CAAC;YACpB,cAAc,GAAG,CAAC,CAAC;QACvB,CAAC;IACL,CAAC;IAED,OAAO,cAAc,IAAI,SAAS,CAAC;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,+BAA+B,CAC3C,MAAkC;IAElC,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAE,MAAM,CAAE,CAAC,GAAG,CAAE,CAAE,CAAC,EAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAE,CAAC;IACvE,OAAO,OAAO,CAAE,UAAU,CAAE,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mCAAmC,CAC/C,UAA4B;IAE5B,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAE,CAAE,CAAC,EAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAE,CAAC;IAC1D,OAAO,OAAO,CAAE,UAAU,CAAE,CAAC;AACjC,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @open-operational-state/core
3
+ *
4
+ * Core model logic: normalization, aggregation, and validation.
5
+ *
6
+ * Depends only on @open-operational-state/types.
7
+ */
8
+ export { normalizeSnapshot } from './normalize.js';
9
+ export { worstOf, deriveParentConditionFromChecks, deriveParentConditionFromComponents } from './aggregate.js';
10
+ export { validateSnapshot } from './validate-model.js';
11
+ //# 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,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,+BAA+B,EAAE,mCAAmC,EAAE,MAAM,gBAAgB,CAAC;AAC/G,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @open-operational-state/core
3
+ *
4
+ * Core model logic: normalization, aggregation, and validation.
5
+ *
6
+ * Depends only on @open-operational-state/types.
7
+ */
8
+ export { normalizeSnapshot } from './normalize.js';
9
+ export { worstOf, deriveParentConditionFromChecks, deriveParentConditionFromComponents } from './aggregate.js';
10
+ export { validateSnapshot } from './validate-model.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,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,+BAA+B,EAAE,mCAAmC,EAAE,MAAM,gBAAgB,CAAC;AAC/G,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Snapshot Normalization
3
+ *
4
+ * Coerces raw JSON into a typed Snapshot, applying spec-defined defaults.
5
+ */
6
+ import type { Snapshot } from '@open-operational-state/types';
7
+ /**
8
+ * Normalize a raw (parsed-JSON) object into a typed Snapshot.
9
+ *
10
+ * This does NOT validate — it applies structural defaults so downstream
11
+ * code can rely on consistent shapes. Invalid data passes through;
12
+ * use `validateSnapshot` for correctness checks.
13
+ */
14
+ export declare function normalizeSnapshot(input: Record<string, unknown>): Snapshot;
15
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAgD,MAAM,+BAA+B,CAAC;AAE5G;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAI,QAAQ,CAkC5E"}
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Snapshot Normalization
3
+ *
4
+ * Coerces raw JSON into a typed Snapshot, applying spec-defined defaults.
5
+ */
6
+ /**
7
+ * Normalize a raw (parsed-JSON) object into a typed Snapshot.
8
+ *
9
+ * This does NOT validate — it applies structural defaults so downstream
10
+ * code can rely on consistent shapes. Invalid data passes through;
11
+ * use `validateSnapshot` for correctness checks.
12
+ */
13
+ export function normalizeSnapshot(input) {
14
+ const subject = normalizeSubject(input.subject);
15
+ const timing = normalizeTiming(input.timing);
16
+ const evidence = normalizeEvidence(input.evidence);
17
+ const scope = normalizeScope(input.scope);
18
+ const checks = normalizeChecks(input.checks);
19
+ const snapshot = {
20
+ condition: typeof input.condition === 'string' ? input.condition : '',
21
+ profiles: normalizeProfiles(input.profiles),
22
+ subject,
23
+ };
24
+ if (timing) {
25
+ snapshot.timing = timing;
26
+ }
27
+ if (typeof input.provenance === 'string') {
28
+ snapshot.provenance = input.provenance;
29
+ }
30
+ if (evidence) {
31
+ snapshot.evidence = evidence;
32
+ }
33
+ if (scope) {
34
+ snapshot.scope = scope;
35
+ }
36
+ if (checks) {
37
+ snapshot.checks = checks;
38
+ }
39
+ if (input.links && typeof input.links === 'object') {
40
+ snapshot.links = input.links;
41
+ }
42
+ // service-status nested arrays
43
+ if (Array.isArray(input.components)) {
44
+ snapshot.components = input.components;
45
+ }
46
+ if (Array.isArray(input.dependencies)) {
47
+ snapshot.dependencies = input.dependencies;
48
+ }
49
+ if (Array.isArray(input.incidents)) {
50
+ snapshot.incidents = input.incidents;
51
+ }
52
+ return snapshot;
53
+ }
54
+ // ---------------------------------------------------------------------------
55
+ // Internal helpers
56
+ // ---------------------------------------------------------------------------
57
+ function normalizeSubject(raw) {
58
+ if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
59
+ const obj = raw;
60
+ return {
61
+ id: typeof obj.id === 'string' ? obj.id : '',
62
+ ...(typeof obj.description === 'string' ? { description: obj.description } : {}),
63
+ ...(typeof obj.version === 'string' ? { version: obj.version } : {}),
64
+ ...(typeof obj.contact === 'string' ? { contact: obj.contact } : {}),
65
+ };
66
+ }
67
+ return { id: '' };
68
+ }
69
+ function normalizeTiming(raw) {
70
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
71
+ return undefined;
72
+ }
73
+ const obj = raw;
74
+ const timing = {};
75
+ if (typeof obj.observed === 'string') {
76
+ timing.observed = obj.observed;
77
+ }
78
+ if (typeof obj.reported === 'string') {
79
+ timing.reported = obj.reported;
80
+ }
81
+ if (typeof obj.stateChanged === 'string') {
82
+ timing.stateChanged = obj.stateChanged;
83
+ }
84
+ return Object.keys(timing).length > 0 ? timing : undefined;
85
+ }
86
+ function normalizeEvidence(raw) {
87
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
88
+ return undefined;
89
+ }
90
+ const obj = raw;
91
+ if (typeof obj.type !== 'string') {
92
+ return undefined;
93
+ }
94
+ const evidence = { type: obj.type };
95
+ if (typeof obj.detail === 'string') {
96
+ evidence.detail = obj.detail;
97
+ }
98
+ if (obj.observedValue !== undefined) {
99
+ evidence.observedValue = obj.observedValue;
100
+ }
101
+ if (typeof obj.observedUnit === 'string') {
102
+ evidence.observedUnit = obj.observedUnit;
103
+ }
104
+ return evidence;
105
+ }
106
+ function normalizeScope(raw) {
107
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
108
+ return undefined;
109
+ }
110
+ const obj = raw;
111
+ if (typeof obj.type !== 'string') {
112
+ return undefined;
113
+ }
114
+ const scope = { type: obj.type };
115
+ if (typeof obj.identifier === 'string') {
116
+ scope.identifier = obj.identifier;
117
+ }
118
+ return scope;
119
+ }
120
+ function normalizeChecks(raw) {
121
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
122
+ return undefined;
123
+ }
124
+ const obj = raw;
125
+ const checks = {};
126
+ for (const [key, value] of Object.entries(obj)) {
127
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
128
+ const entry = value;
129
+ const check = {
130
+ condition: typeof entry.condition === 'string' ? entry.condition : '',
131
+ };
132
+ if (entry.role === 'component' || entry.role === 'dependency') {
133
+ check.role = entry.role;
134
+ }
135
+ const timing = normalizeTiming(entry.timing);
136
+ if (timing) {
137
+ check.timing = timing;
138
+ }
139
+ if (typeof entry.provenance === 'string') {
140
+ check.provenance = entry.provenance;
141
+ }
142
+ const evidence = normalizeEvidence(entry.evidence);
143
+ if (evidence) {
144
+ check.evidence = evidence;
145
+ }
146
+ checks[key] = check;
147
+ }
148
+ }
149
+ return Object.keys(checks).length > 0 ? checks : undefined;
150
+ }
151
+ function normalizeProfiles(raw) {
152
+ if (Array.isArray(raw)) {
153
+ return raw.filter((v) => typeof v === 'string');
154
+ }
155
+ return [];
156
+ }
157
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Snapshot Validation
3
+ *
4
+ * Structural and semantic validation of a Snapshot against the core model
5
+ * and declared profiles.
6
+ */
7
+ import type { Snapshot, ValidationResult } from '@open-operational-state/types';
8
+ /**
9
+ * Validate a Snapshot for structural correctness and semantic compliance
10
+ * against the core model and declared profiles.
11
+ */
12
+ export declare function validateSnapshot(snapshot: Snapshot): ValidationResult;
13
+ //# sourceMappingURL=validate-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-model.d.ts","sourceRoot":"","sources":["../src/validate-model.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACR,QAAQ,EACR,gBAAgB,EAInB,MAAM,+BAA+B,CAAC;AA0BvC;;;GAGG;AACH,wBAAgB,gBAAgB,CAAE,QAAQ,EAAE,QAAQ,GAAI,gBAAgB,CAmHvE"}
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Snapshot Validation
3
+ *
4
+ * Structural and semantic validation of a Snapshot against the core model
5
+ * and declared profiles.
6
+ */
7
+ import { isProfileId, isHealthCondition, isLivenessCondition, isReadinessCondition, isExtensionCondition, isProvenance, PROFILE_REQUIREMENTS, } from '@open-operational-state/types';
8
+ // ---------------------------------------------------------------------------
9
+ // RFC 3339 timestamp pattern (basic, not exhaustive)
10
+ // ---------------------------------------------------------------------------
11
+ const RFC3339_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
12
+ function isRfc3339(value) {
13
+ return RFC3339_PATTERN.test(value);
14
+ }
15
+ // ---------------------------------------------------------------------------
16
+ // Public API
17
+ // ---------------------------------------------------------------------------
18
+ /**
19
+ * Validate a Snapshot for structural correctness and semantic compliance
20
+ * against the core model and declared profiles.
21
+ */
22
+ export function validateSnapshot(snapshot) {
23
+ const errors = [];
24
+ const warnings = [];
25
+ // ── Required fields ────────────────────────────────────────────────
26
+ if (!snapshot.condition || typeof snapshot.condition !== 'string') {
27
+ errors.push({
28
+ path: 'condition',
29
+ message: 'Missing required field: condition',
30
+ code: 'MISSING_CONDITION',
31
+ });
32
+ }
33
+ if (!snapshot.subject || typeof snapshot.subject.id !== 'string' || !snapshot.subject.id) {
34
+ errors.push({
35
+ path: 'subject.id',
36
+ message: 'Missing required field: subject.id',
37
+ code: 'MISSING_SUBJECT_ID',
38
+ });
39
+ }
40
+ if (!Array.isArray(snapshot.profiles) || snapshot.profiles.length === 0) {
41
+ errors.push({
42
+ path: 'profiles',
43
+ message: 'Missing required field: profiles (must be non-empty array)',
44
+ code: 'MISSING_PROFILES',
45
+ });
46
+ }
47
+ // ── Profile identifiers ────────────────────────────────────────────
48
+ const validProfiles = [];
49
+ if (Array.isArray(snapshot.profiles)) {
50
+ for (const p of snapshot.profiles) {
51
+ if (isProfileId(p)) {
52
+ validProfiles.push(p);
53
+ }
54
+ else {
55
+ errors.push({
56
+ path: 'profiles',
57
+ message: `Invalid profile identifier: '${p}'`,
58
+ code: 'INVALID_PROFILE',
59
+ });
60
+ }
61
+ }
62
+ }
63
+ // ── Condition value vs declared profiles ────────────────────────────
64
+ if (snapshot.condition) {
65
+ validateConditionForProfiles(snapshot.condition, validProfiles, errors);
66
+ }
67
+ // ── Provenance ─────────────────────────────────────────────────────
68
+ if (snapshot.provenance !== undefined) {
69
+ if (typeof snapshot.provenance !== 'string') {
70
+ errors.push({
71
+ path: 'provenance',
72
+ message: 'Provenance must be a string',
73
+ code: 'INVALID_PROVENANCE_TYPE',
74
+ });
75
+ }
76
+ else if (!isProvenance(snapshot.provenance) && !isExtensionCondition(snapshot.provenance)) {
77
+ warnings.push({
78
+ path: 'provenance',
79
+ message: `Unrecognized provenance type: '${snapshot.provenance}'`,
80
+ code: 'UNKNOWN_PROVENANCE',
81
+ });
82
+ }
83
+ }
84
+ // ── Timing format ──────────────────────────────────────────────────
85
+ if (snapshot.timing) {
86
+ for (const field of ['observed', 'reported', 'stateChanged']) {
87
+ const value = snapshot.timing[field];
88
+ if (value !== undefined && !isRfc3339(value)) {
89
+ errors.push({
90
+ path: `timing.${field}`,
91
+ message: `Timing field '${field}' is not valid RFC 3339: '${value}'`,
92
+ code: 'INVALID_TIMESTAMP',
93
+ });
94
+ }
95
+ }
96
+ }
97
+ // ── Profile-level MUST requirements ─────────────────────────────────
98
+ for (const profileId of validProfiles) {
99
+ validateProfileRequirements(snapshot, profileId, errors, warnings);
100
+ }
101
+ // ── Check entry conditions ─────────────────────────────────────────
102
+ if (snapshot.checks) {
103
+ for (const [key, entry] of Object.entries(snapshot.checks)) {
104
+ if (!entry.condition) {
105
+ errors.push({
106
+ path: `checks.${key}.condition`,
107
+ message: `Check '${key}' is missing required field: condition`,
108
+ code: 'MISSING_CHECK_CONDITION',
109
+ });
110
+ }
111
+ else if (!isHealthCondition(entry.condition) &&
112
+ !isLivenessCondition(entry.condition) &&
113
+ !isReadinessCondition(entry.condition) &&
114
+ !isExtensionCondition(entry.condition)) {
115
+ errors.push({
116
+ path: `checks.${key}.condition`,
117
+ message: `Invalid condition value in check '${key}': '${entry.condition}'`,
118
+ code: 'INVALID_CHECK_CONDITION',
119
+ });
120
+ }
121
+ }
122
+ }
123
+ return {
124
+ valid: errors.length === 0,
125
+ errors,
126
+ warnings,
127
+ };
128
+ }
129
+ // ---------------------------------------------------------------------------
130
+ // Internal helpers
131
+ // ---------------------------------------------------------------------------
132
+ function validateConditionForProfiles(condition, profiles, errors) {
133
+ for (const profile of profiles) {
134
+ let valid = false;
135
+ switch (profile) {
136
+ case 'liveness':
137
+ valid = isLivenessCondition(condition);
138
+ break;
139
+ case 'readiness':
140
+ valid = isReadinessCondition(condition);
141
+ break;
142
+ case 'health':
143
+ case 'status':
144
+ valid = isHealthCondition(condition) || isExtensionCondition(condition);
145
+ break;
146
+ }
147
+ // If multiple profiles are declared, the condition must be valid
148
+ // in ALL declared vocabularies — OR the implementation uses a
149
+ // Health/Status value that subsumes the simpler profiles.
150
+ // For practical single-vocab cases, we check each profile.
151
+ // A Health value like 'operational' isn't in liveness vocab ('alive'),
152
+ // but per the profile hierarchy, a Health response satisfies Liveness.
153
+ // We only flag if the condition isn't valid in ANY profile's vocabulary.
154
+ if (!valid && !isExtensionCondition(condition)) {
155
+ // Check if valid in a higher profile's vocabulary
156
+ const validInAnyVocab = isLivenessCondition(condition) ||
157
+ isReadinessCondition(condition) ||
158
+ isHealthCondition(condition);
159
+ if (!validInAnyVocab) {
160
+ errors.push({
161
+ path: 'condition',
162
+ message: `Invalid condition value: '${condition}' is not in the ${profile} vocabulary and does not use x-{vendor}-{value} extension format`,
163
+ code: 'INVALID_CONDITION',
164
+ });
165
+ return; // One error is enough
166
+ }
167
+ }
168
+ }
169
+ }
170
+ function validateProfileRequirements(snapshot, profileId, errors, warnings) {
171
+ const reqs = PROFILE_REQUIREMENTS[profileId];
172
+ // Timing
173
+ if (reqs.timing === 'MUST' && !snapshot.timing) {
174
+ errors.push({
175
+ path: 'timing',
176
+ message: `Profile '${profileId}' requires timing`,
177
+ code: 'PROFILE_MISSING_TIMING',
178
+ });
179
+ }
180
+ // Evidence
181
+ if (reqs.evidence === 'MUST' && !snapshot.evidence) {
182
+ errors.push({
183
+ path: 'evidence',
184
+ message: `Profile '${profileId}' requires evidence`,
185
+ code: 'PROFILE_MISSING_EVIDENCE',
186
+ });
187
+ }
188
+ else if (reqs.evidence === 'SHOULD' && !snapshot.evidence) {
189
+ warnings.push({
190
+ path: 'evidence',
191
+ message: `Profile '${profileId}' recommends evidence`,
192
+ code: 'PROFILE_RECOMMEND_EVIDENCE',
193
+ });
194
+ }
195
+ // Components
196
+ if (reqs.components === 'MUST' && !snapshot.checks && !snapshot.components) {
197
+ errors.push({
198
+ path: 'components',
199
+ message: `Profile '${profileId}' requires components`,
200
+ code: 'PROFILE_MISSING_COMPONENTS',
201
+ });
202
+ }
203
+ // Dependencies
204
+ if (reqs.dependencies === 'MUST' && !snapshot.checks && !snapshot.dependencies) {
205
+ errors.push({
206
+ path: 'dependencies',
207
+ message: `Profile '${profileId}' requires dependencies`,
208
+ code: 'PROFILE_MISSING_DEPENDENCIES',
209
+ });
210
+ }
211
+ // Provenance
212
+ if (reqs.provenance === 'MUST' && !snapshot.provenance) {
213
+ errors.push({
214
+ path: 'provenance',
215
+ message: `Profile '${profileId}' requires provenance`,
216
+ code: 'PROFILE_MISSING_PROVENANCE',
217
+ });
218
+ }
219
+ else if (reqs.provenance === 'SHOULD' && !snapshot.provenance) {
220
+ warnings.push({
221
+ path: 'provenance',
222
+ message: `Profile '${profileId}' recommends provenance`,
223
+ code: 'PROFILE_RECOMMEND_PROVENANCE',
224
+ });
225
+ }
226
+ }
227
+ //# sourceMappingURL=validate-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-model.js","sourceRoot":"","sources":["../src/validate-model.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@open-operational-state/core",
3
+ "version": "0.1.0",
4
+ "description": "Core model logic: normalization, validation, and aggregation for Open Operational State",
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/core"
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
+ },
35
+ "devDependencies": {
36
+ "typescript": "^5.8.0"
37
+ }
38
+ }